[dev.ssa] Merge remote-tracking branch 'origin/master' into merge

Semi-regular merge of tip into dev.ssa.

Change-Id: I6f96b3b2b1b52e0e2ae5451767051fbd42ae0dbe
diff --git a/.gitignore b/.gitignore
index 585cd0f..bbfcc79 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,11 +1,11 @@
 .DS_Store
-*.[5689ao]
-*.a[5689o]
+*.[56789ao]
+*.a[56789o]
 *.so
 *.pyc
 ._*
 .nfs.*
-[5689a].out
+[56789a].out
 *~
 *.orig
 *.rej
@@ -21,22 +21,14 @@
 build.out
 test.out
 doc/articles/wiki/*.bin
-include/plan9/libc_plan9.h
 misc/cgo/life/run.out
 misc/cgo/stdio/run.out
 misc/cgo/testso/main
-misc/dashboard/builder/builder
-src/liblink/anames?.c
 src/cmd/*/y.output
 src/cmd/cgo/zdefaultcc.go
-src/cmd/dist/dist.dSYM
-src/cmd/gc/mkbuiltin1
-src/cmd/gc/opnames.h
 src/cmd/go/zdefaultcc.go
 src/cmd/internal/obj/zbootstrap.go
 src/go/doc/headscan
-src/runtime/mkversion
-src/runtime/zaexperiment.h
 src/runtime/zversion.go
 src/unicode/maketables
 src/*.*/
diff --git a/api/next.txt b/api/next.txt
index eb21e80..b79d7a8 100644
--- a/api/next.txt
+++ b/api/next.txt
@@ -167,83 +167,3 @@
 pkg debug/elf, method (R_PPC64) GoString() string
 pkg debug/elf, method (R_PPC64) String() string
 pkg debug/elf, type R_PPC64 int
-pkg runtime (openbsd-386), const CLOCK_MONOTONIC = 3
-pkg runtime (openbsd-386), const CLOCK_MONOTONIC ideal-int
-pkg runtime (openbsd-386), const CLOCK_PROF = 2
-pkg runtime (openbsd-386), const CLOCK_PROF ideal-int
-pkg runtime (openbsd-386), const CLOCK_REALTIME = 0
-pkg runtime (openbsd-386), const CLOCK_REALTIME ideal-int
-pkg runtime (openbsd-386), const CLOCK_VIRTUAL = 1
-pkg runtime (openbsd-386), const CLOCK_VIRTUAL ideal-int
-pkg runtime (openbsd-386), const CTL_HW = 6
-pkg runtime (openbsd-386), const CTL_HW ideal-int
-pkg runtime (openbsd-386), const EAGAIN = 35
-pkg runtime (openbsd-386), const EAGAIN ideal-int
-pkg runtime (openbsd-386), const ENOTSUP = 91
-pkg runtime (openbsd-386), const ENOTSUP ideal-int
-pkg runtime (openbsd-386), const ESRCH = 3
-pkg runtime (openbsd-386), const ESRCH ideal-int
-pkg runtime (openbsd-386), const EWOULDBLOCK = 35
-pkg runtime (openbsd-386), const EWOULDBLOCK ideal-int
-pkg runtime (openbsd-386), const HW_NCPU = 3
-pkg runtime (openbsd-386), const HW_NCPU ideal-int
-pkg runtime (openbsd-386-cgo), const CLOCK_MONOTONIC = 3
-pkg runtime (openbsd-386-cgo), const CLOCK_MONOTONIC ideal-int
-pkg runtime (openbsd-386-cgo), const CLOCK_PROF = 2
-pkg runtime (openbsd-386-cgo), const CLOCK_PROF ideal-int
-pkg runtime (openbsd-386-cgo), const CLOCK_REALTIME = 0
-pkg runtime (openbsd-386-cgo), const CLOCK_REALTIME ideal-int
-pkg runtime (openbsd-386-cgo), const CLOCK_VIRTUAL = 1
-pkg runtime (openbsd-386-cgo), const CLOCK_VIRTUAL ideal-int
-pkg runtime (openbsd-386-cgo), const CTL_HW = 6
-pkg runtime (openbsd-386-cgo), const CTL_HW ideal-int
-pkg runtime (openbsd-386-cgo), const EAGAIN = 35
-pkg runtime (openbsd-386-cgo), const EAGAIN ideal-int
-pkg runtime (openbsd-386-cgo), const ENOTSUP = 91
-pkg runtime (openbsd-386-cgo), const ENOTSUP ideal-int
-pkg runtime (openbsd-386-cgo), const ESRCH = 3
-pkg runtime (openbsd-386-cgo), const ESRCH ideal-int
-pkg runtime (openbsd-386-cgo), const EWOULDBLOCK = 35
-pkg runtime (openbsd-386-cgo), const EWOULDBLOCK ideal-int
-pkg runtime (openbsd-386-cgo), const HW_NCPU = 3
-pkg runtime (openbsd-386-cgo), const HW_NCPU ideal-int
-pkg runtime (openbsd-amd64), const CLOCK_MONOTONIC = 3
-pkg runtime (openbsd-amd64), const CLOCK_MONOTONIC ideal-int
-pkg runtime (openbsd-amd64), const CLOCK_PROF = 2
-pkg runtime (openbsd-amd64), const CLOCK_PROF ideal-int
-pkg runtime (openbsd-amd64), const CLOCK_REALTIME = 0
-pkg runtime (openbsd-amd64), const CLOCK_REALTIME ideal-int
-pkg runtime (openbsd-amd64), const CLOCK_VIRTUAL = 1
-pkg runtime (openbsd-amd64), const CLOCK_VIRTUAL ideal-int
-pkg runtime (openbsd-amd64), const CTL_HW = 6
-pkg runtime (openbsd-amd64), const CTL_HW ideal-int
-pkg runtime (openbsd-amd64), const EAGAIN = 35
-pkg runtime (openbsd-amd64), const EAGAIN ideal-int
-pkg runtime (openbsd-amd64), const ENOTSUP = 91
-pkg runtime (openbsd-amd64), const ENOTSUP ideal-int
-pkg runtime (openbsd-amd64), const ESRCH = 3
-pkg runtime (openbsd-amd64), const ESRCH ideal-int
-pkg runtime (openbsd-amd64), const EWOULDBLOCK = 35
-pkg runtime (openbsd-amd64), const EWOULDBLOCK ideal-int
-pkg runtime (openbsd-amd64), const HW_NCPU = 3
-pkg runtime (openbsd-amd64), const HW_NCPU ideal-int
-pkg runtime (openbsd-amd64-cgo), const CLOCK_MONOTONIC = 3
-pkg runtime (openbsd-amd64-cgo), const CLOCK_MONOTONIC ideal-int
-pkg runtime (openbsd-amd64-cgo), const CLOCK_PROF = 2
-pkg runtime (openbsd-amd64-cgo), const CLOCK_PROF ideal-int
-pkg runtime (openbsd-amd64-cgo), const CLOCK_REALTIME = 0
-pkg runtime (openbsd-amd64-cgo), const CLOCK_REALTIME ideal-int
-pkg runtime (openbsd-amd64-cgo), const CLOCK_VIRTUAL = 1
-pkg runtime (openbsd-amd64-cgo), const CLOCK_VIRTUAL ideal-int
-pkg runtime (openbsd-amd64-cgo), const CTL_HW = 6
-pkg runtime (openbsd-amd64-cgo), const CTL_HW ideal-int
-pkg runtime (openbsd-amd64-cgo), const EAGAIN = 35
-pkg runtime (openbsd-amd64-cgo), const EAGAIN ideal-int
-pkg runtime (openbsd-amd64-cgo), const ENOTSUP = 91
-pkg runtime (openbsd-amd64-cgo), const ENOTSUP ideal-int
-pkg runtime (openbsd-amd64-cgo), const ESRCH = 3
-pkg runtime (openbsd-amd64-cgo), const ESRCH ideal-int
-pkg runtime (openbsd-amd64-cgo), const EWOULDBLOCK = 35
-pkg runtime (openbsd-amd64-cgo), const EWOULDBLOCK ideal-int
-pkg runtime (openbsd-amd64-cgo), const HW_NCPU = 3
-pkg runtime (openbsd-amd64-cgo), const HW_NCPU ideal-int
diff --git a/doc/contribute.html b/doc/contribute.html
index 63d4774..c112a78 100644
--- a/doc/contribute.html
+++ b/doc/contribute.html
@@ -64,10 +64,8 @@
 <h2 id="Code_review">Code review</h2>
 
 <p>
-Changes to Go must be reviewed before they are submitted,
+Changes to Go must be reviewed before they are accepted,
 no matter who makes the change.
-(In exceptional cases, such as fixing a build, the review can
-follow shortly after submitting.)
 A custom git command called <code>git-codereview</code>,
 discussed below, helps manage the code review process through a Google-hosted
 <a href="https://go-review.googlesource.com/">instance</a> of the code review
@@ -77,49 +75,51 @@
 <h3>Set up authentication for code review</h3>
 
 <p>
-The Git code hosting server and Gerrit code review server both use a Google
-Account to authenticate. You therefore need a Google Account to proceed.
-(If you can use the account to
-<a href="https://www.google.com/accounts/Login">sign in at google.com</a>,
-you can use it to sign in to the code review server.)
-The email address you use with the code review system
-will be recorded in the <a href="https://go.googlesource.com/go">change log</a>
-and in the <a href="/CONTRIBUTORS"><code>CONTRIBUTORS</code></a> file.
-You can <a href="https://www.google.com/accounts/NewAccount">create a Google Account</a>
-associated with any address where you receive email.
+Gerrit uses Google Accounts for authentication. If you don't have
+a Google Account, you can create an account which
+<a href="https://www.google.com/accounts/NewAccount">includes
+a new Gmail email account</a> or create an account associated
+<a href="https://accounts.google.com/SignUpWithoutGmail">with your existing
+email address</a>.
 </p>
 
 <p>
-Visit the site <a href="https://go.googlesource.com">go.googlesource.com</a>
-and log in using your Google Account.
-Click on the "Generate Password" link that appears at the top of the page.
+The email address associated with the Google Account you use will be recorded in
+the <a href="https://go.googlesource.com/go/+log/">change log</a>
+and in the <a href="/CONTRIBUTORS">contributors file</a>.
 </p>
 
 <p>
-Click the radio button that says "Only <code>go.googlesource.com</code>"
-to use this authentication token only for the Go project.
+To set up your account in Gerrit, visit
+<a href="https://go.googlesource.com">go.googlesource.com</a>
+and click on "Generate Password" in the page's top right menu bar.
 </p>
 
 <p>
-Further down the page is a box containing commands to install
-the authentication cookie in file called <code>.gitcookies</code> in your home
-directory.
-Copy the text for the commands into a Unix shell window to execute it.
-That will install the authentication token.
+You will be redirected to accounts.google.com to sign in.
 </p>
 
 <p>
+Once signed in, you are returned back to go.googlesource.com to "Configure Git".
+Follow the instructions on the page.
 (If you are on a Windows computer, you should instead follow the instructions
 in the yellow box to run the command.)
 </p>
 
+<p>
+Your secret authentication token is now in a <code>.gitcookie</code> file
+and Git is configured to use this file.
+</p>
+
 <h3>Register with Gerrit</h3>
 
 <p>
-Now that you have a Google account and the authentication token,
-you need to register your account with Gerrit, the code review system.
-To do this, visit <a href="https://golang.org/cl">golang.org/cl</a>
-and log in using the same Google Account you used above.
+Now that you have your authentication token,
+you need to register your account with Gerrit.
+To do this, visit
+<a href="https://go-review.googlesource.com/login/">
+go-review.googlesource.com/login/</a>. You will immediately be redirected
+to Google Accounts. Sign in using the same Google Account you used above.
 That is all that is required.
 </p>
 
@@ -130,7 +130,7 @@
 </p>
 
 <pre>
-go get -u golang.org/x/review/git-codereview
+$ go get -u golang.org/x/review/git-codereview
 </pre>
 
 <p>
@@ -482,7 +482,7 @@
 Failed to merge in the changes.
 Patch failed at 0023 math: improved Sin, Cos and Tan precision for very large arguments
 The copy of the patch that failed is found in:
-   /home/you/repo/.git/rebase-apply/patch
+   /home/you/repo/.git/rebase-apply/patch
 
 When you have resolved this problem, run "git rebase --continue".
 If you prefer to skip this patch, run "git rebase --skip" instead.
@@ -505,15 +505,15 @@
 <pre>
 rebase in progress; onto a24c3eb
 You are currently rebasing branch 'mcgillicutty' on 'a24c3eb'.
-  (fix conflicts and then run "git rebase --continue")
-  (use "git rebase --skip" to skip this patch)
-  (use "git rebase --abort" to check out the original branch)
+  (fix conflicts and then run "git rebase --continue")
+  (use "git rebase --skip" to skip this patch)
+  (use "git rebase --abort" to check out the original branch)
 
 Unmerged paths:
-  (use "git reset HEAD &lt;file&gt;..." to unstage)
-  (use "git add &lt;file&gt;..." to mark resolution)
+  (use "git reset HEAD &lt;file&gt;..." to unstage)
+  (use "git add &lt;file&gt;..." to mark resolution)
 
-	<i>both modified:   sin.go</i>
+	<i>both modified: sin.go</i>
 </pre>
 
 <p>
@@ -530,9 +530,9 @@
 <pre>
 	arg = scale(arg)
 &lt;&lt;&lt;&lt;&lt;&lt;&lt; HEAD
-	if arg > 1e9 {
+	if arg &lt; 1e9 {
 =======
-	if arg > 1e10 {
+	if arg &lh; 1e10 {
 &gt;&gt;&gt;&gt;&gt;&gt;&gt; mcgillicutty
 		largeReduce(arg)
 </pre>
@@ -546,7 +546,7 @@
 
 <pre>
 	arg = scale(arg)
-	if arg > 1e10 {
+	if arg &lt; 1e10 {
 		largeReduce(arg)
 </pre>
 
@@ -577,7 +577,7 @@
 </p>
 
 <pre>
-$ git fetch https://go.googlesource.com/review refs/changes/21/1221/1 && git checkout FETCH_HEAD
+$ git fetch https://go.googlesource.com/review refs/changes/21/1221/1 &amp;&amp; git checkout FETCH_HEAD
 </pre>
 
 <p>
diff --git a/doc/effective_go.html b/doc/effective_go.html
index 4dd1a3e..d6be379 100644
--- a/doc/effective_go.html
+++ b/doc/effective_go.html
@@ -866,7 +866,7 @@
 t = functionOfSomeType()
 switch t := t.(type) {
 default:
-    fmt.Printf("unexpected type %T", t)       // %T prints whatever type t has
+    fmt.Printf("unexpected type %T\n", t)     // %T prints whatever type t has
 case bool:
     fmt.Printf("boolean %t\n", t)             // t has type bool
 case int:
diff --git a/doc/go1.4.html b/doc/go1.4.html
index b4f9619..ca44d56 100644
--- a/doc/go1.4.html
+++ b/doc/go1.4.html
@@ -677,7 +677,7 @@
 The <a href="/pkg/crypto/tls/"><code>crypto/tls</code></a> package
 now supports programmatic selection of server certificates
 through the new <a href="/pkg/crypto/tls/#Config.CertificateForName"><code>CertificateForName</code></a> function
-of the <a href="/pkg/crypo/tls/#Config"><code>Config</code></a> struct.
+of the <a href="/pkg/crypto/tls/#Config"><code>Config</code></a> struct.
 </li>
 
 <li>
diff --git a/doc/go1.5.txt b/doc/go1.5.txt
index e944e46..88e6dbc 100644
--- a/doc/go1.5.txt
+++ b/doc/go1.5.txt
@@ -1,41 +1,77 @@
 Overall:
+toolchain in Go
+new GC
 
-build: Go 1.4 required to build (https://golang.org/cl/2470, https://golang.org/cl/2993)
+Language:
+permit omission of key type in map composite literals where key is a composite literal (https://golang.org/cl/2591)
+
+Build:
+Go 1.4 required to build (https://golang.org/cl/2470, https://golang.org/cl/2993)
 
 New Ports:
-Darwin/ARM, a.k.a iOS. (https://golang.org/cl/2118, 2119, 3273, 2121, 2122, ..., 2127)
+darwin/arm, a.k.a iOS. (https://golang.org/cl/2118, 2119, 3273, 2121, 2122, ..., 2127)
+linux/arm64
+
+Removed Ports:
+dragonfly/386 (https://golang.org/cl/7543)
 
 API additions and behavior changes:
 
+archive/zip: add (*Writer).SetOffset method (https://golang.org/cl/7445)
 bufio: add Reader.Discard (https://golang.org/cl/2260)
 crypto/cipher: clarify what will happen if len(src) != len(dst) for the Stream interface. (https://golang.org/cl/1754)
 crypto/elliptic: add Name field to CurveParams struct (https://golang.org/cl/2133)
 crypto/tls: change default minimum version to TLS 1.0. (https://golang.org/cl/1791)
 crypto/x509: wildcards are now only accepted as the first label (https://golang.org/cl/5691)
 encoding/base64: add unpadded encodings (https://golang.org/cl/1511)
+flag: new nicer format for PrintDefaults (https://go-review.googlesource.com/7330)
 go/ast: add Implicit field to ast.EmptyStmt; changed meaning of ast.EmptyStmt.Semicolon position (https://golang.org/cl/5720)
 log: add SetOutput functions (https://golang.org/cl/2686, https://golang.org/cl/3023)
+math/big: add arbitrary precision Floats (many cl's)
+mime: add ExtensionByType (https://golang.org/cl/7444)
 net/http: support for setting trailers from a server Handler (https://golang.org/cl/2157)
+net/http: ignore the Unix epoch time in ServeContent (https://golang.org/cl/7915)
 net/http/cgi: fix REMOTE_ADDR, REMOTE_HOST, add REMOTE_PORT (https://golang.org/cl/4933)
 net/smtp: add TLSConnectionState accessor (https://golang.org/cl/2151)
 os/signal: add Ignore and Reset (https://golang.org/cl/3580)
 runtime, syscall: use SYSCALL instruction on FreeBSD (Go 1.5 now requires FreeBSD 8-STABLE+) (https://golang.org/cl/3020)
+runtime, syscall: use get_random_bytes syscall for NaCl (Go 1.5 now requires NaCl SDK pepper-39 or above) (https://golang.org/cl/1755)
 strings: add Compare(x, y string) int, for symmetry with bytes.Compare (https://golang.org/cl/2828)
+syscall: Add Foreground and Pgid to SysProcAttr (https://golang.org/cl/5130)
+syscall: add missing Syscall9 for darwin/amd64 (https://golang.org/cl/6555)
 testing/quick: support generation of arrays (https://golang.org/cl/3865)
 
 Tools:
 
+build: external linking support for windows (https://golang.org/cl/7163, 7282, 7283, 7284, 7534, 7535)
+cmd/go, go/build: add ${SRCDIR} variable expansion to cgo lines (https://golang.org/cl/1756)
+cmd/go: add $DOLLAR to generate's variables (https://golang.org/cl/8091)
 cmd/go: std wildcard now excludes commands in main repo (https://golang.org/cl/5550)
+cmd/go: .swig/.swigcxx files now require SWIG 3.0.6 or later
 cmd/vet: better validation of struct tags (https://golang.org/cl/2685)
 cmd/ld: no longer record build timestamp in Windows PE file header (https://golang.org/cl/3740)
+cmd/trace: new command to view traces (https://golang.org/cl/3601)
 
 Performance:
 
+cmd/gc: evaluate concrete == interface without allocating (https://golang.org/cl/2096)
 cmd/gc: optimize memclr of slices and arrays (https://golang.org/cl/2520)
+cmd/gc: transform closure calls to function calls (https://golang.org/cl/4050)
+cmd/gc: transitive inlining (https://golang.org/cl/5952)
+cmd/gc, runtime: speed up some cases of _, ok := i.(T) (https://golang.org/cl/7697)
+cmd/gc: speed up large string switches (https://golang.org/cl/7698)
+cmd/gc: inline x := y.(*T) and x, ok := y.(*T) (https://golang.org/cl/7862)
+cmd/gc: allocate backing storage for non-escaping interfaces on stack (https://golang.org/cl/8201)
+encoding/xml: avoid an allocation for tags without attributes (https://golang.org/cl/4160)
+image: many optimizations
+runtime: add ARM runtime.cmpstring and bytes.Compare (https://golang.org/cl/8010)
 sort: number of Sort performance optimizations (https://golang.org/cl/2100, https://golang.org/cl/2614, ...)
 strconv: optimize decimal to string conversion (https://golang.org/cl/2105)
+strconv: optimize float to string conversion (https://golang.org/cl/5600)
+sync: add active spinning to Mutex (https://golang.org/cl/5430)
 math/big: faster assembly kernels for amd64 and 386 (https://golang.org/cl/2503, https://golang.org/cl/2560)
 math/big: faster "pure Go" kernels for platforms w/o assembly kernels (https://golang.org/cl/2480)
+regexp: port RE2's bitstate backtracker to the regexp package (https://golang.org/cl/2153)
 
 Assembler:
 
diff --git a/doc/go_mem.html b/doc/go_mem.html
index 5dd48ff..143f3b2 100644
--- a/doc/go_mem.html
+++ b/doc/go_mem.html
@@ -322,11 +322,11 @@
 
 func main() {
 	for _, w := range work {
-		go func() {
-			limit <- 1
+		go func(w func()) {
+			limit &lt;- 1
 			w()
-			<-limit
-		}()
+			&lt;-limit
+		}(w)
 	}
 	select{}
 }
diff --git a/doc/go_spec.html b/doc/go_spec.html
index 5a1b291..d02697b 100644
--- a/doc/go_spec.html
+++ b/doc/go_spec.html
@@ -1,6 +1,6 @@
 <!--{
 	"Title": "The Go Programming Language Specification",
-	"Subtitle": "Version of December 26, 2014",
+	"Subtitle": "Version of March 20, 2015",
 	"Path": "/ref/spec"
 }-->
 
@@ -2236,9 +2236,8 @@
 LiteralValue  = "{" [ ElementList [ "," ] ] "}" .
 ElementList   = Element { "," Element } .
 Element       = [ Key ":" ] Value .
-Key           = FieldName | ElementIndex .
+Key           = FieldName | Expression | LiteralValue .
 FieldName     = identifier .
-ElementIndex  = Expression .
 Value         = Expression | LiteralValue .
 </pre>
 
@@ -2357,17 +2356,21 @@
 
 <p>
 Within a composite literal of array, slice, or map type <code>T</code>,
-elements that are themselves composite literals may elide the respective
-literal type if it is identical to the element type of <code>T</code>.
-Similarly, elements that are addresses of composite literals may elide
-the <code>&amp;T</code> when the element type is <code>*T</code>.
+elements or map keys that are themselves composite literals may elide the respective
+literal type if it is identical to the element or key type of <code>T</code>.
+Similarly, elements or keys that are addresses of composite literals may elide
+the <code>&amp;T</code> when the element or key type is <code>*T</code>.
 </p>
 
 <pre>
-[...]Point{{1.5, -3.5}, {0, 0}}   // same as [...]Point{Point{1.5, -3.5}, Point{0, 0}}
-[][]int{{1, 2, 3}, {4, 5}}        // same as [][]int{[]int{1, 2, 3}, []int{4, 5}}
+[...]Point{{1.5, -3.5}, {0, 0}}     // same as [...]Point{Point{1.5, -3.5}, Point{0, 0}}
+[][]int{{1, 2, 3}, {4, 5}}          // same as [][]int{[]int{1, 2, 3}, []int{4, 5}}
+[][]Point{{{0, 1}, {1, 2}}}         // same as [][]Point{[]Point{Point{0, 1}, Point{1, 2}}}
+map[string]Point{"orig": {0, 0}}    // same as map[string]Point{"orig": Point{0, 0}}
 
-[...]*Point{{1.5, -3.5}, {0, 0}}  // same as [...]*Point{&amp;Point{1.5, -3.5}, &amp;Point{0, 0}}
+[...]*Point{{1.5, -3.5}, {0, 0}}    // same as [...]*Point{&amp;Point{1.5, -3.5}, &amp;Point{0, 0}}
+
+map[Point]string{{0, 0}: "orig"}    // same as map[Point]string{Point{0, 0}: "orig"}
 </pre>
 
 <p>
diff --git a/misc/cgo/errors/test.bash b/misc/cgo/errors/test.bash
index c962643..c880ad6 100755
--- a/misc/cgo/errors/test.bash
+++ b/misc/cgo/errors/test.bash
@@ -1,3 +1,5 @@
+#!/usr/bin/env bash
+
 # Copyright 2013 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.
diff --git a/misc/cgo/testgodefs/test.bash b/misc/cgo/testgodefs/test.bash
index 5281b10..14235c0 100755
--- a/misc/cgo/testgodefs/test.bash
+++ b/misc/cgo/testgodefs/test.bash
@@ -1,3 +1,5 @@
+#!/usr/bin/env bash
+
 # 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.
diff --git a/misc/cgo/testso/test.bat b/misc/cgo/testso/test.bat
index b8cc384..7bbabea 100644
--- a/misc/cgo/testso/test.bat
+++ b/misc/cgo/testso/test.bat
@@ -13,6 +13,6 @@
 goto :end
 
 :fail
-set FAIL=1
+echo FAIL
 :end
 del /F cgoso_c.o libcgosotest.dll main.exe 2>NUL
diff --git a/misc/ios/go_darwin_arm_exec.go b/misc/ios/go_darwin_arm_exec.go
new file mode 100644
index 0000000..4495f52
--- /dev/null
+++ b/misc/ios/go_darwin_arm_exec.go
@@ -0,0 +1,597 @@
+// Copyright 2015 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.
+
+// This program can be used as go_darwin_arm_exec by the Go tool.
+// It executes binaries on an iOS device using the XCode toolchain
+// and the ios-deploy program: https://github.com/phonegap/ios-deploy
+package main
+
+import (
+	"bytes"
+	"errors"
+	"flag"
+	"fmt"
+	"go/build"
+	"io/ioutil"
+	"log"
+	"os"
+	"os/exec"
+	"path/filepath"
+	"runtime"
+	"strings"
+	"sync"
+	"time"
+)
+
+const debug = false
+
+var errRetry = errors.New("failed to start test harness (retry attempted)")
+
+var tmpdir string
+
+func main() {
+	log.SetFlags(0)
+	log.SetPrefix("go_darwin_arm_exec: ")
+	if debug {
+		log.Println(strings.Join(os.Args, " "))
+	}
+	if len(os.Args) < 2 {
+		log.Fatal("usage: go_darwin_arm_exec a.out")
+	}
+
+	var err error
+	tmpdir, err = ioutil.TempDir("", "go_darwin_arm_exec_")
+	if err != nil {
+		log.Fatal(err)
+	}
+
+	// Approximately 1 in a 100 binaries fail to start. If it happens,
+	// try again. These failures happen for several reasons beyond
+	// our control, but all of them are safe to retry as they happen
+	// before lldb encounters the initial getwd breakpoint. As we
+	// know the tests haven't started, we are not hiding flaky tests
+	// with this retry.
+	for i := 0; i < 5; i++ {
+		if i > 0 {
+			fmt.Fprintln(os.Stderr, "start timeout, trying again")
+		}
+		err = run(os.Args[1], os.Args[2:])
+		if err == nil || err != errRetry {
+			break
+		}
+	}
+	if !debug {
+		os.RemoveAll(tmpdir)
+	}
+	if err != nil {
+		fmt.Fprintf(os.Stderr, "go_darwin_arm_exec: %v\n", err)
+		os.Exit(1)
+	}
+}
+
+func run(bin string, args []string) (err error) {
+	appdir := filepath.Join(tmpdir, "gotest.app")
+	os.RemoveAll(appdir)
+	if err := os.MkdirAll(appdir, 0755); err != nil {
+		return err
+	}
+
+	if err := cp(filepath.Join(appdir, "gotest"), bin); err != nil {
+		return err
+	}
+
+	entitlementsPath := filepath.Join(tmpdir, "Entitlements.plist")
+	if err := ioutil.WriteFile(entitlementsPath, []byte(entitlementsPlist), 0744); err != nil {
+		return err
+	}
+	if err := ioutil.WriteFile(filepath.Join(appdir, "Info.plist"), []byte(infoPlist), 0744); err != nil {
+		return err
+	}
+	if err := ioutil.WriteFile(filepath.Join(appdir, "ResourceRules.plist"), []byte(resourceRules), 0744); err != nil {
+		return err
+	}
+
+	pkgpath, err := copyLocalData(appdir)
+	if err != nil {
+		return err
+	}
+
+	cmd := exec.Command(
+		"codesign",
+		"-f",
+		"-s", "E8BMC3FE2Z", // certificate associated with golang.org
+		"--entitlements", entitlementsPath,
+		appdir,
+	)
+	if debug {
+		log.Println(strings.Join(cmd.Args, " "))
+	}
+	cmd.Stdout = os.Stdout
+	cmd.Stderr = os.Stderr
+	if err := cmd.Run(); err != nil {
+		return fmt.Errorf("codesign: %v", err)
+	}
+
+	oldwd, err := os.Getwd()
+	if err != nil {
+		return err
+	}
+	if err := os.Chdir(filepath.Join(appdir, "..")); err != nil {
+		return err
+	}
+	defer os.Chdir(oldwd)
+
+	type waitPanic struct {
+		err error
+	}
+	defer func() {
+		if r := recover(); r != nil {
+			if w, ok := r.(waitPanic); ok {
+				err = w.err
+				return
+			}
+			panic(r)
+		}
+	}()
+
+	defer exec.Command("killall", "ios-deploy").Run() // cleanup
+
+	exec.Command("killall", "ios-deploy").Run()
+
+	// ios-deploy invokes lldb to give us a shell session with the app.
+	cmd = exec.Command(
+		// lldb tries to be clever with terminals.
+		// So we wrap it in script(1) and be clever
+		// right back at it.
+		"script",
+		"-q", "-t", "0",
+		"/dev/null",
+
+		"ios-deploy",
+		"--debug",
+		"-u",
+		"-r",
+		"-n",
+		`--args=`+strings.Join(args, " ")+``,
+		"--bundle", appdir,
+	)
+	if debug {
+		log.Println(strings.Join(cmd.Args, " "))
+	}
+
+	lldbr, lldb, err := os.Pipe()
+	if err != nil {
+		return err
+	}
+	w := new(bufWriter)
+	cmd.Stdout = w
+	cmd.Stderr = w // everything of interest is on stderr
+	cmd.Stdin = lldbr
+
+	if err := cmd.Start(); err != nil {
+		return fmt.Errorf("ios-deploy failed to start: %v", err)
+	}
+
+	// Manage the -test.timeout here, outside of the test. There is a lot
+	// of moving parts in an iOS test harness (notably lldb) that can
+	// swallow useful stdio or cause its own ruckus.
+	var timedout chan struct{}
+	if t := parseTimeout(args); t > 1*time.Second {
+		timedout = make(chan struct{})
+		time.AfterFunc(t-1*time.Second, func() {
+			close(timedout)
+		})
+	}
+
+	exited := make(chan error)
+	go func() {
+		exited <- cmd.Wait()
+	}()
+
+	waitFor := func(stage, str string, timeout time.Duration) error {
+		select {
+		case <-timedout:
+			w.printBuf()
+			if p := cmd.Process; p != nil {
+				p.Kill()
+			}
+			return fmt.Errorf("timeout (stage %s)", stage)
+		case err := <-exited:
+			w.printBuf()
+			return fmt.Errorf("failed (stage %s): %v", stage, err)
+		case i := <-w.find(str, timeout):
+			if i < 0 {
+				log.Printf("timed out on stage %q, retrying", stage)
+				return errRetry
+			}
+			w.clearTo(i + len(str))
+			return nil
+		}
+	}
+	do := func(cmd string) {
+		fmt.Fprintln(lldb, cmd)
+		if err := waitFor(fmt.Sprintf("prompt after %q", cmd), "(lldb)", 0); err != nil {
+			panic(waitPanic{err})
+		}
+	}
+
+	// Wait for installation and connection.
+	if err := waitFor("ios-deploy before run", "(lldb)     connect\r\nProcess 0 connected\r\n", 0); err != nil {
+		// Retry if we see a rare and longstanding ios-deploy bug.
+		// https://github.com/phonegap/ios-deploy/issues/11
+		//	Assertion failed: (AMDeviceStartService(device, CFSTR("com.apple.debugserver"), &gdbfd, NULL) == 0)
+		log.Printf("%v, retrying", err)
+		return errRetry
+	}
+
+	// Script LLDB. Oh dear.
+	do(`process handle SIGHUP  --stop false --pass true --notify false`)
+	do(`process handle SIGPIPE --stop false --pass true --notify false`)
+	do(`process handle SIGUSR1 --stop false --pass true --notify false`)
+	do(`process handle SIGSEGV --stop false --pass true --notify false`) // does not work
+	do(`process handle SIGBUS  --stop false --pass true --notify false`) // does not work
+
+	do(`breakpoint set -n getwd`) // in runtime/cgo/gcc_darwin_arm.go
+
+	fmt.Fprintln(lldb, `run`)
+	if err := waitFor("br getwd", "stop reason = breakpoint", 20*time.Second); err != nil {
+		// At this point we see several flaky errors from the iOS
+		// build infrastructure. The most common is never reaching
+		// the breakpoint, which we catch with a timeout. Very
+		// occasionally lldb can produce errors like:
+		//
+		//	Breakpoint 1: no locations (pending).
+		//	WARNING:  Unable to resolve breakpoint to any actual locations.
+		//
+		// As no actual test code has been executed by this point,
+		// we treat all errors as recoverable.
+		if err != errRetry {
+			log.Printf("%v, retrying", err)
+			err = errRetry
+		}
+		return err
+	}
+	if err := waitFor("br getwd prompt", "(lldb)", 0); err != nil {
+		return err
+	}
+
+	// Move the current working directory into the faux gopath.
+	do(`breakpoint delete 1`)
+	do(`expr char* $mem = (char*)malloc(512)`)
+	do(`expr $mem = (char*)getwd($mem, 512)`)
+	do(`expr $mem = (char*)strcat($mem, "/` + pkgpath + `")`)
+	do(`call (void)chdir($mem)`)
+
+	// Watch for SIGSEGV. Ideally lldb would never break on SIGSEGV.
+	// http://golang.org/issue/10043
+	go func() {
+		<-w.find("stop reason = EXC_BAD_ACCESS", 0)
+		// cannot use do here, as the defer/recover is not available
+		// on this goroutine.
+		fmt.Fprintln(lldb, `bt`)
+		waitFor("finish backtrace", "(lldb)", 0)
+		w.printBuf()
+		if p := cmd.Process; p != nil {
+			p.Kill()
+		}
+	}()
+
+	// Run the tests.
+	w.trimSuffix("(lldb) ")
+	fmt.Fprintln(lldb, `process continue`)
+
+	// Wait for the test to complete.
+	select {
+	case <-timedout:
+		w.printBuf()
+		if p := cmd.Process; p != nil {
+			p.Kill()
+		}
+		return errors.New("timeout running tests")
+	case err := <-exited:
+		// The returned lldb error code is usually non-zero.
+		// We check for test success by scanning for the final
+		// PASS returned by the test harness, assuming the worst
+		// in its absence.
+		if w.isPass() {
+			err = nil
+		} else if err == nil {
+			err = errors.New("test failure")
+		}
+		w.printBuf()
+		return err
+	}
+}
+
+type bufWriter struct {
+	mu     sync.Mutex
+	buf    []byte
+	suffix []byte // remove from each Write
+
+	findTxt   []byte   // search buffer on each Write
+	findCh    chan int // report find position
+	findAfter *time.Timer
+}
+
+func (w *bufWriter) Write(in []byte) (n int, err error) {
+	w.mu.Lock()
+	defer w.mu.Unlock()
+
+	n = len(in)
+	in = bytes.TrimSuffix(in, w.suffix)
+
+	w.buf = append(w.buf, in...)
+
+	if len(w.findTxt) > 0 {
+		if i := bytes.Index(w.buf, w.findTxt); i >= 0 {
+			w.findCh <- i
+			close(w.findCh)
+			w.findTxt = nil
+			w.findCh = nil
+			if w.findAfter != nil {
+				w.findAfter.Stop()
+				w.findAfter = nil
+			}
+		}
+	}
+	return n, nil
+}
+
+func (w *bufWriter) trimSuffix(p string) {
+	w.mu.Lock()
+	defer w.mu.Unlock()
+	w.suffix = []byte(p)
+}
+
+func (w *bufWriter) printBuf() {
+	w.mu.Lock()
+	defer w.mu.Unlock()
+	fmt.Fprintf(os.Stderr, "%s", w.buf)
+	w.buf = nil
+}
+
+func (w *bufWriter) clearTo(i int) {
+	w.mu.Lock()
+	defer w.mu.Unlock()
+	if debug {
+		fmt.Fprintf(os.Stderr, "--- go_darwin_arm_exec clear ---\n%s\n--- go_darwin_arm_exec clear ---\n", w.buf[:i])
+	}
+	w.buf = w.buf[i:]
+}
+
+// find returns a channel that will have exactly one byte index sent
+// to it when the text str appears in the buffer. If the text does not
+// appear before timeout, -1 is sent.
+//
+// A timeout of zero means no timeout.
+func (w *bufWriter) find(str string, timeout time.Duration) <-chan int {
+	w.mu.Lock()
+	defer w.mu.Unlock()
+	if len(w.findTxt) > 0 {
+		panic(fmt.Sprintf("find(%s): already trying to find %s", str, w.findTxt))
+	}
+	txt := []byte(str)
+	ch := make(chan int, 1)
+	if i := bytes.Index(w.buf, txt); i >= 0 {
+		ch <- i
+		close(ch)
+	} else {
+		w.findTxt = txt
+		w.findCh = ch
+		if timeout > 0 {
+			w.findAfter = time.AfterFunc(timeout, func() {
+				w.mu.Lock()
+				defer w.mu.Unlock()
+				if w.findCh == ch {
+					w.findTxt = nil
+					w.findCh = nil
+					w.findAfter = nil
+					ch <- -1
+					close(ch)
+				}
+			})
+		}
+	}
+	return ch
+}
+
+func (w *bufWriter) isPass() bool {
+	w.mu.Lock()
+	defer w.mu.Unlock()
+
+	// The final stdio of lldb is non-deterministic, so we
+	// scan the whole buffer.
+	//
+	// Just to make things fun, lldb sometimes translates \n
+	// into \r\n.
+	return bytes.Contains(w.buf, []byte("\nPASS\n")) || bytes.Contains(w.buf, []byte("\nPASS\r"))
+}
+
+func parseTimeout(testArgs []string) (timeout time.Duration) {
+	var args []string
+	for _, arg := range testArgs {
+		if strings.Contains(arg, "test.timeout") {
+			args = append(args, arg)
+		}
+	}
+	f := flag.NewFlagSet("", flag.ContinueOnError)
+	f.DurationVar(&timeout, "test.timeout", 0, "")
+	f.Parse(args)
+	if debug {
+		log.Printf("parseTimeout of %s, got %s", args, timeout)
+	}
+	return timeout
+}
+
+func copyLocalDir(dst, src string) error {
+	if err := os.Mkdir(dst, 0755); err != nil {
+		return err
+	}
+
+	d, err := os.Open(src)
+	if err != nil {
+		return err
+	}
+	defer d.Close()
+	fi, err := d.Readdir(-1)
+	if err != nil {
+		return err
+	}
+
+	for _, f := range fi {
+		if f.IsDir() {
+			if f.Name() == "testdata" {
+				if err := cp(dst, filepath.Join(src, f.Name())); err != nil {
+					return err
+				}
+			}
+			continue
+		}
+		if err := cp(dst, filepath.Join(src, f.Name())); err != nil {
+			return err
+		}
+	}
+	return nil
+}
+
+func cp(dst, src string) error {
+	out, err := exec.Command("cp", "-a", src, dst).CombinedOutput()
+	if err != nil {
+		os.Stderr.Write(out)
+	}
+	return err
+}
+
+func copyLocalData(dstbase string) (pkgpath string, err error) {
+	cwd, err := os.Getwd()
+	if err != nil {
+		return "", err
+	}
+
+	finalPkgpath, underGoRoot, err := subdir()
+	if err != nil {
+		return "", err
+	}
+	cwd = strings.TrimSuffix(cwd, finalPkgpath)
+
+	// Copy all immediate files and testdata directories between
+	// the package being tested and the source root.
+	pkgpath = ""
+	for _, element := range strings.Split(finalPkgpath, string(filepath.Separator)) {
+		if debug {
+			log.Printf("copying %s", pkgpath)
+		}
+		pkgpath = filepath.Join(pkgpath, element)
+		dst := filepath.Join(dstbase, pkgpath)
+		src := filepath.Join(cwd, pkgpath)
+		if err := copyLocalDir(dst, src); err != nil {
+			return "", err
+		}
+	}
+
+	// Copy timezone file.
+	//
+	// Typical apps have the zoneinfo.zip in the root of their app bundle,
+	// read by the time package as the working directory at initialization.
+	// As we move the working directory to the GOROOT pkg directory, we
+	// install the zoneinfo.zip file in the pkgpath.
+	if underGoRoot {
+		err := cp(
+			filepath.Join(dstbase, pkgpath),
+			filepath.Join(cwd, "lib", "time", "zoneinfo.zip"),
+		)
+		if err != nil {
+			return "", err
+		}
+	}
+
+	return finalPkgpath, nil
+}
+
+// subdir determines the package based on the current working directory,
+// and returns the path to the package source relative to $GOROOT (or $GOPATH).
+func subdir() (pkgpath string, underGoRoot bool, err error) {
+	cwd, err := os.Getwd()
+	if err != nil {
+		return "", false, err
+	}
+	if root := runtime.GOROOT(); strings.HasPrefix(cwd, root) {
+		subdir, err := filepath.Rel(root, cwd)
+		if err != nil {
+			return "", false, err
+		}
+		return subdir, true, nil
+	}
+
+	for _, p := range filepath.SplitList(build.Default.GOPATH) {
+		if !strings.HasPrefix(cwd, p) {
+			continue
+		}
+		subdir, err := filepath.Rel(p, cwd)
+		if err == nil {
+			return subdir, false, nil
+		}
+	}
+	return "", false, fmt.Errorf(
+		"working directory %q is not in either GOROOT(%q) or GOPATH(%q)",
+		cwd,
+		runtime.GOROOT(),
+		build.Default.GOPATH,
+	)
+}
+
+const infoPlist = `<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+<key>CFBundleName</key><string>golang.gotest</string>
+<key>CFBundleSupportedPlatforms</key><array><string>iPhoneOS</string></array>
+<key>CFBundleExecutable</key><string>gotest</string>
+<key>CFBundleVersion</key><string>1.0</string>
+<key>CFBundleIdentifier</key><string>golang.gotest</string>
+<key>CFBundleResourceSpecification</key><string>ResourceRules.plist</string>
+<key>LSRequiresIPhoneOS</key><true/>
+<key>CFBundleDisplayName</key><string>gotest</string>
+</dict>
+</plist>
+`
+
+const devID = `YE84DJ86AZ`
+
+const entitlementsPlist = `<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+	<key>keychain-access-groups</key>
+	<array><string>` + devID + `.golang.gotest</string></array>
+	<key>get-task-allow</key>
+	<true/>
+	<key>application-identifier</key>
+	<string>` + devID + `.golang.gotest</string>
+	<key>com.apple.developer.team-identifier</key>
+	<string>` + devID + `</string>
+</dict>
+</plist>`
+
+const resourceRules = `<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+        <key>rules</key>
+        <dict>
+                <key>.*</key><true/>
+		<key>Info.plist</key> 
+		<dict>
+			<key>omit</key> <true/>
+			<key>weight</key> <real>10</real>
+		</dict>
+		<key>ResourceRules.plist</key>
+		<dict>
+			<key>omit</key> <true/>
+			<key>weight</key> <real>100</real>
+		</dict>
+	</dict>
+</dict>
+</plist>
+`
diff --git a/misc/nacl/README b/misc/nacl/README
index 72d0e08..b7163d3 100644
--- a/misc/nacl/README
+++ b/misc/nacl/README
@@ -8,7 +8,7 @@
 
  * nacl/386 which is standard 386.
  * nacl/amd64p32 which is a 64 bit architecture, where the address space is
-   limited to a 4gb window. 
+   limited to a 4gb window.
  * nacl/arm which is 32-bit ARMv7A architecture with 1GB address space.
 
 For background it is recommended that you read http://golang.org/s/go13nacl.
@@ -37,21 +37,20 @@
 	% cd /opt/nacl_sdk
 	% ./naclsdk update
 
-At this time pepper_34 is the stable version. If naclsdk downloads a later
-version, please adjust accordingly. As of June 2014, only the canary sdk
-provides support for nacl/arm.
+At this time pepper_40 is the stable version. The NaCl port needs at least pepper_39
+to work. If naclsdk downloads a later version, please adjust accordingly.
 
 The cmd/go helper scripts expect that the loaders sel_ldr_{x86_{32,64},arm} and
 nacl_helper_bootstrap_arm are in your path. I find it easiest to make a symlink
 from the NaCl distribution to my $GOPATH/bin directory.
 
-	% ln -nfs /opt/nacl_sdk/pepper_34/tools/sel_ldr_x86_32 $GOPATH/bin/sel_ldr_x86_32
-	% ln -nfs /opt/nacl_sdk/pepper_34/tools/sel_ldr_x86_64 $GOPATH/bin/sel_ldr_x86_64
-	% ln -nfs /opt/nacl_sdk/pepper_canary/tools/sel_ldr_arm $GOPATH/bin/sel_ldr_arm
+	% ln -nfs /opt/nacl_sdk/pepper_39/tools/sel_ldr_x86_32 $GOPATH/bin/sel_ldr_x86_32
+	% ln -nfs /opt/nacl_sdk/pepper_39/tools/sel_ldr_x86_64 $GOPATH/bin/sel_ldr_x86_64
+	% ln -nfs /opt/nacl_sdk/pepper_39/tools/sel_ldr_arm $GOPATH/bin/sel_ldr_arm
 
 Additionally, for NaCl/ARM only:
 
-	% ln -nfs /opt/nacl_sdk/pepper_canary/tools/nacl_helper_bootstrap_arm $GOPATH/bin/nacl_helper_bootstrap_arm 
+	% ln -nfs /opt/nacl_sdk/pepper_39/tools/nacl_helper_bootstrap_arm $GOPATH/bin/nacl_helper_bootstrap_arm
 
 Support scripts
 ---------------
@@ -110,7 +109,7 @@
 
 The -g flag instructs the loader to stop at startup. Then, in another console:
 
-	% /opt/nacl_sdk/pepper_34/toolchain/linux_x86_glibc/bin/x86_64-nacl-gdb
+	% /opt/nacl_sdk/pepper_39/toolchain/linux_x86_glibc/bin/x86_64-nacl-gdb
 	% nacl-manifest mybin.manifest
 	% target remote :4014
 
@@ -118,5 +117,5 @@
 loaded successfully and you can type 'c' to start the program.
 Next time you can automate it as:
 
-	% /opt/nacl_sdk/pepper_34/toolchain/linux_x86_glibc/bin/x86_64-nacl-gdb \
+	% /opt/nacl_sdk/pepper_39/toolchain/linux_x86_glibc/bin/x86_64-nacl-gdb \
 		-ex 'nacl-manifest mybin.manifest' -ex 'target remote :4014'
diff --git a/misc/swig/callback/callback_test.go b/misc/swig/callback/callback_test.go
index cf008fb..dbbbab5 100644
--- a/misc/swig/callback/callback_test.go
+++ b/misc/swig/callback/callback_test.go
@@ -2,16 +2,15 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-package callback_test
+package callback
 
 import (
-	"../callback"
 	"testing"
 )
 
 func TestCall(t *testing.T) {
-	c := callback.NewCaller()
-	cb := callback.NewCallback()
+	c := NewCaller()
+	cb := NewCallback()
 
 	c.SetCallback(cb)
 	s := c.Call()
@@ -22,13 +21,13 @@
 }
 
 func TestCallback(t *testing.T) {
-	c := callback.NewCaller()
-	cb := callback.NewDirectorCallback(&callback.GoCallback{})
+	c := NewCaller()
+	cb := NewDirectorCallback(&GoCallback{})
 	c.SetCallback(cb)
 	s := c.Call()
 	if s != "GoCallback.Run" {
 		t.Errorf("unexpected string from Call with callback: %q", s)
 	}
 	c.DelCallback()
-	callback.DeleteDirectorCallback(cb)
+	DeleteDirectorCallback(cb)
 }
diff --git a/src/archive/zip/struct.go b/src/archive/zip/struct.go
index cb28e83..793d5da 100644
--- a/src/archive/zip/struct.go
+++ b/src/archive/zip/struct.go
@@ -233,7 +233,7 @@
 	}
 }
 
-// isZip64 returns true if the file size exceeds the 32 bit limit
+// isZip64 reports whether the file size exceeds the 32 bit limit
 func (fh *FileHeader) isZip64() bool {
 	return fh.CompressedSize64 > uint32max || fh.UncompressedSize64 > uint32max
 }
diff --git a/src/archive/zip/writer.go b/src/archive/zip/writer.go
index 6a71887..87ac694 100644
--- a/src/archive/zip/writer.go
+++ b/src/archive/zip/writer.go
@@ -34,6 +34,17 @@
 	return &Writer{cw: &countWriter{w: bufio.NewWriter(w)}}
 }
 
+// SetOffset sets the offset of the beginning of the zip data within the
+// underlying writer. It should be used when the zip data is appended to an
+// existing file, such as a binary executable.
+// It must be called before any data is written.
+func (w *Writer) SetOffset(n int64) {
+	if w.cw.count != 0 {
+		panic("zip: SetOffset called after data was written")
+	}
+	w.cw.count = n
+}
+
 // Flush flushes any buffered data to the underlying writer.
 // Calling Flush is not normally necessary; calling Close is sufficient.
 func (w *Writer) Flush() error {
diff --git a/src/archive/zip/writer_test.go b/src/archive/zip/writer_test.go
index 184a7d9..01b63f2 100644
--- a/src/archive/zip/writer_test.go
+++ b/src/archive/zip/writer_test.go
@@ -87,6 +87,41 @@
 	}
 }
 
+func TestWriterOffset(t *testing.T) {
+	largeData := make([]byte, 1<<17)
+	for i := range largeData {
+		largeData[i] = byte(rand.Int())
+	}
+	writeTests[1].Data = largeData
+	defer func() {
+		writeTests[1].Data = nil
+	}()
+
+	// write a zip file
+	buf := new(bytes.Buffer)
+	existingData := []byte{1, 2, 3, 1, 2, 3, 1, 2, 3}
+	n, _ := buf.Write(existingData)
+	w := NewWriter(buf)
+	w.SetOffset(int64(n))
+
+	for _, wt := range writeTests {
+		testCreate(t, w, &wt)
+	}
+
+	if err := w.Close(); err != nil {
+		t.Fatal(err)
+	}
+
+	// read it back
+	r, err := NewReader(bytes.NewReader(buf.Bytes()), int64(buf.Len()))
+	if err != nil {
+		t.Fatal(err)
+	}
+	for i, wt := range writeTests {
+		testReadFile(t, r.File[i], &wt)
+	}
+}
+
 func TestWriterFlush(t *testing.T) {
 	var buf bytes.Buffer
 	w := NewWriter(struct{ io.Writer }{&buf})
diff --git a/src/bootstrap.bash b/src/bootstrap.bash
new file mode 100755
index 0000000..60d6151c
--- /dev/null
+++ b/src/bootstrap.bash
@@ -0,0 +1,71 @@
+#!/bin/bash
+# Copyright 2015 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.
+
+# When run as (for example)
+#
+#	GOOS=linux GOARCH=ppc64 bootstrap.bash
+#
+# this script cross-compiles a toolchain for that GOOS/GOARCH
+# combination, leaving the resulting tree in ../../go-${GOOS}-${GOARCH}-bootstrap.
+# That tree can be copied to a machine of the given target type
+# and used as $GOROOT_BOOTSTRAP to bootstrap a local build.
+#
+# Only changes that have been committed to Git (at least locally,
+# not necessary reviewed and submitted to master) are included in the tree.
+
+set -e
+
+if [ "$GOOS" = "" -o "$GOARCH" = "" ]; then
+	echo "usage: GOOS=os GOARCH=arch ./bootstrap.bash" >&2
+	exit 2
+fi
+
+targ="../../go-${GOOS}-${GOARCH}-bootstrap"
+if [ -e $targ ]; then
+	echo "$targ already exists; remove before continuing"
+	exit 2
+fi
+
+unset GOROOT
+src=$(cd .. && pwd)
+echo "#### Copying to $targ"
+cp -R "$src" "$targ"
+cd "$targ"
+echo
+echo "#### Cleaning $targ"
+rm .gitignore
+git clean -f -d
+echo
+echo "#### Building $targ"
+echo
+cd src
+./make.bash --no-banner
+gohostos="$(../bin/go env GOHOSTOS)"
+gohostarch="$(../bin/go env GOHOSTARCH)"
+goos="$(../bin/go env GOOS)"
+goarch="$(../bin/go env GOARCH)"
+
+# NOTE: Cannot invoke go command after this point.
+# We're about to delete all but the cross-compiled binaries.
+cd ..
+if [ "$goos" = "$gohostos" -a "$goarch" = "$gohostarch" ]; then
+	# cross-compile for local system. nothing to copy.
+	# useful if you've bootstrapped yourself but want to
+	# prepare a clean toolchain for others.
+	true
+else
+	mv bin/*_*/* bin
+	rmdir bin/*_*
+	rm -rf "pkg/${gohostos}_${gohostarch}" "pkg/tool/${gohostos}_${gohostarch}"
+fi
+rm -rf pkg/bootstrap pkg/obj .git
+
+echo ----
+echo Bootstrap toolchain for "$GOOS/$GOARCH" installed in "$(pwd)".
+echo Building tbz.
+cd ..
+tar cf - "go-${GOOS}-${GOARCH}-bootstrap" | bzip2 -9 >"go-${GOOS}-${GOARCH}-bootstrap.tbz"
+ls -l "$(pwd)/go-${GOOS}-${GOARCH}-bootstrap.tbz"
+exit 0
diff --git a/src/bufio/scan.go b/src/bufio/scan.go
index 364d159..7a349fa 100644
--- a/src/bufio/scan.go
+++ b/src/bufio/scan.go
@@ -109,7 +109,7 @@
 // After Scan returns false, the Err method will return any error that
 // occurred during scanning, except that if it was io.EOF, Err
 // will return nil.
-// Split panics if the split function returns 100 empty tokens without
+// Scan panics if the split function returns 100 empty tokens without
 // advancing the input. This is a common error mode for scanners.
 func (s *Scanner) Scan() bool {
 	// Loop until we have a token.
diff --git a/src/bytes/bytes.go b/src/bytes/bytes.go
index f24a071..60de451 100644
--- a/src/bytes/bytes.go
+++ b/src/bytes/bytes.go
@@ -443,7 +443,7 @@
 // Title returns a copy of s with all Unicode letters that begin words
 // mapped to their title case.
 //
-// BUG: The rule Title uses for word boundaries does not handle Unicode punctuation properly.
+// BUG(rsc): The rule Title uses for word boundaries does not handle Unicode punctuation properly.
 func Title(s []byte) []byte {
 	// Use a closure here to remember state.
 	// Hackish but effective. Depends on Map scanning in order and calling
diff --git a/src/bytes/compare_test.go b/src/bytes/compare_test.go
index 6352237..f2d81d5 100644
--- a/src/bytes/compare_test.go
+++ b/src/bytes/compare_test.go
@@ -17,6 +17,8 @@
 	{[]byte("a"), []byte(""), 1},
 	{[]byte(""), []byte("a"), -1},
 	{[]byte("abc"), []byte("abc"), 0},
+	{[]byte("abd"), []byte("abc"), 1},
+	{[]byte("abc"), []byte("abd"), -1},
 	{[]byte("ab"), []byte("abc"), -1},
 	{[]byte("abc"), []byte("ab"), 1},
 	{[]byte("x"), []byte("ab"), 1},
@@ -27,6 +29,7 @@
 	{[]byte("abcdefgh"), []byte("abcdefgh"), 0},
 	{[]byte("abcdefghi"), []byte("abcdefghi"), 0},
 	{[]byte("abcdefghi"), []byte("abcdefghj"), -1},
+	{[]byte("abcdefghj"), []byte("abcdefghi"), 1},
 	// nil tests
 	{nil, nil, 0},
 	{[]byte(""), nil, 0},
diff --git a/src/cmd/5g/cgen.go b/src/cmd/5g/cgen.go
index 638c5a6..07ced87 100644
--- a/src/cmd/5g/cgen.go
+++ b/src/cmd/5g/cgen.go
@@ -5,609 +5,10 @@
 package main
 
 import (
+	"cmd/internal/gc"
 	"cmd/internal/obj"
 	"cmd/internal/obj/arm"
-	"fmt"
 )
-import "cmd/internal/gc"
-
-/*
- * 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)
-	}
-
-	var n1 gc.Node
-	var nr *gc.Node
-	var nl *gc.Node
-	var a int
-	var f1 gc.Node
-	var f0 gc.Node
-	var n2 gc.Node
-	if n == nil || n.Type == nil {
-		goto ret
-	}
-
-	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)
-			goto ret
-		}
-	}
-
-	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)
-		goto ret
-	}
-
-	// 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] != 0 || gc.Iscomplex[res.Type.Etype] != 0 {
-			gmove(n, res)
-		} else {
-			var n1 gc.Node
-			regalloc(&n1, n.Type, nil)
-			gmove(n, &n1)
-			cgen(&n1, res)
-			regfree(&n1)
-		}
-
-		goto ret
-	}
-
-	// 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] == 0 && gc.Iscomplex[res.Type.Etype] == 0 {
-		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()
-			goto ret
-		}
-	}
-
-	// 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)
-			goto ret
-		}
-	}
-
-	// 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] != 0 && gc.Isfloat[nl.Type.Etype] != 0 {
-		goto flt
-	}
-	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)
-		goto ret
-
-	case gc.OPLUS:
-		cgen(nl, res)
-		goto ret
-
-		// 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)
-
-		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.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] != 0 {
-				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] != 0 {
-			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.S, &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
-	}
-
-	goto ret
-
-sbop: // symmetric binary
-	if nl.Ullman < nr.Ullman {
-		r := nl
-		nl = nr
-		nr = r
-	}
-
-	// 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)
-	}
-	goto ret
-
-flt: // 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)
-	goto ret
-
-flt2: // binary
-	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)
-	goto ret
-
-ret:
-}
 
 /*
  * generate array index into res.
@@ -616,13 +17,13 @@
  */
 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)
@@ -633,921 +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
-	}
-
-	var nl *gc.Node
-	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)
-		goto ret
-	}
-
-	if n.Addable != 0 {
-		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)
-		goto ret
-	}
-
-	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)
-		}
-	}
-
-ret:
-}
-
-/*
- * 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:
-		p2 := (*obj.Prog)(nil) // 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.S)))
-			} 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.S, &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)
-	}
-
-	var et int
-	var nl *gc.Node
-	var nr *gc.Node
-	if n.Type == nil {
-		gc.Convlit(&n, gc.Types[gc.TBOOL])
-		if n.Type == nil {
-			goto ret
-		}
-	}
-
-	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)
-		goto ret
-	}
-
-	nr = nil
-
-	switch n.Op {
-	default:
-		a := gc.ONE
-		if !true_ {
-			a = gc.OEQ
-		}
-		gencmp0(n, n.Type, a, likely, to)
-		goto ret
-
-		// 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)
-		}
-		goto ret
-
-	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)
-		}
-
-		goto ret
-
-	case gc.OEQ,
-		gc.ONE,
-		gc.OLT,
-		gc.OGT,
-		gc.OLE,
-		gc.OGE:
-		nr = n.Right
-		if nr == nil || nr.Type == nil {
-			goto ret
-		}
-		fallthrough
-
-	case gc.ONOT: // unary
-		nl = n.Left
-
-		if nl == nil || nl.Type == nil {
-			goto ret
-		}
-	}
-
-	switch n.Op {
-	case gc.ONOT:
-		bgen(nl, !true_, likely, to)
-		goto ret
-
-	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] != 0 {
-				// 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)
-				goto ret
-			}
-
-			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] != 0 {
-			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] != 0 {
-			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)
-	}
-
-	goto ret
-
-ret:
-}
-
-/*
- * 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] != 0 {
-			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] != 0 {
-			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 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.
@@ -1574,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
 	}
@@ -1606,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)
@@ -1644,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
-	nend := gc.Node{}
+	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
@@ -1714,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 {
@@ -1735,272 +245,7 @@
 		}
 	}
 
-	regfree(&dst)
-	regfree(&src)
-	regfree(&tmp)
-}
-
-func cadable(n *gc.Node) bool {
-	if n.Addable == 0 {
-		// dont know how it happens,
-		// but it does
-		return false
-	}
-
-	switch n.Op {
-	case gc.ONAME:
-		return true
-	}
-
-	return false
-}
-
-/*
- * copy a composite value by moving its individual components.
- * Slices, strings and interfaces are supported.
- * Small structs or arrays with elements of basic type are
- * also supported.
- * nr is N when assigning a zero value.
- * return 1 if can do, 0 if cant.
- */
-func componentgen(nr *gc.Node, nl *gc.Node) bool {
-	var nodl gc.Node
-	var nodr gc.Node
-
-	freel := 0
-	freer := 0
-
-	switch nl.Type.Etype {
-	default:
-		goto no
-
-	case gc.TARRAY:
-		t := nl.Type
-
-		// Slices are ok.
-		if gc.Isslice(t) {
-			break
-		}
-
-		// Small arrays are ok.
-		if t.Bound > 0 && t.Bound <= 3 && !gc.Isfat(t.Type) {
-			break
-		}
-
-		goto no
-
-		// Small structs with non-fat types are ok.
-	// Zero-sized structs are treated separately elsewhere.
-	case gc.TSTRUCT:
-		fldcount := int64(0)
-
-		for t := nl.Type.Type; t != nil; t = t.Down {
-			if gc.Isfat(t.Type) {
-				goto no
-			}
-			if t.Etype != gc.TFIELD {
-				gc.Fatal("componentgen: not a TFIELD: %v", gc.Tconv(t, obj.FmtLong))
-			}
-			fldcount++
-		}
-
-		if fldcount == 0 || fldcount > 4 {
-			goto no
-		}
-
-	case gc.TSTRING,
-		gc.TINTER:
-		break
-	}
-
-	nodl = *nl
-	if !cadable(nl) {
-		if nr != nil && !cadable(nr) {
-			goto no
-		}
-		igen(nl, &nodl, nil)
-		freel = 1
-	}
-
-	if nr != nil {
-		nodr = *nr
-		if !cadable(nr) {
-			igen(nr, &nodr, nil)
-			freer = 1
-		}
-	} else {
-		// When zeroing, prepare a register containing zero.
-		var tmp gc.Node
-		gc.Nodconst(&tmp, nl.Type, 0)
-
-		regalloc(&nodr, gc.Types[gc.TUINT], nil)
-		gmove(&tmp, &nodr)
-		freer = 1
-	}
-
-	// nl and nr are 'cadable' which basically means they are names (variables) now.
-	// If they are the same variable, don't generate any code, because the
-	// VARDEF we generate will mark the old value as dead incorrectly.
-	// (And also the assignments are useless.)
-	if nr != nil && nl.Op == gc.ONAME && nr.Op == gc.ONAME && nl == nr {
-		goto yes
-	}
-
-	switch nl.Type.Etype {
-	// componentgen for arrays.
-	case gc.TARRAY:
-		if nl.Op == gc.ONAME {
-			gc.Gvardef(nl)
-		}
-		t := nl.Type
-		if !gc.Isslice(t) {
-			nodl.Type = t.Type
-			nodr.Type = nodl.Type
-			for fldcount := int64(0); fldcount < t.Bound; fldcount++ {
-				if nr == nil {
-					gc.Clearslim(&nodl)
-				} else {
-					gmove(&nodr, &nodl)
-				}
-				nodl.Xoffset += t.Type.Width
-				nodr.Xoffset += t.Type.Width
-			}
-
-			goto yes
-		}
-
-		// componentgen for slices.
-		nodl.Xoffset += int64(gc.Array_array)
-
-		nodl.Type = gc.Ptrto(nl.Type.Type)
-
-		if nr != nil {
-			nodr.Xoffset += int64(gc.Array_array)
-			nodr.Type = nodl.Type
-		}
-
-		gmove(&nodr, &nodl)
-
-		nodl.Xoffset += int64(gc.Array_nel) - int64(gc.Array_array)
-		nodl.Type = gc.Types[gc.Simtype[gc.TUINT]]
-
-		if nr != nil {
-			nodr.Xoffset += int64(gc.Array_nel) - int64(gc.Array_array)
-			nodr.Type = nodl.Type
-		}
-
-		gmove(&nodr, &nodl)
-
-		nodl.Xoffset += int64(gc.Array_cap) - int64(gc.Array_nel)
-		nodl.Type = gc.Types[gc.Simtype[gc.TUINT]]
-
-		if nr != nil {
-			nodr.Xoffset += int64(gc.Array_cap) - int64(gc.Array_nel)
-			nodr.Type = nodl.Type
-		}
-
-		gmove(&nodr, &nodl)
-
-		goto yes
-
-	case gc.TSTRING:
-		if nl.Op == gc.ONAME {
-			gc.Gvardef(nl)
-		}
-		nodl.Xoffset += int64(gc.Array_array)
-		nodl.Type = gc.Ptrto(gc.Types[gc.TUINT8])
-
-		if nr != nil {
-			nodr.Xoffset += int64(gc.Array_array)
-			nodr.Type = nodl.Type
-		}
-
-		gmove(&nodr, &nodl)
-
-		nodl.Xoffset += int64(gc.Array_nel) - int64(gc.Array_array)
-		nodl.Type = gc.Types[gc.Simtype[gc.TUINT]]
-
-		if nr != nil {
-			nodr.Xoffset += int64(gc.Array_nel) - int64(gc.Array_array)
-			nodr.Type = nodl.Type
-		}
-
-		gmove(&nodr, &nodl)
-
-		goto yes
-
-	case gc.TINTER:
-		if nl.Op == gc.ONAME {
-			gc.Gvardef(nl)
-		}
-		nodl.Xoffset += int64(gc.Array_array)
-		nodl.Type = gc.Ptrto(gc.Types[gc.TUINT8])
-
-		if nr != nil {
-			nodr.Xoffset += int64(gc.Array_array)
-			nodr.Type = nodl.Type
-		}
-
-		gmove(&nodr, &nodl)
-
-		nodl.Xoffset += int64(gc.Array_nel) - int64(gc.Array_array)
-		nodl.Type = gc.Ptrto(gc.Types[gc.TUINT8])
-
-		if nr != nil {
-			nodr.Xoffset += int64(gc.Array_nel) - int64(gc.Array_array)
-			nodr.Type = nodl.Type
-		}
-
-		gmove(&nodr, &nodl)
-
-		goto yes
-
-	case gc.TSTRUCT:
-		if nl.Op == gc.ONAME {
-			gc.Gvardef(nl)
-		}
-		loffset := nodl.Xoffset
-		roffset := nodr.Xoffset
-
-		// funarg structs may not begin at offset zero.
-		if nl.Type.Etype == gc.TSTRUCT && nl.Type.Funarg != 0 && nl.Type.Type != nil {
-			loffset -= nl.Type.Type.Width
-		}
-		if nr != nil && nr.Type.Etype == gc.TSTRUCT && nr.Type.Funarg != 0 && nr.Type.Type != nil {
-			roffset -= nr.Type.Type.Width
-		}
-
-		for t := nl.Type.Type; t != nil; t = t.Down {
-			nodl.Xoffset = loffset + t.Width
-			nodl.Type = t.Type
-
-			if nr == nil {
-				gc.Clearslim(&nodl)
-			} else {
-				nodr.Xoffset = roffset + t.Width
-				nodr.Type = nodl.Type
-				gmove(&nodr, &nodl)
-			}
-		}
-
-		goto yes
-	}
-
-no:
-	if freer != 0 {
-		regfree(&nodr)
-	}
-	if freel != 0 {
-		regfree(&nodl)
-	}
-	return false
-
-yes:
-	if freer != 0 {
-		regfree(&nodr)
-	}
-	if freel != 0 {
-		regfree(&nodl)
-	}
-	return true
+	gc.Regfree(&dst)
+	gc.Regfree(&src)
+	gc.Regfree(&tmp)
 }
diff --git a/src/cmd/5g/cgen64.go b/src/cmd/5g/cgen64.go
index b9e5b7c..05f2e1e 100644
--- a/src/cmd/5g/cgen64.go
+++ b/src/cmd/5g/cgen64.go
@@ -5,10 +5,10 @@
 package main
 
 import (
+	"cmd/internal/gc"
 	"cmd/internal/obj"
 	"cmd/internal/obj/arm"
 )
-import "cmd/internal/gc"
 
 /*
  * attempt to generate 64-bit
@@ -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,15 +782,15 @@
 	// 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)
 
-	br := (*obj.Prog)(nil)
+	var br *obj.Prog
 	switch op {
 	default:
 		gc.Fatal("cmp64 %v %v", gc.Oconv(int(op), 0), gc.Tconv(t, 0))
@@ -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 d2eeeab..1b349e1 100644
--- a/src/cmd/5g/galign.go
+++ b/src/cmd/5g/galign.go
@@ -5,10 +5,10 @@
 package main
 
 import (
+	"cmd/internal/gc"
 	"cmd/internal/obj"
 	"cmd/internal/obj/arm"
 )
-import "cmd/internal/gc"
 
 var thechar int = '5'
 
@@ -45,32 +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.Igen = igen
+	gc.Thearch.Ginscon = ginscon
+	gc.Thearch.Ginsnop = ginsnop
+	gc.Thearch.Gmove = gmove
+	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 8b7010f..753c6e0 100644
--- a/src/cmd/5g/ggen.go
+++ b/src/cmd/5g/ggen.go
@@ -5,10 +5,10 @@
 package main
 
 import (
+	"cmd/internal/gc"
 	"cmd/internal/obj"
 	"cmd/internal/obj/arm"
 )
-import "cmd/internal/gc"
 
 func defframe(ptxt *obj.Prog) {
 	var n *gc.Node
@@ -16,7 +16,7 @@
 	// fill in argument size, stack size
 	ptxt.To.Type = obj.TYPE_TEXTSIZE
 
-	ptxt.To.U.Argsize = int32(gc.Rnd(gc.Curfn.Type.Argwid, int64(gc.Widthptr)))
+	ptxt.To.Val = int32(gc.Rnd(gc.Curfn.Type.Argwid, int64(gc.Widthptr)))
 	frame := uint32(gc.Rnd(gc.Stksize+gc.Maxarg, int64(gc.Widthreg)))
 	ptxt.To.Offset = int64(frame)
 
@@ -28,9 +28,9 @@
 	hi := int64(0)
 	lo := hi
 	r0 := uint32(0)
-	for l := gc.Curfn.Dcl; l != nil; l = l.Next {
+	for l := gc.Curfn.Func.Dcl; l != nil; l = l.Next {
 		n = l.N
-		if n.Needzero == 0 {
+		if !n.Needzero {
 			continue
 		}
 		if n.Class != gc.PAUTO {
@@ -78,7 +78,7 @@
 		p.Reg = arm.REGSP
 		p = appendpp(p, obj.ADUFFZERO, obj.TYPE_NONE, 0, 0, obj.TYPE_MEM, 0, 0)
 		f := gc.Sysfunc("duffzero")
-		gc.Naddr(f, &p.To, 1)
+		gc.Naddr(&p.To, f)
 		gc.Afunclit(&p.To, f)
 		p.To.Offset = 4 * (128 - cnt/int64(gc.Widthptr))
 	} else {
@@ -115,326 +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)
-		goto ret
-	}
-
-	// 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)
-		goto ret
-	}
-
-	// call direct
-	n.Left.Method = 1
-
-	ginscall(n.Left, proc)
-
-ret:
-}
-
-/*
- * 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")
-	}
-
-	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] != 0 {
-		t = t.Type
-	}
-
-	var flist gc.Iter
-	fp := gc.Structfirst(&flist, gc.Getoutarg(t))
-	if fp == nil {
-		gc.Fatal("cgen_aret: nil")
-	}
-
-	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
  */
@@ -448,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:
@@ -468,7 +148,7 @@
 	case gc.TINT32,
 		gc.TUINT32:
 		var p *obj.Prog
-		if gc.Issigned[t.Etype] != 0 {
+		if gc.Issigned[t.Etype] {
 			p = gins(arm.AMULL, &n2, nil)
 		} else {
 			p = gins(arm.AMULLU, &n2, nil)
@@ -485,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)
 }
 
 /*
@@ -505,42 +185,42 @@
 	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
 		if sc >= uint64(nl.Type.Width*8) {
-			if op == gc.ORSH && gc.Issigned[nl.Type.Etype] != 0 {
+			if op == gc.ORSH && gc.Issigned[nl.Type.Etype] {
 				gshift(arm.AMOVW, &n1, arm.SHIFT_AR, int32(w), &n1)
 			} else {
 				gins(arm.AEOR, &n1, &n1)
 			}
 		} else {
-			if op == gc.ORSH && gc.Issigned[nl.Type.Etype] != 0 {
+			if op == gc.ORSH && gc.Issigned[nl.Type.Etype] {
 				gshift(arm.AMOVW, &n1, arm.SHIFT_AR, int32(sc), &n1)
 			} else if op == gc.ORSH {
 				gshift(arm.AMOVW, &n1, arm.SHIFT_LR, int32(sc), &n1) // OLSH
@@ -553,7 +233,7 @@
 			gins(optoas(gc.OAS, nl.Type), &n1, &n1)
 		}
 		gmove(&n1, res)
-		regfree(&n1)
+		gc.Regfree(&n1)
 		return
 	}
 
@@ -566,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()
@@ -589,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)
 		}
 	}
 
@@ -611,15 +291,15 @@
 
 	// 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
-		if gc.Issigned[nl.Type.Etype] != 0 {
+		if gc.Issigned[nl.Type.Etype] {
 			p1 = gshift(arm.AMOVW, &n2, arm.SHIFT_AR, int32(w)-1, &n2)
 			p2 = gregshift(arm.AMOVW, &n2, arm.SHIFT_AR, &n1, &n2)
 		} else {
@@ -636,7 +316,7 @@
 		p2.Scond = arm.C_SCOND_LO
 	}
 
-	regfree(&n3)
+	gc.Regfree(&n3)
 
 	gc.Patch(p3, gc.Pc)
 
@@ -646,8 +326,8 @@
 	}
 	gmove(&n2, res)
 
-	regfree(&n1)
-	regfree(&n2)
+	gc.Regfree(&n1)
+	gc.Regfree(&n2)
 }
 
 func clearfat(nl *gc.Node) {
@@ -659,7 +339,7 @@
 	w := uint32(nl.Type.Width)
 
 	// Avoid taking the address for simple enough types.
-	if componentgen(nil, nl) {
+	if gc.Componentgen(nil, nl) {
 		return
 	}
 
@@ -669,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
@@ -699,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)
@@ -731,8 +411,8 @@
 		c--
 	}
 
-	regfree(&dst)
-	regfree(&nz)
+	gc.Regfree(&dst)
+	gc.Regfree(&nz)
 }
 
 // Called after regopt and peep have run.
@@ -777,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 ce0d5e8..0d22f74 100644
--- a/src/cmd/5g/gsubr.go
+++ b/src/cmd/5g/gsubr.go
@@ -31,11 +31,11 @@
 package main
 
 import (
+	"cmd/internal/gc"
 	"cmd/internal/obj"
 	"cmd/internal/obj/arm"
 	"fmt"
 )
-import "cmd/internal/gc"
 
 // TODO(rsc): Can make this bigger if we move
 // the text segment up higher in 5l for all GOOS.
@@ -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])
 	}
 }
 
@@ -324,17 +147,15 @@
 	tt := gc.Simsimtype(t.Type)
 	cvt := t.Type
 
-	if gc.Iscomplex[ft] != 0 || gc.Iscomplex[tt] != 0 {
+	if gc.Iscomplex[ft] || gc.Iscomplex[tt] {
 		gc.Complexmove(f, t)
 		return
 	}
 
 	// cannot have two memory operands;
 	// except 64-bit, which always copies via registers anyway.
-	var flo gc.Node
 	var a int
 	var r1 gc.Node
-	var fhi gc.Node
 	if !gc.Is64(f.Type) && !gc.Is64(t.Type) && gc.Ismem(f) && gc.Ismem(t) {
 		goto hard
 	}
@@ -351,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,
@@ -362,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
 		}
 
@@ -387,7 +208,9 @@
 
 	switch uint32(ft)<<16 | uint32(tt) {
 	default:
-		goto fatal
+		// should not happen
+		gc.Fatal("gmove %v -> %v", gc.Nconv(f, 0), gc.Nconv(t, 0))
+		return
 
 		/*
 		 * integer copy and truncate
@@ -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
 	}
 
@@ -766,36 +589,36 @@
 	// removed.
 	// requires register destination
 rdst:
-	regalloc(&r1, t.Type, t)
+	{
+		gc.Regalloc(&r1, t.Type, t)
 
-	gins(a, f, &r1)
-	gmove(&r1, t)
-	regfree(&r1)
-	return
+		gins(a, f, &r1)
+		gmove(&r1, t)
+		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
 trunc64:
+	var fhi gc.Node
+	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
-
-	// should not happen
-fatal:
-	gc.Fatal("gmove %v -> %v", gc.Nconv(f, 0), gc.Nconv(t, 0))
 }
 
 func samaddr(f *gc.Node, t *gc.Node) bool {
@@ -826,38 +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);
-	af := obj.Addr{}
+	//		gc.Regfree(&nod);
 
-	at := obj.Addr{}
-	if f != nil {
-		gc.Naddr(f, &af, 1)
-	}
-	if t != nil {
-		gc.Naddr(t, &at, 1)
-	}
 	p := gc.Prog(as)
-	if f != nil {
-		p.From = af
+	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 t != nil {
-		p.To = at
-	}
+
 	if gc.Debug['g'] != 0 {
 		fmt.Printf("%v\n", p)
 	}
@@ -869,8 +721,7 @@
  */
 func raddr(n *gc.Node, p *obj.Prog) {
 	var a obj.Addr
-
-	gc.Naddr(n, &a, 1)
+	gc.Naddr(&a, n)
 	if a.Type != obj.TYPE_REG {
 		if n != nil {
 			gc.Fatal("bad in raddr: %v", gc.Oconv(int(n.Op), 0))
@@ -883,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.
  */
@@ -1045,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
 
@@ -1229,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
 }
@@ -1266,19 +1108,13 @@
  * 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
 	}
 
 	*a = obj.Addr{}
 
-	var oary [10]int64
-	var nn *gc.Node
-	var reg *gc.Node
-	var n1 gc.Node
-	var reg1 *gc.Node
-	var o int
 	switch n.Op {
 	case gc.OLITERAL:
 		if !gc.Isconst(n, gc.CTINT) {
@@ -1288,98 +1124,88 @@
 		if v >= 32000 || v <= -32000 {
 			break
 		}
-		goto lit
+		switch as {
+		default:
+			return false
+
+		case arm.AADD,
+			arm.ASUB,
+			arm.AAND,
+			arm.AORR,
+			arm.AEOR,
+			arm.AMOVB,
+			arm.AMOVBS,
+			arm.AMOVBU,
+			arm.AMOVH,
+			arm.AMOVHS,
+			arm.AMOVHU,
+			arm.AMOVW:
+			break
+		}
+
+		cleani += 2
+		reg := &clean[cleani-1]
+		reg1 := &clean[cleani-2]
+		reg.Op = gc.OEMPTY
+		reg1.Op = gc.OEMPTY
+		gc.Naddr(a, n)
+		return true
 
 	case gc.ODOT,
 		gc.ODOTPTR:
 		cleani += 2
-		reg = &clean[cleani-1]
+		reg := &clean[cleani-1]
 		reg1 := &clean[cleani-2]
 		reg.Op = gc.OEMPTY
 		reg1.Op = gc.OEMPTY
-		goto odot
+		var nn *gc.Node
+		var oary [10]int64
+		o := gc.Dotoffset(n, oary[:], &nn)
+		if nn == nil {
+			sudoclean()
+			return false
+		}
+
+		if nn.Addable != 0 && o == 1 && oary[0] >= 0 {
+			// directly addressable set of DOTs
+			n1 := *nn
+
+			n1.Type = n.Type
+			n1.Xoffset += oary[0]
+			gc.Naddr(a, &n1)
+			return true
+		}
+
+		gc.Regalloc(reg, gc.Types[gc.Tptr], nil)
+		n1 := *reg
+		n1.Op = gc.OINDREG
+		if oary[0] >= 0 {
+			gc.Agen(nn, reg)
+			n1.Xoffset = oary[0]
+		} else {
+			gc.Cgen(nn, reg)
+			gc.Cgen_checknil(reg)
+			n1.Xoffset = -(oary[0] + 1)
+		}
+
+		for i := 1; i < o; i++ {
+			if oary[i] >= 0 {
+				gc.Fatal("can't happen")
+			}
+			gins(arm.AMOVW, &n1, reg)
+			gc.Cgen_checknil(reg)
+			n1.Xoffset = -(oary[i] + 1)
+		}
+
+		a.Type = obj.TYPE_NONE
+		a.Name = obj.NAME_NONE
+		n1.Type = n.Type
+		gc.Naddr(a, &n1)
+		return true
 
 	case gc.OINDEX:
 		return false
 	}
 
 	return false
-
-lit:
-	switch as {
-	default:
-		return false
-
-	case arm.AADD,
-		arm.ASUB,
-		arm.AAND,
-		arm.AORR,
-		arm.AEOR,
-		arm.AMOVB,
-		arm.AMOVBS,
-		arm.AMOVBU,
-		arm.AMOVH,
-		arm.AMOVHS,
-		arm.AMOVHU,
-		arm.AMOVW:
-		break
-	}
-
-	cleani += 2
-	reg = &clean[cleani-1]
-	reg1 = &clean[cleani-2]
-	reg.Op = gc.OEMPTY
-	reg1.Op = gc.OEMPTY
-	gc.Naddr(n, a, 1)
-	goto yes
-
-odot:
-	o = gc.Dotoffset(n, oary[:], &nn)
-	if nn == nil {
-		goto no
-	}
-
-	if nn.Addable != 0 && o == 1 && oary[0] >= 0 {
-		// directly addressable set of DOTs
-		n1 := *nn
-
-		n1.Type = n.Type
-		n1.Xoffset += oary[0]
-		gc.Naddr(&n1, a, 1)
-		goto yes
-	}
-
-	regalloc(reg, gc.Types[gc.Tptr], nil)
-	n1 = *reg
-	n1.Op = gc.OINDREG
-	if oary[0] >= 0 {
-		agen(nn, reg)
-		n1.Xoffset = oary[0]
-	} else {
-		cgen(nn, reg)
-		gc.Cgen_checknil(reg)
-		n1.Xoffset = -(oary[0] + 1)
-	}
-
-	for i := 1; i < o; i++ {
-		if oary[i] >= 0 {
-			gc.Fatal("can't happen")
-		}
-		gins(arm.AMOVW, &n1, reg)
-		gc.Cgen_checknil(reg)
-		n1.Xoffset = -(oary[i] + 1)
-	}
-
-	a.Type = obj.TYPE_NONE
-	a.Name = obj.NAME_NONE
-	n1.Type = n.Type
-	gc.Naddr(&n1, a, 1)
-	goto yes
-
-yes:
-	return true
-
-no:
-	sudoclean()
-	return false
 }
diff --git a/src/cmd/5g/peep.go b/src/cmd/5g/peep.go
index e28ec02..5305e4b 100644
--- a/src/cmd/5g/peep.go
+++ b/src/cmd/5g/peep.go
@@ -31,11 +31,11 @@
 package main
 
 import (
+	"cmd/internal/gc"
 	"cmd/internal/obj"
 	"cmd/internal/obj/arm"
 	"fmt"
 )
-import "cmd/internal/gc"
 
 var gactive uint32
 
@@ -257,9 +257,7 @@
 	if !regtyp(v2) {
 		return false
 	}
-	var r *gc.Flow
-	var info gc.ProgInfo
-	for r = gc.Uniqp(r0); r != nil; r = gc.Uniqp(r) {
+	for r := gc.Uniqp(r0); r != nil; r = gc.Uniqp(r) {
 		if gc.Uniqs(r) == nil {
 			break
 		}
@@ -267,14 +265,16 @@
 		if p.As == obj.AVARDEF || p.As == obj.AVARKILL {
 			continue
 		}
-		proginfo(&info, p)
-		if info.Flags&gc.Call != 0 {
+		if p.Info.Flags&gc.Call != 0 {
 			return false
 		}
 
-		if (info.Flags&gc.CanRegRead != 0) && p.To.Type == obj.TYPE_REG {
-			info.Flags |= gc.RegRead
-			info.Flags &^= (gc.CanRegRead | gc.RightRead)
+		// TODO(rsc): Whatever invalidated the info should have done this call.
+		proginfo(p)
+
+		if (p.Info.Flags&gc.CanRegRead != 0) && p.To.Type == obj.TYPE_REG {
+			p.Info.Flags |= gc.RegRead
+			p.Info.Flags &^= (gc.CanRegRead | gc.RightRead)
 			p.Reg = p.To.Reg
 		}
 
@@ -285,11 +285,36 @@
 			return false
 		}
 
-		if info.Flags&(gc.RightRead|gc.RightWrite) == gc.RightWrite {
+		if p.Info.Flags&(gc.RightRead|gc.RightWrite) == gc.RightWrite {
 			if p.To.Type == v1.Type {
 				if p.To.Reg == v1.Reg {
 					if p.Scond == arm.C_SCOND_NONE {
-						goto gotit
+						copysub(&p.To, v1, v2, 1)
+						if gc.Debug['P'] != 0 {
+							fmt.Printf("gotit: %v->%v\n%v", gc.Ctxt.Dconv(v1), gc.Ctxt.Dconv(v2), r.Prog)
+							if p.From.Type == v2.Type {
+								fmt.Printf(" excise")
+							}
+							fmt.Printf("\n")
+						}
+
+						for r = gc.Uniqs(r); r != r0; r = gc.Uniqs(r) {
+							p = r.Prog
+							copysub(&p.From, v1, v2, 1)
+							copysub1(p, v1, v2, 1)
+							copysub(&p.To, v1, v2, 1)
+							if gc.Debug['P'] != 0 {
+								fmt.Printf("%v\n", r.Prog)
+							}
+						}
+
+						t := int(int(v1.Reg))
+						v1.Reg = v2.Reg
+						v2.Reg = int16(t)
+						if gc.Debug['P'] != 0 {
+							fmt.Printf("%v last\n", r.Prog)
+						}
+						return true
 					}
 				}
 			}
@@ -304,34 +329,6 @@
 	}
 
 	return false
-
-gotit:
-	copysub(&p.To, v1, v2, 1)
-	if gc.Debug['P'] != 0 {
-		fmt.Printf("gotit: %v->%v\n%v", gc.Ctxt.Dconv(v1), gc.Ctxt.Dconv(v2), r.Prog)
-		if p.From.Type == v2.Type {
-			fmt.Printf(" excise")
-		}
-		fmt.Printf("\n")
-	}
-
-	for r = gc.Uniqs(r); r != r0; r = gc.Uniqs(r) {
-		p = r.Prog
-		copysub(&p.From, v1, v2, 1)
-		copysub1(p, v1, v2, 1)
-		copysub(&p.To, v1, v2, 1)
-		if gc.Debug['P'] != 0 {
-			fmt.Printf("%v\n", r.Prog)
-		}
-	}
-
-	t := int(int(v1.Reg))
-	v1.Reg = v2.Reg
-	v2.Reg = int16(t)
-	if gc.Debug['P'] != 0 {
-		fmt.Printf("%v last\n", r.Prog)
-	}
-	return true
 }
 
 /*
@@ -548,7 +545,7 @@
 	}
 
 	if gc.Debug['P'] != 0 {
-		fmt.Printf(" => %v\n", arm.Aconv(int(p.As)))
+		fmt.Printf(" => %v\n", obj.Aconv(int(p.As)))
 	}
 	return true
 }
@@ -792,7 +789,7 @@
 func findpre(r *gc.Flow, v *obj.Addr) *gc.Flow {
 	var r1 *gc.Flow
 
-	for r1 = gc.Uniqp(r); r1 != nil; (func() { r = r1; r1 = gc.Uniqp(r) })() {
+	for r1 = gc.Uniqp(r); r1 != nil; r, r1 = r1, gc.Uniqp(r1) {
 		if gc.Uniqs(r1) != r {
 			return nil
 		}
@@ -818,7 +815,7 @@
 	var r1 *gc.Flow
 	var p *obj.Prog
 
-	for r1 = gc.Uniqs(r); r1 != nil && r1 != r2; (func() { r = r1; r1 = gc.Uniqs(r) })() {
+	for r1 = gc.Uniqs(r); r1 != nil && r1 != r2; r, r1 = r1, gc.Uniqs(r1) {
 		if gc.Uniqp(r1) != r {
 			return nil
 		}
@@ -1047,7 +1044,7 @@
 func copyu(p *obj.Prog, v *obj.Addr, s *obj.Addr) int {
 	switch p.As {
 	default:
-		fmt.Printf("copyu: can't find %v\n", arm.Aconv(int(p.As)))
+		fmt.Printf("copyu: can't find %v\n", obj.Aconv(int(p.As)))
 		return 2
 
 	case arm.AMOVM:
@@ -1333,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
 			}
 		}
@@ -1347,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/5g/prog.go b/src/cmd/5g/prog.go
index 3f7715f..bfb703e 100644
--- a/src/cmd/5g/prog.go
+++ b/src/cmd/5g/prog.go
@@ -5,10 +5,10 @@
 package main
 
 import (
+	"cmd/internal/gc"
 	"cmd/internal/obj"
 	"cmd/internal/obj/arm"
 )
-import "cmd/internal/gc"
 
 const (
 	RightRdwr = gc.RightRead | gc.RightWrite
@@ -23,117 +23,118 @@
 // size variants of an operation even if we just use a subset.
 //
 // The table is formatted for 8-space tabs.
-var progtable = [arm.ALAST]gc.ProgInfo{
-	obj.ATYPE:     gc.ProgInfo{gc.Pseudo | gc.Skip, 0, 0, 0},
-	obj.ATEXT:     gc.ProgInfo{gc.Pseudo, 0, 0, 0},
-	obj.AFUNCDATA: gc.ProgInfo{gc.Pseudo, 0, 0, 0},
-	obj.APCDATA:   gc.ProgInfo{gc.Pseudo, 0, 0, 0},
-	obj.AUNDEF:    gc.ProgInfo{gc.Break, 0, 0, 0},
-	obj.AUSEFIELD: gc.ProgInfo{gc.OK, 0, 0, 0},
-	obj.ACHECKNIL: gc.ProgInfo{gc.LeftRead, 0, 0, 0},
-	obj.AVARDEF:   gc.ProgInfo{gc.Pseudo | gc.RightWrite, 0, 0, 0},
-	obj.AVARKILL:  gc.ProgInfo{gc.Pseudo | gc.RightWrite, 0, 0, 0},
+var progtable = [arm.ALAST]obj.ProgInfo{
+	obj.ATYPE:     {gc.Pseudo | gc.Skip, 0, 0, 0},
+	obj.ATEXT:     {gc.Pseudo, 0, 0, 0},
+	obj.AFUNCDATA: {gc.Pseudo, 0, 0, 0},
+	obj.APCDATA:   {gc.Pseudo, 0, 0, 0},
+	obj.AUNDEF:    {gc.Break, 0, 0, 0},
+	obj.AUSEFIELD: {gc.OK, 0, 0, 0},
+	obj.ACHECKNIL: {gc.LeftRead, 0, 0, 0},
+	obj.AVARDEF:   {gc.Pseudo | gc.RightWrite, 0, 0, 0},
+	obj.AVARKILL:  {gc.Pseudo | gc.RightWrite, 0, 0, 0},
 
 	// NOP is an internal no-op that also stands
 	// for USED and SET annotations, not the Intel opcode.
-	obj.ANOP: gc.ProgInfo{gc.LeftRead | gc.RightWrite, 0, 0, 0},
+	obj.ANOP: {gc.LeftRead | gc.RightWrite, 0, 0, 0},
 
 	// Integer.
-	arm.AADC:    gc.ProgInfo{gc.SizeL | gc.LeftRead | gc.RegRead | gc.RightWrite, 0, 0, 0},
-	arm.AADD:    gc.ProgInfo{gc.SizeL | gc.LeftRead | gc.RegRead | gc.RightWrite, 0, 0, 0},
-	arm.AAND:    gc.ProgInfo{gc.SizeL | gc.LeftRead | gc.RegRead | gc.RightWrite, 0, 0, 0},
-	arm.ABIC:    gc.ProgInfo{gc.SizeL | gc.LeftRead | gc.RegRead | gc.RightWrite, 0, 0, 0},
-	arm.ACMN:    gc.ProgInfo{gc.SizeL | gc.LeftRead | gc.RightRead, 0, 0, 0},
-	arm.ACMP:    gc.ProgInfo{gc.SizeL | gc.LeftRead | gc.RightRead, 0, 0, 0},
-	arm.ADIVU:   gc.ProgInfo{gc.SizeL | gc.LeftRead | gc.RegRead | gc.RightWrite, 0, 0, 0},
-	arm.ADIV:    gc.ProgInfo{gc.SizeL | gc.LeftRead | gc.RegRead | gc.RightWrite, 0, 0, 0},
-	arm.AEOR:    gc.ProgInfo{gc.SizeL | gc.LeftRead | gc.RegRead | gc.RightWrite, 0, 0, 0},
-	arm.AMODU:   gc.ProgInfo{gc.SizeL | gc.LeftRead | gc.RegRead | gc.RightWrite, 0, 0, 0},
-	arm.AMOD:    gc.ProgInfo{gc.SizeL | gc.LeftRead | gc.RegRead | gc.RightWrite, 0, 0, 0},
-	arm.AMULALU: gc.ProgInfo{gc.SizeL | gc.LeftRead | gc.RegRead | RightRdwr, 0, 0, 0},
-	arm.AMULAL:  gc.ProgInfo{gc.SizeL | gc.LeftRead | gc.RegRead | RightRdwr, 0, 0, 0},
-	arm.AMULA:   gc.ProgInfo{gc.SizeL | gc.LeftRead | gc.RegRead | RightRdwr, 0, 0, 0},
-	arm.AMULU:   gc.ProgInfo{gc.SizeL | gc.LeftRead | gc.RegRead | gc.RightWrite, 0, 0, 0},
-	arm.AMUL:    gc.ProgInfo{gc.SizeL | gc.LeftRead | gc.RegRead | gc.RightWrite, 0, 0, 0},
-	arm.AMULL:   gc.ProgInfo{gc.SizeL | gc.LeftRead | gc.RegRead | gc.RightWrite, 0, 0, 0},
-	arm.AMULLU:  gc.ProgInfo{gc.SizeL | gc.LeftRead | gc.RegRead | gc.RightWrite, 0, 0, 0},
-	arm.AMVN:    gc.ProgInfo{gc.SizeL | gc.LeftRead | gc.RightWrite, 0, 0, 0},
-	arm.AORR:    gc.ProgInfo{gc.SizeL | gc.LeftRead | gc.RegRead | gc.RightWrite, 0, 0, 0},
-	arm.ARSB:    gc.ProgInfo{gc.SizeL | gc.LeftRead | gc.RegRead | gc.RightWrite, 0, 0, 0},
-	arm.ARSC:    gc.ProgInfo{gc.SizeL | gc.LeftRead | gc.RegRead | gc.RightWrite, 0, 0, 0},
-	arm.ASBC:    gc.ProgInfo{gc.SizeL | gc.LeftRead | gc.RegRead | gc.RightWrite, 0, 0, 0},
-	arm.ASLL:    gc.ProgInfo{gc.SizeL | gc.LeftRead | gc.RegRead | gc.RightWrite, 0, 0, 0},
-	arm.ASRA:    gc.ProgInfo{gc.SizeL | gc.LeftRead | gc.RegRead | gc.RightWrite, 0, 0, 0},
-	arm.ASRL:    gc.ProgInfo{gc.SizeL | gc.LeftRead | gc.RegRead | gc.RightWrite, 0, 0, 0},
-	arm.ASUB:    gc.ProgInfo{gc.SizeL | gc.LeftRead | gc.RegRead | gc.RightWrite, 0, 0, 0},
-	arm.ATEQ:    gc.ProgInfo{gc.SizeL | gc.LeftRead | gc.RightRead, 0, 0, 0},
-	arm.ATST:    gc.ProgInfo{gc.SizeL | gc.LeftRead | gc.RightRead, 0, 0, 0},
+	arm.AADC:    {gc.SizeL | gc.LeftRead | gc.RegRead | gc.RightWrite, 0, 0, 0},
+	arm.AADD:    {gc.SizeL | gc.LeftRead | gc.RegRead | gc.RightWrite, 0, 0, 0},
+	arm.AAND:    {gc.SizeL | gc.LeftRead | gc.RegRead | gc.RightWrite, 0, 0, 0},
+	arm.ABIC:    {gc.SizeL | gc.LeftRead | gc.RegRead | gc.RightWrite, 0, 0, 0},
+	arm.ACMN:    {gc.SizeL | gc.LeftRead | gc.RightRead, 0, 0, 0},
+	arm.ACMP:    {gc.SizeL | gc.LeftRead | gc.RightRead, 0, 0, 0},
+	arm.ADIVU:   {gc.SizeL | gc.LeftRead | gc.RegRead | gc.RightWrite, 0, 0, 0},
+	arm.ADIV:    {gc.SizeL | gc.LeftRead | gc.RegRead | gc.RightWrite, 0, 0, 0},
+	arm.AEOR:    {gc.SizeL | gc.LeftRead | gc.RegRead | gc.RightWrite, 0, 0, 0},
+	arm.AMODU:   {gc.SizeL | gc.LeftRead | gc.RegRead | gc.RightWrite, 0, 0, 0},
+	arm.AMOD:    {gc.SizeL | gc.LeftRead | gc.RegRead | gc.RightWrite, 0, 0, 0},
+	arm.AMULALU: {gc.SizeL | gc.LeftRead | gc.RegRead | RightRdwr, 0, 0, 0},
+	arm.AMULAL:  {gc.SizeL | gc.LeftRead | gc.RegRead | RightRdwr, 0, 0, 0},
+	arm.AMULA:   {gc.SizeL | gc.LeftRead | gc.RegRead | RightRdwr, 0, 0, 0},
+	arm.AMULU:   {gc.SizeL | gc.LeftRead | gc.RegRead | gc.RightWrite, 0, 0, 0},
+	arm.AMUL:    {gc.SizeL | gc.LeftRead | gc.RegRead | gc.RightWrite, 0, 0, 0},
+	arm.AMULL:   {gc.SizeL | gc.LeftRead | gc.RegRead | gc.RightWrite, 0, 0, 0},
+	arm.AMULLU:  {gc.SizeL | gc.LeftRead | gc.RegRead | gc.RightWrite, 0, 0, 0},
+	arm.AMVN:    {gc.SizeL | gc.LeftRead | gc.RightWrite, 0, 0, 0},
+	arm.AORR:    {gc.SizeL | gc.LeftRead | gc.RegRead | gc.RightWrite, 0, 0, 0},
+	arm.ARSB:    {gc.SizeL | gc.LeftRead | gc.RegRead | gc.RightWrite, 0, 0, 0},
+	arm.ARSC:    {gc.SizeL | gc.LeftRead | gc.RegRead | gc.RightWrite, 0, 0, 0},
+	arm.ASBC:    {gc.SizeL | gc.LeftRead | gc.RegRead | gc.RightWrite, 0, 0, 0},
+	arm.ASLL:    {gc.SizeL | gc.LeftRead | gc.RegRead | gc.RightWrite, 0, 0, 0},
+	arm.ASRA:    {gc.SizeL | gc.LeftRead | gc.RegRead | gc.RightWrite, 0, 0, 0},
+	arm.ASRL:    {gc.SizeL | gc.LeftRead | gc.RegRead | gc.RightWrite, 0, 0, 0},
+	arm.ASUB:    {gc.SizeL | gc.LeftRead | gc.RegRead | gc.RightWrite, 0, 0, 0},
+	arm.ATEQ:    {gc.SizeL | gc.LeftRead | gc.RightRead, 0, 0, 0},
+	arm.ATST:    {gc.SizeL | gc.LeftRead | gc.RightRead, 0, 0, 0},
 
 	// Floating point.
-	arm.AADDD: gc.ProgInfo{gc.SizeD | gc.LeftRead | RightRdwr, 0, 0, 0},
-	arm.AADDF: gc.ProgInfo{gc.SizeF | gc.LeftRead | RightRdwr, 0, 0, 0},
-	arm.ACMPD: gc.ProgInfo{gc.SizeD | gc.LeftRead | gc.RightRead, 0, 0, 0},
-	arm.ACMPF: gc.ProgInfo{gc.SizeF | gc.LeftRead | gc.RightRead, 0, 0, 0},
-	arm.ADIVD: gc.ProgInfo{gc.SizeD | gc.LeftRead | RightRdwr, 0, 0, 0},
-	arm.ADIVF: gc.ProgInfo{gc.SizeF | gc.LeftRead | RightRdwr, 0, 0, 0},
-	arm.AMULD: gc.ProgInfo{gc.SizeD | gc.LeftRead | RightRdwr, 0, 0, 0},
-	arm.AMULF: gc.ProgInfo{gc.SizeF | gc.LeftRead | RightRdwr, 0, 0, 0},
-	arm.ASUBD: gc.ProgInfo{gc.SizeD | gc.LeftRead | RightRdwr, 0, 0, 0},
-	arm.ASUBF: gc.ProgInfo{gc.SizeF | gc.LeftRead | RightRdwr, 0, 0, 0},
+	arm.AADDD: {gc.SizeD | gc.LeftRead | RightRdwr, 0, 0, 0},
+	arm.AADDF: {gc.SizeF | gc.LeftRead | RightRdwr, 0, 0, 0},
+	arm.ACMPD: {gc.SizeD | gc.LeftRead | gc.RightRead, 0, 0, 0},
+	arm.ACMPF: {gc.SizeF | gc.LeftRead | gc.RightRead, 0, 0, 0},
+	arm.ADIVD: {gc.SizeD | gc.LeftRead | RightRdwr, 0, 0, 0},
+	arm.ADIVF: {gc.SizeF | gc.LeftRead | RightRdwr, 0, 0, 0},
+	arm.AMULD: {gc.SizeD | gc.LeftRead | RightRdwr, 0, 0, 0},
+	arm.AMULF: {gc.SizeF | gc.LeftRead | RightRdwr, 0, 0, 0},
+	arm.ASUBD: {gc.SizeD | gc.LeftRead | RightRdwr, 0, 0, 0},
+	arm.ASUBF: {gc.SizeF | gc.LeftRead | RightRdwr, 0, 0, 0},
 
 	// Conversions.
-	arm.AMOVWD: gc.ProgInfo{gc.SizeD | gc.LeftRead | gc.RightWrite | gc.Conv, 0, 0, 0},
-	arm.AMOVWF: gc.ProgInfo{gc.SizeF | gc.LeftRead | gc.RightWrite | gc.Conv, 0, 0, 0},
-	arm.AMOVDF: gc.ProgInfo{gc.SizeF | gc.LeftRead | gc.RightWrite | gc.Conv, 0, 0, 0},
-	arm.AMOVDW: gc.ProgInfo{gc.SizeL | gc.LeftRead | gc.RightWrite | gc.Conv, 0, 0, 0},
-	arm.AMOVFD: gc.ProgInfo{gc.SizeD | gc.LeftRead | gc.RightWrite | gc.Conv, 0, 0, 0},
-	arm.AMOVFW: gc.ProgInfo{gc.SizeL | gc.LeftRead | gc.RightWrite | gc.Conv, 0, 0, 0},
+	arm.AMOVWD: {gc.SizeD | gc.LeftRead | gc.RightWrite | gc.Conv, 0, 0, 0},
+	arm.AMOVWF: {gc.SizeF | gc.LeftRead | gc.RightWrite | gc.Conv, 0, 0, 0},
+	arm.AMOVDF: {gc.SizeF | gc.LeftRead | gc.RightWrite | gc.Conv, 0, 0, 0},
+	arm.AMOVDW: {gc.SizeL | gc.LeftRead | gc.RightWrite | gc.Conv, 0, 0, 0},
+	arm.AMOVFD: {gc.SizeD | gc.LeftRead | gc.RightWrite | gc.Conv, 0, 0, 0},
+	arm.AMOVFW: {gc.SizeL | gc.LeftRead | gc.RightWrite | gc.Conv, 0, 0, 0},
 
 	// Moves.
-	arm.AMOVB: gc.ProgInfo{gc.SizeB | gc.LeftRead | gc.RightWrite | gc.Move, 0, 0, 0},
-	arm.AMOVD: gc.ProgInfo{gc.SizeD | gc.LeftRead | gc.RightWrite | gc.Move, 0, 0, 0},
-	arm.AMOVF: gc.ProgInfo{gc.SizeF | gc.LeftRead | gc.RightWrite | gc.Move, 0, 0, 0},
-	arm.AMOVH: gc.ProgInfo{gc.SizeW | gc.LeftRead | gc.RightWrite | gc.Move, 0, 0, 0},
-	arm.AMOVW: gc.ProgInfo{gc.SizeL | gc.LeftRead | gc.RightWrite | gc.Move, 0, 0, 0},
+	arm.AMOVB: {gc.SizeB | gc.LeftRead | gc.RightWrite | gc.Move, 0, 0, 0},
+	arm.AMOVD: {gc.SizeD | gc.LeftRead | gc.RightWrite | gc.Move, 0, 0, 0},
+	arm.AMOVF: {gc.SizeF | gc.LeftRead | gc.RightWrite | gc.Move, 0, 0, 0},
+	arm.AMOVH: {gc.SizeW | gc.LeftRead | gc.RightWrite | gc.Move, 0, 0, 0},
+	arm.AMOVW: {gc.SizeL | gc.LeftRead | gc.RightWrite | gc.Move, 0, 0, 0},
 
 	// In addtion, duffzero reads R0,R1 and writes R1.  This fact is
 	// encoded in peep.c
-	obj.ADUFFZERO: gc.ProgInfo{gc.Call, 0, 0, 0},
+	obj.ADUFFZERO: {gc.Call, 0, 0, 0},
 
 	// In addtion, duffcopy reads R1,R2 and writes R0,R1,R2.  This fact is
 	// encoded in peep.c
-	obj.ADUFFCOPY: gc.ProgInfo{gc.Call, 0, 0, 0},
+	obj.ADUFFCOPY: {gc.Call, 0, 0, 0},
 
 	// These should be split into the two different conversions instead
 	// of overloading the one.
-	arm.AMOVBS: gc.ProgInfo{gc.SizeB | gc.LeftRead | gc.RightWrite | gc.Conv, 0, 0, 0},
-	arm.AMOVBU: gc.ProgInfo{gc.SizeB | gc.LeftRead | gc.RightWrite | gc.Conv, 0, 0, 0},
-	arm.AMOVHS: gc.ProgInfo{gc.SizeW | gc.LeftRead | gc.RightWrite | gc.Conv, 0, 0, 0},
-	arm.AMOVHU: gc.ProgInfo{gc.SizeW | gc.LeftRead | gc.RightWrite | gc.Conv, 0, 0, 0},
+	arm.AMOVBS: {gc.SizeB | gc.LeftRead | gc.RightWrite | gc.Conv, 0, 0, 0},
+	arm.AMOVBU: {gc.SizeB | gc.LeftRead | gc.RightWrite | gc.Conv, 0, 0, 0},
+	arm.AMOVHS: {gc.SizeW | gc.LeftRead | gc.RightWrite | gc.Conv, 0, 0, 0},
+	arm.AMOVHU: {gc.SizeW | gc.LeftRead | gc.RightWrite | gc.Conv, 0, 0, 0},
 
 	// Jumps.
-	arm.AB:   gc.ProgInfo{gc.Jump | gc.Break, 0, 0, 0},
-	arm.ABL:  gc.ProgInfo{gc.Call, 0, 0, 0},
-	arm.ABEQ: gc.ProgInfo{gc.Cjmp, 0, 0, 0},
-	arm.ABNE: gc.ProgInfo{gc.Cjmp, 0, 0, 0},
-	arm.ABCS: gc.ProgInfo{gc.Cjmp, 0, 0, 0},
-	arm.ABHS: gc.ProgInfo{gc.Cjmp, 0, 0, 0},
-	arm.ABCC: gc.ProgInfo{gc.Cjmp, 0, 0, 0},
-	arm.ABLO: gc.ProgInfo{gc.Cjmp, 0, 0, 0},
-	arm.ABMI: gc.ProgInfo{gc.Cjmp, 0, 0, 0},
-	arm.ABPL: gc.ProgInfo{gc.Cjmp, 0, 0, 0},
-	arm.ABVS: gc.ProgInfo{gc.Cjmp, 0, 0, 0},
-	arm.ABVC: gc.ProgInfo{gc.Cjmp, 0, 0, 0},
-	arm.ABHI: gc.ProgInfo{gc.Cjmp, 0, 0, 0},
-	arm.ABLS: gc.ProgInfo{gc.Cjmp, 0, 0, 0},
-	arm.ABGE: gc.ProgInfo{gc.Cjmp, 0, 0, 0},
-	arm.ABLT: gc.ProgInfo{gc.Cjmp, 0, 0, 0},
-	arm.ABGT: gc.ProgInfo{gc.Cjmp, 0, 0, 0},
-	arm.ABLE: gc.ProgInfo{gc.Cjmp, 0, 0, 0},
-	obj.ARET: gc.ProgInfo{gc.Break, 0, 0, 0},
+	arm.AB:   {gc.Jump | gc.Break, 0, 0, 0},
+	arm.ABL:  {gc.Call, 0, 0, 0},
+	arm.ABEQ: {gc.Cjmp, 0, 0, 0},
+	arm.ABNE: {gc.Cjmp, 0, 0, 0},
+	arm.ABCS: {gc.Cjmp, 0, 0, 0},
+	arm.ABHS: {gc.Cjmp, 0, 0, 0},
+	arm.ABCC: {gc.Cjmp, 0, 0, 0},
+	arm.ABLO: {gc.Cjmp, 0, 0, 0},
+	arm.ABMI: {gc.Cjmp, 0, 0, 0},
+	arm.ABPL: {gc.Cjmp, 0, 0, 0},
+	arm.ABVS: {gc.Cjmp, 0, 0, 0},
+	arm.ABVC: {gc.Cjmp, 0, 0, 0},
+	arm.ABHI: {gc.Cjmp, 0, 0, 0},
+	arm.ABLS: {gc.Cjmp, 0, 0, 0},
+	arm.ABGE: {gc.Cjmp, 0, 0, 0},
+	arm.ABLT: {gc.Cjmp, 0, 0, 0},
+	arm.ABGT: {gc.Cjmp, 0, 0, 0},
+	arm.ABLE: {gc.Cjmp, 0, 0, 0},
+	obj.ARET: {gc.Break, 0, 0, 0},
 }
 
-func proginfo(info *gc.ProgInfo, p *obj.Prog) {
+func proginfo(p *obj.Prog) {
+	info := &p.Info
 	*info = progtable[p.As]
 	if info.Flags == 0 {
 		gc.Fatal("unknown instruction %v", p)
diff --git a/src/cmd/5l/asm.go b/src/cmd/5l/asm.go
index 909f682..525764e 100644
--- a/src/cmd/5l/asm.go
+++ b/src/cmd/5l/asm.go
@@ -31,24 +31,21 @@
 package main
 
 import (
+	"cmd/internal/ld"
 	"cmd/internal/obj"
 	"fmt"
 	"log"
 )
-import "cmd/internal/ld"
 
 func needlib(name string) int {
-	var p string
-	var s *ld.LSym
-
 	if name[0] == '\x00' {
 		return 0
 	}
 
 	/* reuse hash code in symbol table */
-	p = fmt.Sprintf(".dynlib.%s", name)
+	p := fmt.Sprintf(".dynlib.%s", name)
 
-	s = ld.Linklookup(ld.Ctxt, p, 0)
+	s := ld.Linklookup(ld.Ctxt, p, 0)
 
 	if s.Type == 0 {
 		s.Type = 100 // avoid SDATA, etc.
@@ -73,10 +70,7 @@
 }
 
 func adddynrel(s *ld.LSym, r *ld.Reloc) {
-	var targ *ld.LSym
-	var rel *ld.LSym
-
-	targ = r.Sym
+	targ := r.Sym
 	ld.Ctxt.Cursym = s
 
 	switch r.Type {
@@ -203,7 +197,7 @@
 		}
 		if ld.Iself {
 			adddynsym(ld.Ctxt, targ)
-			rel = ld.Linklookup(ld.Ctxt, ".rel", 0)
+			rel := ld.Linklookup(ld.Ctxt, ".rel", 0)
 			ld.Addaddrplus(ld.Ctxt, rel, s, int64(r.Off))
 			ld.Adduint32(ld.Ctxt, rel, ld.ELF32_R_INFO(uint32(targ.Dynid), ld.R_ARM_GLOB_DAT)) // we need a nil + A dynmic reloc
 			r.Type = ld.R_CONST                                                                // write r->add during relocsym
@@ -217,11 +211,9 @@
 }
 
 func elfreloc1(r *ld.Reloc, sectoff int64) int {
-	var elfsym int32
-
 	ld.Thearch.Lput(uint32(sectoff))
 
-	elfsym = r.Xsym.Elfsym
+	elfsym := r.Xsym.Elfsym
 	switch r.Type {
 	default:
 		return -1
@@ -267,11 +259,8 @@
 }
 
 func elfsetupplt() {
-	var plt *ld.LSym
-	var got *ld.LSym
-
-	plt = ld.Linklookup(ld.Ctxt, ".plt", 0)
-	got = ld.Linklookup(ld.Ctxt, ".got.plt", 0)
+	plt := ld.Linklookup(ld.Ctxt, ".plt", 0)
+	got := ld.Linklookup(ld.Ctxt, ".got.plt", 0)
 	if plt.Size == 0 {
 		// str lr, [sp, #-4]!
 		ld.Adduint32(ld.Ctxt, plt, 0xe52de004)
@@ -298,9 +287,8 @@
 
 func machoreloc1(r *ld.Reloc, sectoff int64) int {
 	var v uint32
-	var rs *ld.LSym
 
-	rs = r.Xsym
+	rs := r.Xsym
 
 	if rs.Type == ld.SHOSTOBJ || r.Type == ld.R_CALLARM {
 		if rs.Dynid < 0 {
@@ -353,15 +341,13 @@
 }
 
 func archreloc(r *ld.Reloc, s *ld.LSym, val *int64) int {
-	var rs *ld.LSym
-
 	if ld.Linkmode == ld.LinkExternal {
 		switch r.Type {
 		case ld.R_CALLARM:
 			r.Done = 0
 
 			// set up addend for eventual relocation via outer symbol.
-			rs = r.Sym
+			rs := r.Sym
 
 			r.Xadd = r.Add
 			if r.Xadd&0x800000 != 0 {
@@ -437,9 +423,7 @@
 }
 
 func addpltreloc(ctxt *ld.Link, plt *ld.LSym, got *ld.LSym, sym *ld.LSym, typ int) *ld.Reloc {
-	var r *ld.Reloc
-
-	r = ld.Addrel(plt)
+	r := ld.Addrel(plt)
 	r.Sym = got
 	r.Off = int32(plt.Size)
 	r.Siz = 4
@@ -454,10 +438,6 @@
 }
 
 func addpltsym(ctxt *ld.Link, s *ld.LSym) {
-	var plt *ld.LSym
-	var got *ld.LSym
-	var rel *ld.LSym
-
 	if s.Plt >= 0 {
 		return
 	}
@@ -465,9 +445,9 @@
 	adddynsym(ctxt, s)
 
 	if ld.Iself {
-		plt = ld.Linklookup(ctxt, ".plt", 0)
-		got = ld.Linklookup(ctxt, ".got.plt", 0)
-		rel = ld.Linklookup(ctxt, ".rel.plt", 0)
+		plt := ld.Linklookup(ctxt, ".plt", 0)
+		got := ld.Linklookup(ctxt, ".got.plt", 0)
+		rel := ld.Linklookup(ctxt, ".rel.plt", 0)
 		if plt.Size == 0 {
 			elfsetupplt()
 		}
@@ -497,13 +477,11 @@
 }
 
 func addgotsyminternal(ctxt *ld.Link, s *ld.LSym) {
-	var got *ld.LSym
-
 	if s.Got >= 0 {
 		return
 	}
 
-	got = ld.Linklookup(ctxt, ".got", 0)
+	got := ld.Linklookup(ctxt, ".got", 0)
 	s.Got = int32(got.Size)
 
 	ld.Addaddrplus(ctxt, got, s, 0)
@@ -515,20 +493,17 @@
 }
 
 func addgotsym(ctxt *ld.Link, s *ld.LSym) {
-	var got *ld.LSym
-	var rel *ld.LSym
-
 	if s.Got >= 0 {
 		return
 	}
 
 	adddynsym(ctxt, s)
-	got = ld.Linklookup(ctxt, ".got", 0)
+	got := ld.Linklookup(ctxt, ".got", 0)
 	s.Got = int32(got.Size)
 	ld.Adduint32(ctxt, got, 0)
 
 	if ld.Iself {
-		rel = ld.Linklookup(ctxt, ".rel", 0)
+		rel := ld.Linklookup(ctxt, ".rel", 0)
 		ld.Addaddrplus(ctxt, rel, got, int64(s.Got))
 		ld.Adduint32(ctxt, rel, ld.ELF32_R_INFO(uint32(s.Dynid), ld.R_ARM_GLOB_DAT))
 	} else {
@@ -537,10 +512,6 @@
 }
 
 func adddynsym(ctxt *ld.Link, s *ld.LSym) {
-	var d *ld.LSym
-	var t int
-	var name string
-
 	if s.Dynid >= 0 {
 		return
 	}
@@ -549,10 +520,10 @@
 		s.Dynid = int32(ld.Nelfsym)
 		ld.Nelfsym++
 
-		d = ld.Linklookup(ctxt, ".dynsym", 0)
+		d := ld.Linklookup(ctxt, ".dynsym", 0)
 
 		/* name */
-		name = s.Extname
+		name := s.Extname
 
 		ld.Adduint32(ctxt, d, uint32(ld.Addstring(ld.Linklookup(ctxt, ".dynstr", 0), name)))
 
@@ -567,7 +538,7 @@
 		ld.Adduint32(ctxt, d, 0)
 
 		/* type */
-		t = ld.STB_GLOBAL << 4
+		t := ld.STB_GLOBAL << 4
 
 		if (s.Cgoexport&ld.CgoExportDynamic != 0) && s.Type&ld.SMASK == ld.STEXT {
 			t |= ld.STT_FUNC
@@ -589,14 +560,12 @@
 }
 
 func adddynlib(lib string) {
-	var s *ld.LSym
-
 	if needlib(lib) == 0 {
 		return
 	}
 
 	if ld.Iself {
-		s = ld.Linklookup(ld.Ctxt, ".dynstr", 0)
+		s := ld.Linklookup(ld.Ctxt, ".dynstr", 0)
 		if s.Size == 0 {
 			ld.Addstring(s, "")
 		}
@@ -609,13 +578,6 @@
 }
 
 func asmb() {
-	var symo uint32
-	var dwarfoff uint32
-	var machlink uint32
-	var sect *ld.Section
-	var sym *ld.LSym
-	var i int
-
 	if ld.Debug['v'] != 0 {
 		fmt.Fprintf(&ld.Bso, "%5.2f asmb\n", obj.Cputime())
 	}
@@ -625,7 +587,7 @@
 		ld.Asmbelfsetup()
 	}
 
-	sect = ld.Segtext.Sect
+	sect := ld.Segtext.Sect
 	ld.Cseek(int64(sect.Vaddr - ld.Segtext.Vaddr + ld.Segtext.Fileoff))
 	ld.Codeblk(int64(sect.Vaddr), int64(sect.Length))
 	for sect = sect.Next; sect != nil; sect = sect.Next {
@@ -651,14 +613,14 @@
 	ld.Cseek(int64(ld.Segdata.Fileoff))
 	ld.Datblk(int64(ld.Segdata.Vaddr), int64(ld.Segdata.Filelen))
 
-	machlink = 0
+	machlink := uint32(0)
 	if ld.HEADTYPE == ld.Hdarwin {
 		if ld.Debug['v'] != 0 {
 			fmt.Fprintf(&ld.Bso, "%5.2f dwarf\n", obj.Cputime())
 		}
 
-		if ld.Debug['w'] == 0 {
-			dwarfoff = uint32(ld.Rnd(int64(uint64(ld.HEADR)+ld.Segtext.Length), int64(ld.INITRND)) + ld.Rnd(int64(ld.Segdata.Filelen), int64(ld.INITRND)))
+		if ld.Debug['w'] == 0 { // TODO(minux): enable DWARF Support
+			dwarfoff := uint32(ld.Rnd(int64(uint64(ld.HEADR)+ld.Segtext.Length), int64(ld.INITRND)) + ld.Rnd(int64(ld.Segdata.Filelen), int64(ld.INITRND)))
 			ld.Cseek(int64(dwarfoff))
 
 			ld.Segdwarf.Fileoff = uint64(ld.Cpos())
@@ -673,7 +635,7 @@
 	ld.Symsize = 0
 
 	ld.Lcsize = 0
-	symo = 0
+	symo := uint32(0)
 	if ld.Debug['s'] == 0 {
 		// TODO: rationalize
 		if ld.Debug['v'] != 0 {
@@ -719,10 +681,10 @@
 			ld.Asmplan9sym()
 			ld.Cflush()
 
-			sym = ld.Linklookup(ld.Ctxt, "pclntab", 0)
+			sym := ld.Linklookup(ld.Ctxt, "pclntab", 0)
 			if sym != nil {
 				ld.Lcsize = int32(len(sym.P))
-				for i = 0; int32(i) < ld.Lcsize; i++ {
+				for i := 0; int32(i) < ld.Lcsize; i++ {
 					ld.Cput(uint8(sym.P[i]))
 				}
 
diff --git a/src/cmd/5l/l.go b/src/cmd/5l/l.go
index 9eb078d..a521545 100644
--- a/src/cmd/5l/l.go
+++ b/src/cmd/5l/l.go
@@ -67,8 +67,8 @@
 	PtrSize   = 4
 	IntSize   = 4
 	RegSize   = 4
-	MaxAlign  = 8
-	FuncAlign = 4
+	MaxAlign  = 8 // max data alignment
+	FuncAlign = 4 // single-instruction alignment
 	MINLC     = 4
 )
 
diff --git a/src/cmd/5l/obj.go b/src/cmd/5l/obj.go
index 98ebbc2..075f15f 100644
--- a/src/cmd/5l/obj.go
+++ b/src/cmd/5l/obj.go
@@ -31,11 +31,11 @@
 package main
 
 import (
+	"cmd/internal/ld"
 	"cmd/internal/obj"
 	"fmt"
 	"log"
 )
-import "cmd/internal/ld"
 
 // Reading object files.
 
@@ -74,15 +74,13 @@
 
 	ld.Thearch.Linuxdynld = "/lib/ld-linux.so.3" // 2 for OABI, 3 for EABI
 	ld.Thearch.Freebsddynld = "/usr/libexec/ld-elf.so.1"
-	ld.Thearch.Openbsddynld = "XXX"
+	ld.Thearch.Openbsddynld = "/usr/libexec/ld.so"
 	ld.Thearch.Netbsddynld = "/libexec/ld.elf_so"
 	ld.Thearch.Dragonflydynld = "XXX"
 	ld.Thearch.Solarisdynld = "XXX"
 }
 
 func archinit() {
-	var s *ld.LSym
-
 	// getgoextlinkenabled is based on GO_EXTLINK_ENABLED when
 	// Go was built; see ../../make.bash.
 	if ld.Linkmode == ld.LinkAuto && obj.Getgoextlinkenabled() == "0" {
@@ -126,7 +124,8 @@
 
 	case ld.Hlinux, /* arm elf */
 		ld.Hfreebsd,
-		ld.Hnetbsd:
+		ld.Hnetbsd,
+		ld.Hopenbsd:
 		ld.Debug['d'] = 0
 		// with dynamic linking
 		ld.Elfinit()
@@ -175,7 +174,7 @@
 	}
 
 	// embed goarm to runtime.goarm
-	s = ld.Linklookup(ld.Ctxt, "runtime.goarm", 0)
+	s := ld.Linklookup(ld.Ctxt, "runtime.goarm", 0)
 
 	s.Type = ld.SRODATA
 	ld.Adduint8(ld.Ctxt, s, uint8(ld.Ctxt.Goarm))
diff --git a/src/cmd/6g/cgen.go b/src/cmd/6g/cgen.go
index cb16039..41ed363 100644
--- a/src/cmd/6g/cgen.go
+++ b/src/cmd/6g/cgen.go
@@ -5,1489 +5,12 @@
 package main
 
 import (
+	"cmd/internal/gc"
 	"cmd/internal/obj"
 	"cmd/internal/obj/x86"
-	"fmt"
 )
-import "cmd/internal/gc"
 
-/*
- * 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)
-	}
-
-	var nl *gc.Node
-	var n1 gc.Node
-	var nr *gc.Node
-	var n2 gc.Node
-	var a int
-	if n == nil || n.Type == nil {
-		goto ret
-	}
-
-	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)
-		}
-		goto ret
-
-	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)
-		}
-		goto ret
-	}
-
-	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)
-			goto ret
-		}
-	}
-
-	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)
-		goto ret
-	}
-
-	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)
-			goto ret
-		}
-
-		var f int
-		if res.Ullman >= gc.UINF {
-			goto gen
-		}
-
-		if gc.Complexop(n, res) {
-			gc.Complexgen(n, res)
-			goto ret
-		}
-
-		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] == 0 {
-			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()
-				goto ret
-			}
-		}
-
-	gen:
-		var n1 gc.Node
-		igen(res, &n1, nil)
-		cgen(n, &n1)
-		regfree(&n1)
-		goto ret
-	}
-
-	// 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)
-		goto ret
-	}
-
-	if n.Addable != 0 {
-		gmove(n, res)
-		goto ret
-	}
-
-	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)
-			goto ret
-		}
-	}
-
-	if gc.Iscomplex[n.Type.Etype] == 0 {
-		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()
-			goto ret
-		}
-	}
-
-	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)
-		goto ret
-
-	case gc.OPLUS:
-		cgen(nl, res)
-		goto ret
-
-		// 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)
-		goto ret
-
-	case gc.OMINUS:
-		if gc.Isfloat[nl.Type.Etype] != 0 {
-			nr = gc.Nodintconst(-1)
-			gc.Convlit(&nr, n.Type)
-			a = optoas(gc.OMUL, nl.Type)
-			goto sbop
-		}
-
-		a = optoas(int(n.Op), nl.Type)
-		goto uop
-
-		// 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)
-				goto ret
-			}
-		}
-
-		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.S, &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] != 0 {
-			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)
-	}
-
-	goto ret
-
-	/*
-	 * 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
-	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)
-	}
-	goto ret
-
-uop: // unary
-	regalloc(&n1, nl.Type, res)
-
-	cgen(nl, &n1)
-	gins(a, nil, &n1)
-	gmove(&n1, res)
-	regfree(&n1)
-	goto ret
-
-ret:
-}
-
-/*
- * 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] != 0 {
-			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.S)))
-			} 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.S, &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
-	}
-
-	var nl *gc.Node
-	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)
-		goto ret
-	}
-
-	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)
-		goto ret
-	}
-
-	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)
-		}
-	}
-
-ret:
-}
-
-/*
- * 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] != 0 && gc.Isfixedarray(n.Left.Left.Type)) {
-			if gc.Isconst(n.Right, gc.CTINT) {
-				// Compute &a.
-				if gc.Isptr[n.Left.Type.Etype] == 0 {
-					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)
-	}
-
-	var a int
-	var et int
-	var nl *gc.Node
-	var n1 gc.Node
-	var nr *gc.Node
-	var n2 gc.Node
-	if n.Type == nil {
-		gc.Convlit(&n, gc.Types[gc.TBOOL])
-		if n.Type == nil {
-			goto ret
-		}
-	}
-
-	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)
-		goto ret
-	}
-
-	nr = nil
-
-	for n.Op == gc.OCONVNOP {
-		n = n.Left
-		if n.Ninit != nil {
-			gc.Genlist(n.Ninit)
-		}
-	}
-
-	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)
-		}
-		goto ret
-
-	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)
-		goto ret
-
-	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)
-		}
-
-		goto ret
-
-	case gc.OEQ,
-		gc.ONE,
-		gc.OLT,
-		gc.OGT,
-		gc.OLE,
-		gc.OGE:
-		nr = n.Right
-		if nr == nil || nr.Type == nil {
-			goto ret
-		}
-		fallthrough
-
-	case gc.ONOT: // unary
-		nl = n.Left
-
-		if nl == nil || nl.Type == nil {
-			goto ret
-		}
-	}
-
-	switch n.Op {
-	case gc.ONOT:
-		bgen(nl, !true_, likely, to)
-		goto ret
-
-	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] != 0 {
-				// 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)
-				goto ret
-			}
-
-			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] != 0 {
-			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] != 0 && (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] != 0 && (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)
-	}
-
-	goto ret
-
-def:
-	regalloc(&n1, n.Type, nil)
-	cgen(n, &n1)
-	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)
-	goto ret
-
-ret:
-}
-
-/*
- * 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] != 0 {
-			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] != 0 {
-			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 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
@@ -1496,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 {
@@ -1515,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
@@ -1626,268 +149,3 @@
 
 	restx(&cx, &oldcx)
 }
-
-func cadable(n *gc.Node) bool {
-	if n.Addable == 0 {
-		// dont know how it happens,
-		// but it does
-		return false
-	}
-
-	switch n.Op {
-	case gc.ONAME:
-		return true
-	}
-
-	return false
-}
-
-/*
- * copy a composite value by moving its individual components.
- * Slices, strings and interfaces are supported.
- * Small structs or arrays with elements of basic type are
- * also supported.
- * nr is N when assigning a zero value.
- * return 1 if can do, 0 if can't.
- */
-func componentgen(nr *gc.Node, nl *gc.Node) bool {
-	var nodl gc.Node
-	var nodr gc.Node
-
-	freel := 0
-	freer := 0
-
-	switch nl.Type.Etype {
-	default:
-		goto no
-
-	case gc.TARRAY:
-		t := nl.Type
-
-		// Slices are ok.
-		if gc.Isslice(t) {
-			break
-		}
-
-		// Small arrays are ok.
-		if t.Bound > 0 && t.Bound <= 3 && !gc.Isfat(t.Type) {
-			break
-		}
-
-		goto no
-
-		// Small structs with non-fat types are ok.
-	// Zero-sized structs are treated separately elsewhere.
-	case gc.TSTRUCT:
-		fldcount := int64(0)
-
-		for t := nl.Type.Type; t != nil; t = t.Down {
-			if gc.Isfat(t.Type) {
-				goto no
-			}
-			if t.Etype != gc.TFIELD {
-				gc.Fatal("componentgen: not a TFIELD: %v", gc.Tconv(t, obj.FmtLong))
-			}
-			fldcount++
-		}
-
-		if fldcount == 0 || fldcount > 4 {
-			goto no
-		}
-
-	case gc.TSTRING,
-		gc.TINTER:
-		break
-	}
-
-	nodl = *nl
-	if !cadable(nl) {
-		if nr != nil && !cadable(nr) {
-			goto no
-		}
-		igen(nl, &nodl, nil)
-		freel = 1
-	}
-
-	if nr != nil {
-		nodr = *nr
-		if !cadable(nr) {
-			igen(nr, &nodr, nil)
-			freer = 1
-		}
-	} else {
-		// When zeroing, prepare a register containing zero.
-		var tmp gc.Node
-		gc.Nodconst(&tmp, nl.Type, 0)
-
-		regalloc(&nodr, gc.Types[gc.TUINT], nil)
-		gmove(&tmp, &nodr)
-		freer = 1
-	}
-
-	// nl and nr are 'cadable' which basically means they are names (variables) now.
-	// If they are the same variable, don't generate any code, because the
-	// VARDEF we generate will mark the old value as dead incorrectly.
-	// (And also the assignments are useless.)
-	if nr != nil && nl.Op == gc.ONAME && nr.Op == gc.ONAME && nl == nr {
-		goto yes
-	}
-
-	switch nl.Type.Etype {
-	// componentgen for arrays.
-	case gc.TARRAY:
-		if nl.Op == gc.ONAME {
-			gc.Gvardef(nl)
-		}
-		t := nl.Type
-		if !gc.Isslice(t) {
-			nodl.Type = t.Type
-			nodr.Type = nodl.Type
-			for fldcount := int64(0); fldcount < t.Bound; fldcount++ {
-				if nr == nil {
-					gc.Clearslim(&nodl)
-				} else {
-					gmove(&nodr, &nodl)
-				}
-				nodl.Xoffset += t.Type.Width
-				nodr.Xoffset += t.Type.Width
-			}
-
-			goto yes
-		}
-
-		// componentgen for slices.
-		nodl.Xoffset += int64(gc.Array_array)
-
-		nodl.Type = gc.Ptrto(nl.Type.Type)
-
-		if nr != nil {
-			nodr.Xoffset += int64(gc.Array_array)
-			nodr.Type = nodl.Type
-		}
-
-		gmove(&nodr, &nodl)
-
-		nodl.Xoffset += int64(gc.Array_nel) - int64(gc.Array_array)
-		nodl.Type = gc.Types[gc.Simtype[gc.TUINT]]
-
-		if nr != nil {
-			nodr.Xoffset += int64(gc.Array_nel) - int64(gc.Array_array)
-			nodr.Type = nodl.Type
-		}
-
-		gmove(&nodr, &nodl)
-
-		nodl.Xoffset += int64(gc.Array_cap) - int64(gc.Array_nel)
-		nodl.Type = gc.Types[gc.Simtype[gc.TUINT]]
-
-		if nr != nil {
-			nodr.Xoffset += int64(gc.Array_cap) - int64(gc.Array_nel)
-			nodr.Type = nodl.Type
-		}
-
-		gmove(&nodr, &nodl)
-
-		goto yes
-
-	case gc.TSTRING:
-		if nl.Op == gc.ONAME {
-			gc.Gvardef(nl)
-		}
-		nodl.Xoffset += int64(gc.Array_array)
-		nodl.Type = gc.Ptrto(gc.Types[gc.TUINT8])
-
-		if nr != nil {
-			nodr.Xoffset += int64(gc.Array_array)
-			nodr.Type = nodl.Type
-		}
-
-		gmove(&nodr, &nodl)
-
-		nodl.Xoffset += int64(gc.Array_nel) - int64(gc.Array_array)
-		nodl.Type = gc.Types[gc.Simtype[gc.TUINT]]
-
-		if nr != nil {
-			nodr.Xoffset += int64(gc.Array_nel) - int64(gc.Array_array)
-			nodr.Type = nodl.Type
-		}
-
-		gmove(&nodr, &nodl)
-
-		goto yes
-
-	case gc.TINTER:
-		if nl.Op == gc.ONAME {
-			gc.Gvardef(nl)
-		}
-		nodl.Xoffset += int64(gc.Array_array)
-		nodl.Type = gc.Ptrto(gc.Types[gc.TUINT8])
-
-		if nr != nil {
-			nodr.Xoffset += int64(gc.Array_array)
-			nodr.Type = nodl.Type
-		}
-
-		gmove(&nodr, &nodl)
-
-		nodl.Xoffset += int64(gc.Array_nel) - int64(gc.Array_array)
-		nodl.Type = gc.Ptrto(gc.Types[gc.TUINT8])
-
-		if nr != nil {
-			nodr.Xoffset += int64(gc.Array_nel) - int64(gc.Array_array)
-			nodr.Type = nodl.Type
-		}
-
-		gmove(&nodr, &nodl)
-
-		goto yes
-
-	case gc.TSTRUCT:
-		if nl.Op == gc.ONAME {
-			gc.Gvardef(nl)
-		}
-		loffset := nodl.Xoffset
-		roffset := nodr.Xoffset
-
-		// funarg structs may not begin at offset zero.
-		if nl.Type.Etype == gc.TSTRUCT && nl.Type.Funarg != 0 && nl.Type.Type != nil {
-			loffset -= nl.Type.Type.Width
-		}
-		if nr != nil && nr.Type.Etype == gc.TSTRUCT && nr.Type.Funarg != 0 && nr.Type.Type != nil {
-			roffset -= nr.Type.Type.Width
-		}
-
-		for t := nl.Type.Type; t != nil; t = t.Down {
-			nodl.Xoffset = loffset + t.Width
-			nodl.Type = t.Type
-
-			if nr == nil {
-				gc.Clearslim(&nodl)
-			} else {
-				nodr.Xoffset = roffset + t.Width
-				nodr.Type = nodl.Type
-				gmove(&nodr, &nodl)
-			}
-		}
-
-		goto yes
-	}
-
-no:
-	if freer != 0 {
-		regfree(&nodr)
-	}
-	if freel != 0 {
-		regfree(&nodl)
-	}
-	return false
-
-yes:
-	if freer != 0 {
-		regfree(&nodr)
-	}
-	if freel != 0 {
-		regfree(&nodl)
-	}
-	return true
-}
diff --git a/src/cmd/6g/galign.go b/src/cmd/6g/galign.go
index bdd8a3c..a73ddc6 100644
--- a/src/cmd/6g/galign.go
+++ b/src/cmd/6g/galign.go
@@ -5,10 +5,10 @@
 package main
 
 import (
+	"cmd/internal/gc"
 	"cmd/internal/obj"
 	"cmd/internal/obj/x86"
 )
-import "cmd/internal/gc"
 
 var thechar int = '6'
 
@@ -64,38 +64,52 @@
 }
 
 func main() {
+	if obj.Getgoos() == "nacl" {
+		resvd = append(resvd, x86.REG_BP, x86.REG_R15)
+	} 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.Igen = igen
+	gc.Thearch.Ginscon = ginscon
+	gc.Thearch.Ginsnop = ginsnop
+	gc.Thearch.Gmove = gmove
 	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 d0c43d6..e609d0e 100644
--- a/src/cmd/6g/ggen.go
+++ b/src/cmd/6g/ggen.go
@@ -5,10 +5,10 @@
 package main
 
 import (
+	"cmd/internal/gc"
 	"cmd/internal/obj"
 	"cmd/internal/obj/x86"
 )
-import "cmd/internal/gc"
 
 func defframe(ptxt *obj.Prog) {
 	var n *gc.Node
@@ -16,7 +16,7 @@
 	// fill in argument size, stack size
 	ptxt.To.Type = obj.TYPE_TEXTSIZE
 
-	ptxt.To.U.Argsize = int32(gc.Rnd(gc.Curfn.Type.Argwid, int64(gc.Widthptr)))
+	ptxt.To.Val = int32(gc.Rnd(gc.Curfn.Type.Argwid, int64(gc.Widthptr)))
 	frame := uint32(gc.Rnd(gc.Stksize+gc.Maxarg, int64(gc.Widthreg)))
 	ptxt.To.Offset = int64(frame)
 
@@ -30,9 +30,9 @@
 	ax := uint32(0)
 
 	// iterate through declarations - they are sorted in decreasing xoffset order.
-	for l := gc.Curfn.Dcl; l != nil; l = l.Next {
+	for l := gc.Curfn.Func.Dcl; l != nil; l = l.Next {
 		n = l.N
-		if n.Needzero == 0 {
+		if !n.Needzero {
 			continue
 		}
 		if n.Class != gc.PAUTO {
@@ -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)
-		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")
-	}
-
-	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] != 0 {
-		t = t.Type
-	}
-
-	var flist gc.Iter
-	fp := gc.Structfirst(&flist, gc.Getoutarg(t))
-	if fp == nil {
-		gc.Fatal("cgen_aret: nil")
-	}
-
-	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
@@ -456,7 +136,7 @@
 
 	t0 := t
 	check := 0
-	if gc.Issigned[t.Etype] != 0 {
+	if gc.Issigned[t.Etype] {
 		check = 1
 		if gc.Isconst(nl, gc.CTINT) && gc.Mpgetfix(nl.Val.U.Xval) != -(1<<uint64(t.Width*8-1)) {
 			check = 0
@@ -466,7 +146,7 @@
 	}
 
 	if t.Width < 4 {
-		if gc.Issigned[t.Etype] != 0 {
+		if gc.Issigned[t.Etype] {
 			t = gc.Types[gc.TINT32]
 		} else {
 			t = gc.Types[gc.TUINT32]
@@ -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 {
@@ -503,7 +183,6 @@
 		gmove(&n31, &n3)
 	}
 
-	p2 := (*obj.Prog)(nil)
 	var n4 gc.Node
 	if gc.Nacl {
 		// Native Client does not relay the divide-by-zero trap
@@ -516,10 +195,11 @@
 		if panicdiv == nil {
 			panicdiv = gc.Sysfunc("panicdivide")
 		}
-		ginscall(panicdiv, -1)
+		gc.Ginscall(panicdiv, -1)
 		gc.Patch(p1, gc.Pc)
 	}
 
+	var p2 *obj.Prog
 	if check != 0 {
 		gc.Nodconst(&n4, t, -1)
 		gins(optoas(gc.OCMP, t), &n3, &n4)
@@ -543,14 +223,14 @@
 	var olddx gc.Node
 	var dx gc.Node
 	savex(x86.REG_DX, &dx, &olddx, res, t)
-	if gc.Issigned[t.Etype] == 0 {
+	if !gc.Issigned[t.Etype] {
 		gc.Nodconst(&n4, t, 0)
 		gmove(&n4, &dx)
 	} else {
 		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 {
@@ -786,20 +323,12 @@
  *	res = nl >> nr
  */
 func cgen_shift(op int, bounded bool, nl *gc.Node, nr *gc.Node, res *gc.Node) {
-	var n1 gc.Node
-	var n2 gc.Node
-	var n3 gc.Node
-	var cx gc.Node
-	var oldcx gc.Node
-	var rcx int
-	var tcount *gc.Type
-
 	a := optoas(op, nl.Type)
 
 	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
@@ -812,72 +341,76 @@
 			gins(a, nr, &n1)
 		}
 		gmove(&n1, res)
-		regfree(&n1)
-		goto ret
+		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
 	}
 
-	rcx = int(reg[x86.REG_CX])
+	rcx := int(reg[x86.REG_CX])
+	var n1 gc.Node
 	gc.Nodreg(&n1, gc.Types[gc.TUINT32], x86.REG_CX)
 
 	// Allow either uint32 or uint64 as shift type,
 	// to avoid unnecessary conversion from uint32 to uint64
 	// just to do the comparison.
-	tcount = gc.Types[gc.Simtype[nr.Type.Etype]]
+	tcount := gc.Types[gc.Simtype[nr.Type.Etype]]
 
 	if tcount.Etype < gc.TUINT32 {
 		tcount = gc.Types[gc.TUINT32]
 	}
 
-	regalloc(&n1, nr.Type, &n1) // to hold the shift type in CX
-	regalloc(&n3, tcount, &n1)  // to clear high bits of CX
+	gc.Regalloc(&n1, nr.Type, &n1) // to hold the shift type in CX
+	var n3 gc.Node
+	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)
 
-	oldcx = gc.Node{}
+	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)
 	}
 
 	cx.Type = tcount
 
+	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 {
 		gc.Nodconst(&n3, tcount, nl.Type.Width*8)
 		gins(optoas(gc.OCMP, tcount), &n1, &n3)
 		p1 := gc.Gbranch(optoas(gc.OLT, tcount), nil, +1)
-		if op == gc.ORSH && gc.Issigned[nl.Type.Etype] != 0 {
+		if op == gc.ORSH && gc.Issigned[nl.Type.Etype] {
 			gc.Nodconst(&n3, gc.Types[gc.TUINT32], nl.Type.Width*8-1)
 			gins(a, &n3, &n2)
 		} else {
@@ -893,15 +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)
-
-ret:
+	gc.Regfree(&n1)
+	gc.Regfree(&n2)
 }
 
 /*
@@ -910,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
@@ -920,17 +455,17 @@
 
 	// 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]
 
-	if gc.Issigned[nl.Type.Etype] != 0 {
+	if gc.Issigned[nl.Type.Etype] {
 		t = gc.Types[gc.TINT64]
 	}
 	var n1 gc.Node
@@ -943,8 +478,9 @@
 	// truncate.
 	gmove(&n1, res)
 
-	regfree(&n1b)
-	regfree(&n2b)
+	gc.Regfree(&n1b)
+	gc.Regfree(&n2b)
+	return true
 }
 
 func clearfat(nl *gc.Node) {
@@ -956,7 +492,7 @@
 	w := nl.Type.Width
 
 	// Avoid taking the address for simple enough types.
-	if componentgen(nil, nl) {
+	if gc.Componentgen(nil, nl) {
 		return
 	}
 
@@ -971,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
@@ -1007,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
@@ -1101,7 +637,7 @@
 		p1.From.Type = obj.TYPE_CONST
 		p1.From.Offset = 1 // likely
 		p1.To.Type = obj.TYPE_BRANCH
-		p1.To.U.Branch = p2.Link
+		p1.To.Val = p2.Link
 
 		// crash by write to memory address 0.
 		// if possible, since we know arg is 0, use 0(arg),
@@ -1121,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 4a1edf7..b2290af 100644
--- a/src/cmd/6g/gsubr.go
+++ b/src/cmd/6g/gsubr.go
@@ -31,11 +31,11 @@
 package main
 
 import (
+	"cmd/internal/gc"
 	"cmd/internal/obj"
 	"cmd/internal/obj/x86"
 	"fmt"
 )
-import "cmd/internal/gc"
 
 // TODO(rsc): Can make this bigger if we move
 // the text segment up higher in 6l for all GOOS.
@@ -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
 	}
 
@@ -308,13 +143,12 @@
 	tt := gc.Simsimtype(t.Type)
 	cvt := t.Type
 
-	if gc.Iscomplex[ft] != 0 || gc.Iscomplex[tt] != 0 {
+	if gc.Iscomplex[ft] || gc.Iscomplex[tt] {
 		gc.Complexmove(f, t)
 		return
 	}
 
 	// cannot have two memory operands
-	var r1 gc.Node
 	var a int
 	if gc.Ismem(f) && gc.Ismem(t) {
 		goto hard
@@ -330,13 +164,13 @@
 		// some constants can't move directly to memory.
 		if gc.Ismem(t) {
 			// float constants come from memory.
-			if gc.Isfloat[tt] != 0 {
+			if gc.Isfloat[tt] {
 				goto hard
 			}
 
 			// 64-bit immediates are really 32-bit sign-extended
 			// unless moving into a register.
-			if gc.Isint[tt] != 0 {
+			if gc.Isint[tt] {
 				if gc.Mpcmpfixfix(con.Val.U.Xval, gc.Minintval[gc.TINT32]) < 0 {
 					goto hard
 				}
@@ -537,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)
@@ -557,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
 
 		/*
@@ -618,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)
@@ -640,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
 
 		/*
@@ -669,20 +503,24 @@
 
 	// requires register destination
 rdst:
-	regalloc(&r1, t.Type, t)
+	{
+		var r1 gc.Node
+		gc.Regalloc(&r1, t.Type, t)
 
-	gins(a, f, &r1)
-	gmove(&r1, t)
-	regfree(&r1)
-	return
+		gins(a, f, &r1)
+		gmove(&r1, t)
+		gc.Regfree(&r1)
+		return
+	}
 
 	// requires register intermediate
 hard:
-	regalloc(&r1, cvt, t)
+	var r1 gc.Node
+	gc.Regalloc(&r1, cvt, t)
 
 	gmove(f, &r1)
 	gmove(&r1, t)
-	regfree(&r1)
+	gc.Regfree(&r1)
 	return
 }
 
@@ -710,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,
@@ -743,21 +594,10 @@
 		}
 	}
 
-	af := obj.Addr{}
-	at := obj.Addr{}
-	if f != nil {
-		gc.Naddr(f, &af, 1)
-	}
-	if t != nil {
-		gc.Naddr(t, &at, 1)
-	}
 	p := gc.Prog(as)
-	if f != nil {
-		p.From = af
-	}
-	if t != nil {
-		p.To = at
-	}
+	gc.Naddr(&p.From, f)
+	gc.Naddr(&p.To, t)
+
 	if gc.Debug['g'] != 0 {
 		fmt.Printf("%v\n", p)
 	}
@@ -777,10 +617,10 @@
 		w = 8
 	}
 
-	if w != 0 && ((f != nil && af.Width < int64(w)) || (t != nil && at.Width > int64(w))) {
+	if w != 0 && ((f != nil && p.From.Width < int64(w)) || (t != nil && p.To.Width > int64(w))) {
 		gc.Dump("f", f)
 		gc.Dump("t", t)
-		gc.Fatal("bad width: %v (%d, %d)\n", p, af.Width, at.Width)
+		gc.Fatal("bad width: %v (%d, %d)\n", p, p.From.Width, p.To.Width)
 	}
 
 	if p.To.Type == obj.TYPE_ADDR && w > 0 {
@@ -790,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)
 }
 
 /*
@@ -862,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,
@@ -1304,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
 }
@@ -1349,12 +1173,6 @@
 
 	*a = obj.Addr{}
 
-	var o int
-	var n1 gc.Node
-	var oary [10]int64
-	var nn *gc.Node
-	var reg *gc.Node
-	var reg1 *gc.Node
 	switch n.Op {
 	case gc.OLITERAL:
 		if !gc.Isconst(n, gc.CTINT) {
@@ -1364,118 +1182,108 @@
 		if v >= 32000 || v <= -32000 {
 			break
 		}
-		goto lit
+		switch as {
+		default:
+			return false
+
+		case x86.AADDB,
+			x86.AADDW,
+			x86.AADDL,
+			x86.AADDQ,
+			x86.ASUBB,
+			x86.ASUBW,
+			x86.ASUBL,
+			x86.ASUBQ,
+			x86.AANDB,
+			x86.AANDW,
+			x86.AANDL,
+			x86.AANDQ,
+			x86.AORB,
+			x86.AORW,
+			x86.AORL,
+			x86.AORQ,
+			x86.AXORB,
+			x86.AXORW,
+			x86.AXORL,
+			x86.AXORQ,
+			x86.AINCB,
+			x86.AINCW,
+			x86.AINCL,
+			x86.AINCQ,
+			x86.ADECB,
+			x86.ADECW,
+			x86.ADECL,
+			x86.ADECQ,
+			x86.AMOVB,
+			x86.AMOVW,
+			x86.AMOVL,
+			x86.AMOVQ:
+			break
+		}
+
+		cleani += 2
+		reg := &clean[cleani-1]
+		reg1 := &clean[cleani-2]
+		reg.Op = gc.OEMPTY
+		reg1.Op = gc.OEMPTY
+		gc.Naddr(a, n)
+		return true
 
 	case gc.ODOT,
 		gc.ODOTPTR:
 		cleani += 2
-		reg = &clean[cleani-1]
+		reg := &clean[cleani-1]
 		reg1 := &clean[cleani-2]
 		reg.Op = gc.OEMPTY
 		reg1.Op = gc.OEMPTY
-		goto odot
+		var nn *gc.Node
+		var oary [10]int64
+		o := gc.Dotoffset(n, oary[:], &nn)
+		if nn == nil {
+			sudoclean()
+			return false
+		}
+
+		if nn.Addable != 0 && o == 1 && oary[0] >= 0 {
+			// directly addressable set of DOTs
+			n1 := *nn
+
+			n1.Type = n.Type
+			n1.Xoffset += oary[0]
+			gc.Naddr(a, &n1)
+			return true
+		}
+
+		gc.Regalloc(reg, gc.Types[gc.Tptr], nil)
+		n1 := *reg
+		n1.Op = gc.OINDREG
+		if oary[0] >= 0 {
+			gc.Agen(nn, reg)
+			n1.Xoffset = oary[0]
+		} else {
+			gc.Cgen(nn, reg)
+			gc.Cgen_checknil(reg)
+			n1.Xoffset = -(oary[0] + 1)
+		}
+
+		for i := 1; i < o; i++ {
+			if oary[i] >= 0 {
+				gc.Fatal("can't happen")
+			}
+			gins(movptr, &n1, reg)
+			gc.Cgen_checknil(reg)
+			n1.Xoffset = -(oary[i] + 1)
+		}
+
+		a.Type = obj.TYPE_NONE
+		a.Index = obj.TYPE_NONE
+		gc.Fixlargeoffset(&n1)
+		gc.Naddr(a, &n1)
+		return true
 
 	case gc.OINDEX:
 		return false
 	}
 
 	return false
-
-lit:
-	switch as {
-	default:
-		return false
-
-	case x86.AADDB,
-		x86.AADDW,
-		x86.AADDL,
-		x86.AADDQ,
-		x86.ASUBB,
-		x86.ASUBW,
-		x86.ASUBL,
-		x86.ASUBQ,
-		x86.AANDB,
-		x86.AANDW,
-		x86.AANDL,
-		x86.AANDQ,
-		x86.AORB,
-		x86.AORW,
-		x86.AORL,
-		x86.AORQ,
-		x86.AXORB,
-		x86.AXORW,
-		x86.AXORL,
-		x86.AXORQ,
-		x86.AINCB,
-		x86.AINCW,
-		x86.AINCL,
-		x86.AINCQ,
-		x86.ADECB,
-		x86.ADECW,
-		x86.ADECL,
-		x86.ADECQ,
-		x86.AMOVB,
-		x86.AMOVW,
-		x86.AMOVL,
-		x86.AMOVQ:
-		break
-	}
-
-	cleani += 2
-	reg = &clean[cleani-1]
-	reg1 = &clean[cleani-2]
-	reg.Op = gc.OEMPTY
-	reg1.Op = gc.OEMPTY
-	gc.Naddr(n, a, 1)
-	goto yes
-
-odot:
-	o = gc.Dotoffset(n, oary[:], &nn)
-	if nn == nil {
-		goto no
-	}
-
-	if nn.Addable != 0 && o == 1 && oary[0] >= 0 {
-		// directly addressable set of DOTs
-		n1 := *nn
-
-		n1.Type = n.Type
-		n1.Xoffset += oary[0]
-		gc.Naddr(&n1, a, 1)
-		goto yes
-	}
-
-	regalloc(reg, gc.Types[gc.Tptr], nil)
-	n1 = *reg
-	n1.Op = gc.OINDREG
-	if oary[0] >= 0 {
-		agen(nn, reg)
-		n1.Xoffset = oary[0]
-	} else {
-		cgen(nn, reg)
-		gc.Cgen_checknil(reg)
-		n1.Xoffset = -(oary[0] + 1)
-	}
-
-	for i := 1; i < o; i++ {
-		if oary[i] >= 0 {
-			gc.Fatal("can't happen")
-		}
-		gins(movptr, &n1, reg)
-		gc.Cgen_checknil(reg)
-		n1.Xoffset = -(oary[i] + 1)
-	}
-
-	a.Type = obj.TYPE_NONE
-	a.Index = obj.TYPE_NONE
-	fixlargeoffset(&n1)
-	gc.Naddr(&n1, a, 1)
-	goto yes
-
-yes:
-	return true
-
-no:
-	sudoclean()
-	return false
 }
diff --git a/src/cmd/6g/peep.go b/src/cmd/6g/peep.go
index ed582d7..1fbf79a 100644
--- a/src/cmd/6g/peep.go
+++ b/src/cmd/6g/peep.go
@@ -31,11 +31,11 @@
 package main
 
 import (
+	"cmd/internal/gc"
 	"cmd/internal/obj"
 	"cmd/internal/obj/x86"
 	"fmt"
 )
-import "cmd/internal/gc"
 
 var gactive uint32
 
@@ -45,14 +45,12 @@
 
 // do we need the carry bit
 func needc(p *obj.Prog) bool {
-	var info gc.ProgInfo
-
 	for p != nil {
-		proginfo(&info, p)
-		if info.Flags&gc.UseCarry != 0 {
+		flags := progcarryflags(p)
+		if flags&gc.UseCarry != 0 {
 			return true
 		}
-		if info.Flags&(gc.SetCarry|gc.KillCarry) != 0 {
+		if flags&(gc.SetCarry|gc.KillCarry) != 0 {
 			return false
 		}
 		p = p.Link
@@ -308,7 +306,7 @@
 	var r *gc.Flow
 	var p *obj.Prog
 
-	b := (*gc.Flow)(nil)
+	var b *gc.Flow
 	p0 := (*obj.Prog)(r0.Prog)
 	for r = gc.Uniqp(r0); r != nil && gc.Uniqs(r) != nil; r = gc.Uniqp(r) {
 		p = r.Prog
@@ -328,7 +326,7 @@
 	}
 
 	if b == nil {
-		if gc.Debug['v'] != 0 {
+		if gc.Debug['P'] != 0 && gc.Debug['v'] != 0 {
 			fmt.Printf("no pushback: %v\n", r0.Prog)
 			if r != nil {
 				fmt.Printf("\t%v [%d]\n", r.Prog, gc.Uniqs(r) != nil)
@@ -338,7 +336,7 @@
 		return
 	}
 
-	if gc.Debug['v'] != 0 {
+	if gc.Debug['P'] != 0 && gc.Debug['v'] != 0 {
 		fmt.Printf("pushback\n")
 		for r := (*gc.Flow)(b); ; r = r.Link {
 			fmt.Printf("\t%v\n", r.Prog)
@@ -368,7 +366,7 @@
 	p0.From = t.From
 	p0.To = t.To
 
-	if gc.Debug['v'] != 0 {
+	if gc.Debug['P'] != 0 && gc.Debug['v'] != 0 {
 		fmt.Printf("\tafter\n")
 		for r := (*gc.Flow)(b); ; r = r.Link {
 			fmt.Printf("\t%v\n", r.Prog)
@@ -508,15 +506,12 @@
 
 // is reg guaranteed to be truncated by a previous L instruction?
 func prevl(r0 *gc.Flow, reg int) bool {
-	var p *obj.Prog
-	var info gc.ProgInfo
-
 	for r := (*gc.Flow)(gc.Uniqp(r0)); r != nil; r = gc.Uniqp(r) {
-		p = r.Prog
+		p := r.Prog
 		if p.To.Type == obj.TYPE_REG && int(p.To.Reg) == reg {
-			proginfo(&info, p)
-			if info.Flags&gc.RightWrite != 0 {
-				if info.Flags&gc.SizeL != 0 {
+			flags := progflags(p)
+			if flags&gc.RightWrite != 0 {
+				if flags&gc.SizeL != 0 {
 					return true
 				}
 				return false
@@ -562,9 +557,7 @@
 		return false
 	}
 
-	var info gc.ProgInfo
-	var r *gc.Flow
-	for r = gc.Uniqp(r0); r != nil; r = gc.Uniqp(r) {
+	for r := gc.Uniqp(r0); r != nil; r = gc.Uniqp(r) {
 		if gc.Debug['P'] != 0 && gc.Debug['v'] != 0 {
 			fmt.Printf("\t? %v\n", r.Prog)
 		}
@@ -579,23 +572,46 @@
 		if p.As == obj.AVARDEF || p.As == obj.AVARKILL {
 			continue
 		}
-		proginfo(&info, p)
-		if info.Flags&gc.Call != 0 {
+		if p.Info.Flags&gc.Call != 0 {
 			if gc.Debug['P'] != 0 && gc.Debug['v'] != 0 {
 				fmt.Printf("\tfound %v; return 0\n", p)
 			}
 			return false
 		}
 
-		if info.Reguse|info.Regset != 0 {
+		if p.Info.Reguse|p.Info.Regset != 0 {
 			if gc.Debug['P'] != 0 && gc.Debug['v'] != 0 {
 				fmt.Printf("\tfound %v; return 0\n", p)
 			}
 			return false
 		}
 
-		if (info.Flags&gc.Move != 0) && (info.Flags&(gc.SizeL|gc.SizeQ|gc.SizeF|gc.SizeD) != 0) && p.To.Type == v1.Type && p.To.Reg == v1.Reg {
-			goto gotit
+		if (p.Info.Flags&gc.Move != 0) && (p.Info.Flags&(gc.SizeL|gc.SizeQ|gc.SizeF|gc.SizeD) != 0) && p.To.Type == v1.Type && p.To.Reg == v1.Reg {
+			copysub(&p.To, v1, v2, 1)
+			if gc.Debug['P'] != 0 {
+				fmt.Printf("gotit: %v->%v\n%v", gc.Ctxt.Dconv(v1), gc.Ctxt.Dconv(v2), r.Prog)
+				if p.From.Type == v2.Type && p.From.Reg == v2.Reg {
+					fmt.Printf(" excise")
+				}
+				fmt.Printf("\n")
+			}
+
+			for r = gc.Uniqs(r); r != r0; r = gc.Uniqs(r) {
+				p = r.Prog
+				copysub(&p.From, v1, v2, 1)
+				copysub(&p.To, v1, v2, 1)
+				if gc.Debug['P'] != 0 {
+					fmt.Printf("%v\n", r.Prog)
+				}
+			}
+
+			t := int(int(v1.Reg))
+			v1.Reg = v2.Reg
+			v2.Reg = int16(t)
+			if gc.Debug['P'] != 0 {
+				fmt.Printf("%v last\n", r.Prog)
+			}
+			return true
 		}
 
 		if copyau(&p.From, v2) || copyau(&p.To, v2) {
@@ -617,33 +633,6 @@
 		fmt.Printf("\tran off end; return 0\n")
 	}
 	return false
-
-gotit:
-	copysub(&p.To, v1, v2, 1)
-	if gc.Debug['P'] != 0 {
-		fmt.Printf("gotit: %v->%v\n%v", gc.Ctxt.Dconv(v1), gc.Ctxt.Dconv(v2), r.Prog)
-		if p.From.Type == v2.Type && p.From.Reg == v2.Reg {
-			fmt.Printf(" excise")
-		}
-		fmt.Printf("\n")
-	}
-
-	for r = gc.Uniqs(r); r != r0; r = gc.Uniqs(r) {
-		p = r.Prog
-		copysub(&p.From, v1, v2, 1)
-		copysub(&p.To, v1, v2, 1)
-		if gc.Debug['P'] != 0 {
-			fmt.Printf("%v\n", r.Prog)
-		}
-	}
-
-	t := int(int(v1.Reg))
-	v1.Reg = v2.Reg
-	v2.Reg = int16(t)
-	if gc.Debug['P'] != 0 {
-		fmt.Printf("%v last\n", r.Prog)
-	}
-	return true
 }
 
 /*
@@ -829,26 +818,24 @@
 	if p.As == obj.AVARDEF || p.As == obj.AVARKILL {
 		return 0
 	}
-	var info gc.ProgInfo
-	proginfo(&info, p)
 
-	if (info.Reguse|info.Regset)&RtoB(int(v.Reg)) != 0 {
+	if (p.Info.Reguse|p.Info.Regset)&RtoB(int(v.Reg)) != 0 {
 		return 2
 	}
 
-	if info.Flags&gc.LeftAddr != 0 {
+	if p.Info.Flags&gc.LeftAddr != 0 {
 		if copyas(&p.From, v) {
 			return 2
 		}
 	}
 
-	if info.Flags&(gc.RightRead|gc.RightWrite) == gc.RightRead|gc.RightWrite {
+	if p.Info.Flags&(gc.RightRead|gc.RightWrite) == gc.RightRead|gc.RightWrite {
 		if copyas(&p.To, v) {
 			return 2
 		}
 	}
 
-	if info.Flags&gc.RightWrite != 0 {
+	if p.Info.Flags&gc.RightWrite != 0 {
 		if copyas(&p.To, v) {
 			if s != nil {
 				return copysub(&p.From, v, s, 1)
@@ -860,7 +847,7 @@
 		}
 	}
 
-	if info.Flags&(gc.LeftAddr|gc.LeftRead|gc.LeftWrite|gc.RightAddr|gc.RightRead|gc.RightWrite) != 0 {
+	if p.Info.Flags&(gc.LeftAddr|gc.LeftRead|gc.LeftWrite|gc.RightAddr|gc.RightRead|gc.RightWrite) != 0 {
 		if s != nil {
 			if copysub(&p.From, v, s, 1) != 0 {
 				return 1
@@ -1027,7 +1014,7 @@
 					if p.From.Node == p0.From.Node {
 						if p.From.Offset == p0.From.Offset {
 							if p.From.Scale == p0.From.Scale {
-								if p.From.Type == obj.TYPE_FCONST && p.From.U.Dval == p0.From.U.Dval {
+								if p.From.Type == obj.TYPE_FCONST && p.From.Val.(float64) == p0.From.Val.(float64) {
 									if p.From.Index == p0.From.Index {
 										excise(r)
 										goto loop
diff --git a/src/cmd/6g/prog.go b/src/cmd/6g/prog.go
index 3f4c195..0644800 100644
--- a/src/cmd/6g/prog.go
+++ b/src/cmd/6g/prog.go
@@ -5,18 +5,12 @@
 package main
 
 import (
+	"cmd/internal/gc"
 	"cmd/internal/obj"
 	"cmd/internal/obj/x86"
 )
-import "cmd/internal/gc"
 
-var (
-	AX               = RtoB(x86.REG_AX)
-	BX               = RtoB(x86.REG_BX)
-	CX               = RtoB(x86.REG_CX)
-	DX               = RtoB(x86.REG_DX)
-	DI               = RtoB(x86.REG_DI)
-	SI               = RtoB(x86.REG_SI)
+const (
 	LeftRdwr  uint32 = gc.LeftRead | gc.LeftWrite
 	RightRdwr uint32 = gc.RightRead | gc.RightWrite
 )
@@ -30,214 +24,227 @@
 // size variants of an operation even if we just use a subset.
 //
 // The table is formatted for 8-space tabs.
-var progtable = [x86.ALAST]gc.ProgInfo{
-	obj.ATYPE:     gc.ProgInfo{gc.Pseudo | gc.Skip, 0, 0, 0},
-	obj.ATEXT:     gc.ProgInfo{gc.Pseudo, 0, 0, 0},
-	obj.AFUNCDATA: gc.ProgInfo{gc.Pseudo, 0, 0, 0},
-	obj.APCDATA:   gc.ProgInfo{gc.Pseudo, 0, 0, 0},
-	obj.AUNDEF:    gc.ProgInfo{gc.Break, 0, 0, 0},
-	obj.AUSEFIELD: gc.ProgInfo{gc.OK, 0, 0, 0},
-	obj.ACHECKNIL: gc.ProgInfo{gc.LeftRead, 0, 0, 0},
-	obj.AVARDEF:   gc.ProgInfo{gc.Pseudo | gc.RightWrite, 0, 0, 0},
-	obj.AVARKILL:  gc.ProgInfo{gc.Pseudo | gc.RightWrite, 0, 0, 0},
+var progtable = [x86.ALAST]obj.ProgInfo{
+	obj.ATYPE:     {gc.Pseudo | gc.Skip, 0, 0, 0},
+	obj.ATEXT:     {gc.Pseudo, 0, 0, 0},
+	obj.AFUNCDATA: {gc.Pseudo, 0, 0, 0},
+	obj.APCDATA:   {gc.Pseudo, 0, 0, 0},
+	obj.AUNDEF:    {gc.Break, 0, 0, 0},
+	obj.AUSEFIELD: {gc.OK, 0, 0, 0},
+	obj.ACHECKNIL: {gc.LeftRead, 0, 0, 0},
+	obj.AVARDEF:   {gc.Pseudo | gc.RightWrite, 0, 0, 0},
+	obj.AVARKILL:  {gc.Pseudo | gc.RightWrite, 0, 0, 0},
 
 	// NOP is an internal no-op that also stands
 	// for USED and SET annotations, not the Intel opcode.
-	obj.ANOP:       gc.ProgInfo{gc.LeftRead | gc.RightWrite, 0, 0, 0},
-	x86.AADCL:      gc.ProgInfo{gc.SizeL | gc.LeftRead | RightRdwr | gc.SetCarry | gc.UseCarry, 0, 0, 0},
-	x86.AADCQ:      gc.ProgInfo{gc.SizeQ | gc.LeftRead | RightRdwr | gc.SetCarry | gc.UseCarry, 0, 0, 0},
-	x86.AADCW:      gc.ProgInfo{gc.SizeW | gc.LeftRead | RightRdwr | gc.SetCarry | gc.UseCarry, 0, 0, 0},
-	x86.AADDB:      gc.ProgInfo{gc.SizeB | gc.LeftRead | RightRdwr | gc.SetCarry, 0, 0, 0},
-	x86.AADDL:      gc.ProgInfo{gc.SizeL | gc.LeftRead | RightRdwr | gc.SetCarry, 0, 0, 0},
-	x86.AADDW:      gc.ProgInfo{gc.SizeW | gc.LeftRead | RightRdwr | gc.SetCarry, 0, 0, 0},
-	x86.AADDQ:      gc.ProgInfo{gc.SizeQ | gc.LeftRead | RightRdwr | gc.SetCarry, 0, 0, 0},
-	x86.AADDSD:     gc.ProgInfo{gc.SizeD | gc.LeftRead | RightRdwr, 0, 0, 0},
-	x86.AADDSS:     gc.ProgInfo{gc.SizeF | gc.LeftRead | RightRdwr, 0, 0, 0},
-	x86.AANDB:      gc.ProgInfo{gc.SizeB | gc.LeftRead | RightRdwr | gc.SetCarry, 0, 0, 0},
-	x86.AANDL:      gc.ProgInfo{gc.SizeL | gc.LeftRead | RightRdwr | gc.SetCarry, 0, 0, 0},
-	x86.AANDQ:      gc.ProgInfo{gc.SizeQ | gc.LeftRead | RightRdwr | gc.SetCarry, 0, 0, 0},
-	x86.AANDW:      gc.ProgInfo{gc.SizeW | gc.LeftRead | RightRdwr | gc.SetCarry, 0, 0, 0},
-	obj.ACALL:      gc.ProgInfo{gc.RightAddr | gc.Call | gc.KillCarry, 0, 0, 0},
-	x86.ACDQ:       gc.ProgInfo{gc.OK, AX, AX | DX, 0},
-	x86.ACQO:       gc.ProgInfo{gc.OK, AX, AX | DX, 0},
-	x86.ACWD:       gc.ProgInfo{gc.OK, AX, AX | DX, 0},
-	x86.ACLD:       gc.ProgInfo{gc.OK, 0, 0, 0},
-	x86.ASTD:       gc.ProgInfo{gc.OK, 0, 0, 0},
-	x86.ACMPB:      gc.ProgInfo{gc.SizeB | gc.LeftRead | gc.RightRead | gc.SetCarry, 0, 0, 0},
-	x86.ACMPL:      gc.ProgInfo{gc.SizeL | gc.LeftRead | gc.RightRead | gc.SetCarry, 0, 0, 0},
-	x86.ACMPQ:      gc.ProgInfo{gc.SizeQ | gc.LeftRead | gc.RightRead | gc.SetCarry, 0, 0, 0},
-	x86.ACMPW:      gc.ProgInfo{gc.SizeW | gc.LeftRead | gc.RightRead | gc.SetCarry, 0, 0, 0},
-	x86.ACOMISD:    gc.ProgInfo{gc.SizeD | gc.LeftRead | gc.RightRead | gc.SetCarry, 0, 0, 0},
-	x86.ACOMISS:    gc.ProgInfo{gc.SizeF | gc.LeftRead | gc.RightRead | gc.SetCarry, 0, 0, 0},
-	x86.ACVTSD2SL:  gc.ProgInfo{gc.SizeL | gc.LeftRead | gc.RightWrite | gc.Conv, 0, 0, 0},
-	x86.ACVTSD2SQ:  gc.ProgInfo{gc.SizeQ | gc.LeftRead | gc.RightWrite | gc.Conv, 0, 0, 0},
-	x86.ACVTSD2SS:  gc.ProgInfo{gc.SizeF | gc.LeftRead | gc.RightWrite | gc.Conv, 0, 0, 0},
-	x86.ACVTSL2SD:  gc.ProgInfo{gc.SizeD | gc.LeftRead | gc.RightWrite | gc.Conv, 0, 0, 0},
-	x86.ACVTSL2SS:  gc.ProgInfo{gc.SizeF | gc.LeftRead | gc.RightWrite | gc.Conv, 0, 0, 0},
-	x86.ACVTSQ2SD:  gc.ProgInfo{gc.SizeD | gc.LeftRead | gc.RightWrite | gc.Conv, 0, 0, 0},
-	x86.ACVTSQ2SS:  gc.ProgInfo{gc.SizeF | gc.LeftRead | gc.RightWrite | gc.Conv, 0, 0, 0},
-	x86.ACVTSS2SD:  gc.ProgInfo{gc.SizeD | gc.LeftRead | gc.RightWrite | gc.Conv, 0, 0, 0},
-	x86.ACVTSS2SL:  gc.ProgInfo{gc.SizeL | gc.LeftRead | gc.RightWrite | gc.Conv, 0, 0, 0},
-	x86.ACVTSS2SQ:  gc.ProgInfo{gc.SizeQ | gc.LeftRead | gc.RightWrite | gc.Conv, 0, 0, 0},
-	x86.ACVTTSD2SL: gc.ProgInfo{gc.SizeL | gc.LeftRead | gc.RightWrite | gc.Conv, 0, 0, 0},
-	x86.ACVTTSD2SQ: gc.ProgInfo{gc.SizeQ | gc.LeftRead | gc.RightWrite | gc.Conv, 0, 0, 0},
-	x86.ACVTTSS2SL: gc.ProgInfo{gc.SizeL | gc.LeftRead | gc.RightWrite | gc.Conv, 0, 0, 0},
-	x86.ACVTTSS2SQ: gc.ProgInfo{gc.SizeQ | gc.LeftRead | gc.RightWrite | gc.Conv, 0, 0, 0},
-	x86.ADECB:      gc.ProgInfo{gc.SizeB | RightRdwr, 0, 0, 0},
-	x86.ADECL:      gc.ProgInfo{gc.SizeL | RightRdwr, 0, 0, 0},
-	x86.ADECQ:      gc.ProgInfo{gc.SizeQ | RightRdwr, 0, 0, 0},
-	x86.ADECW:      gc.ProgInfo{gc.SizeW | RightRdwr, 0, 0, 0},
-	x86.ADIVB:      gc.ProgInfo{gc.SizeB | gc.LeftRead | gc.SetCarry, AX, AX, 0},
-	x86.ADIVL:      gc.ProgInfo{gc.SizeL | gc.LeftRead | gc.SetCarry, AX | DX, AX | DX, 0},
-	x86.ADIVQ:      gc.ProgInfo{gc.SizeQ | gc.LeftRead | gc.SetCarry, AX | DX, AX | DX, 0},
-	x86.ADIVW:      gc.ProgInfo{gc.SizeW | gc.LeftRead | gc.SetCarry, AX | DX, AX | DX, 0},
-	x86.ADIVSD:     gc.ProgInfo{gc.SizeD | gc.LeftRead | RightRdwr, 0, 0, 0},
-	x86.ADIVSS:     gc.ProgInfo{gc.SizeF | gc.LeftRead | RightRdwr, 0, 0, 0},
-	x86.AIDIVB:     gc.ProgInfo{gc.SizeB | gc.LeftRead | gc.SetCarry, AX, AX, 0},
-	x86.AIDIVL:     gc.ProgInfo{gc.SizeL | gc.LeftRead | gc.SetCarry, AX | DX, AX | DX, 0},
-	x86.AIDIVQ:     gc.ProgInfo{gc.SizeQ | gc.LeftRead | gc.SetCarry, AX | DX, AX | DX, 0},
-	x86.AIDIVW:     gc.ProgInfo{gc.SizeW | gc.LeftRead | gc.SetCarry, AX | DX, AX | DX, 0},
-	x86.AIMULB:     gc.ProgInfo{gc.SizeB | gc.LeftRead | gc.SetCarry, AX, AX, 0},
-	x86.AIMULL:     gc.ProgInfo{gc.SizeL | gc.LeftRead | gc.ImulAXDX | gc.SetCarry, 0, 0, 0},
-	x86.AIMULQ:     gc.ProgInfo{gc.SizeQ | gc.LeftRead | gc.ImulAXDX | gc.SetCarry, 0, 0, 0},
-	x86.AIMULW:     gc.ProgInfo{gc.SizeW | gc.LeftRead | gc.ImulAXDX | gc.SetCarry, 0, 0, 0},
-	x86.AINCB:      gc.ProgInfo{gc.SizeB | RightRdwr, 0, 0, 0},
-	x86.AINCL:      gc.ProgInfo{gc.SizeL | RightRdwr, 0, 0, 0},
-	x86.AINCQ:      gc.ProgInfo{gc.SizeQ | RightRdwr, 0, 0, 0},
-	x86.AINCW:      gc.ProgInfo{gc.SizeW | RightRdwr, 0, 0, 0},
-	x86.AJCC:       gc.ProgInfo{gc.Cjmp | gc.UseCarry, 0, 0, 0},
-	x86.AJCS:       gc.ProgInfo{gc.Cjmp | gc.UseCarry, 0, 0, 0},
-	x86.AJEQ:       gc.ProgInfo{gc.Cjmp | gc.UseCarry, 0, 0, 0},
-	x86.AJGE:       gc.ProgInfo{gc.Cjmp | gc.UseCarry, 0, 0, 0},
-	x86.AJGT:       gc.ProgInfo{gc.Cjmp | gc.UseCarry, 0, 0, 0},
-	x86.AJHI:       gc.ProgInfo{gc.Cjmp | gc.UseCarry, 0, 0, 0},
-	x86.AJLE:       gc.ProgInfo{gc.Cjmp | gc.UseCarry, 0, 0, 0},
-	x86.AJLS:       gc.ProgInfo{gc.Cjmp | gc.UseCarry, 0, 0, 0},
-	x86.AJLT:       gc.ProgInfo{gc.Cjmp | gc.UseCarry, 0, 0, 0},
-	x86.AJMI:       gc.ProgInfo{gc.Cjmp | gc.UseCarry, 0, 0, 0},
-	x86.AJNE:       gc.ProgInfo{gc.Cjmp | gc.UseCarry, 0, 0, 0},
-	x86.AJOC:       gc.ProgInfo{gc.Cjmp | gc.UseCarry, 0, 0, 0},
-	x86.AJOS:       gc.ProgInfo{gc.Cjmp | gc.UseCarry, 0, 0, 0},
-	x86.AJPC:       gc.ProgInfo{gc.Cjmp | gc.UseCarry, 0, 0, 0},
-	x86.AJPL:       gc.ProgInfo{gc.Cjmp | gc.UseCarry, 0, 0, 0},
-	x86.AJPS:       gc.ProgInfo{gc.Cjmp | gc.UseCarry, 0, 0, 0},
-	obj.AJMP:       gc.ProgInfo{gc.Jump | gc.Break | gc.KillCarry, 0, 0, 0},
-	x86.ALEAL:      gc.ProgInfo{gc.LeftAddr | gc.RightWrite, 0, 0, 0},
-	x86.ALEAQ:      gc.ProgInfo{gc.LeftAddr | gc.RightWrite, 0, 0, 0},
-	x86.AMOVBLSX:   gc.ProgInfo{gc.SizeL | gc.LeftRead | gc.RightWrite | gc.Conv, 0, 0, 0},
-	x86.AMOVBLZX:   gc.ProgInfo{gc.SizeL | gc.LeftRead | gc.RightWrite | gc.Conv, 0, 0, 0},
-	x86.AMOVBQSX:   gc.ProgInfo{gc.SizeQ | gc.LeftRead | gc.RightWrite | gc.Conv, 0, 0, 0},
-	x86.AMOVBQZX:   gc.ProgInfo{gc.SizeQ | gc.LeftRead | gc.RightWrite | gc.Conv, 0, 0, 0},
-	x86.AMOVBWSX:   gc.ProgInfo{gc.SizeW | gc.LeftRead | gc.RightWrite | gc.Conv, 0, 0, 0},
-	x86.AMOVBWZX:   gc.ProgInfo{gc.SizeW | gc.LeftRead | gc.RightWrite | gc.Conv, 0, 0, 0},
-	x86.AMOVLQSX:   gc.ProgInfo{gc.SizeQ | gc.LeftRead | gc.RightWrite | gc.Conv, 0, 0, 0},
-	x86.AMOVLQZX:   gc.ProgInfo{gc.SizeQ | gc.LeftRead | gc.RightWrite | gc.Conv, 0, 0, 0},
-	x86.AMOVWLSX:   gc.ProgInfo{gc.SizeL | gc.LeftRead | gc.RightWrite | gc.Conv, 0, 0, 0},
-	x86.AMOVWLZX:   gc.ProgInfo{gc.SizeL | gc.LeftRead | gc.RightWrite | gc.Conv, 0, 0, 0},
-	x86.AMOVWQSX:   gc.ProgInfo{gc.SizeQ | gc.LeftRead | gc.RightWrite | gc.Conv, 0, 0, 0},
-	x86.AMOVWQZX:   gc.ProgInfo{gc.SizeQ | gc.LeftRead | gc.RightWrite | gc.Conv, 0, 0, 0},
-	x86.AMOVQL:     gc.ProgInfo{gc.SizeL | gc.LeftRead | gc.RightWrite | gc.Conv, 0, 0, 0},
-	x86.AMOVB:      gc.ProgInfo{gc.SizeB | gc.LeftRead | gc.RightWrite | gc.Move, 0, 0, 0},
-	x86.AMOVL:      gc.ProgInfo{gc.SizeL | gc.LeftRead | gc.RightWrite | gc.Move, 0, 0, 0},
-	x86.AMOVQ:      gc.ProgInfo{gc.SizeQ | gc.LeftRead | gc.RightWrite | gc.Move, 0, 0, 0},
-	x86.AMOVW:      gc.ProgInfo{gc.SizeW | gc.LeftRead | gc.RightWrite | gc.Move, 0, 0, 0},
-	x86.AMOVSB:     gc.ProgInfo{gc.OK, DI | SI, DI | SI, 0},
-	x86.AMOVSL:     gc.ProgInfo{gc.OK, DI | SI, DI | SI, 0},
-	x86.AMOVSQ:     gc.ProgInfo{gc.OK, DI | SI, DI | SI, 0},
-	x86.AMOVSW:     gc.ProgInfo{gc.OK, DI | SI, DI | SI, 0},
-	obj.ADUFFCOPY:  gc.ProgInfo{gc.OK, DI | SI, DI | SI | CX, 0},
-	x86.AMOVSD:     gc.ProgInfo{gc.SizeD | gc.LeftRead | gc.RightWrite | gc.Move, 0, 0, 0},
-	x86.AMOVSS:     gc.ProgInfo{gc.SizeF | gc.LeftRead | gc.RightWrite | gc.Move, 0, 0, 0},
+	obj.ANOP:       {gc.LeftRead | gc.RightWrite, 0, 0, 0},
+	x86.AADCL:      {gc.SizeL | gc.LeftRead | RightRdwr | gc.SetCarry | gc.UseCarry, 0, 0, 0},
+	x86.AADCQ:      {gc.SizeQ | gc.LeftRead | RightRdwr | gc.SetCarry | gc.UseCarry, 0, 0, 0},
+	x86.AADCW:      {gc.SizeW | gc.LeftRead | RightRdwr | gc.SetCarry | gc.UseCarry, 0, 0, 0},
+	x86.AADDB:      {gc.SizeB | gc.LeftRead | RightRdwr | gc.SetCarry, 0, 0, 0},
+	x86.AADDL:      {gc.SizeL | gc.LeftRead | RightRdwr | gc.SetCarry, 0, 0, 0},
+	x86.AADDW:      {gc.SizeW | gc.LeftRead | RightRdwr | gc.SetCarry, 0, 0, 0},
+	x86.AADDQ:      {gc.SizeQ | gc.LeftRead | RightRdwr | gc.SetCarry, 0, 0, 0},
+	x86.AADDSD:     {gc.SizeD | gc.LeftRead | RightRdwr, 0, 0, 0},
+	x86.AADDSS:     {gc.SizeF | gc.LeftRead | RightRdwr, 0, 0, 0},
+	x86.AANDB:      {gc.SizeB | gc.LeftRead | RightRdwr | gc.SetCarry, 0, 0, 0},
+	x86.AANDL:      {gc.SizeL | gc.LeftRead | RightRdwr | gc.SetCarry, 0, 0, 0},
+	x86.AANDQ:      {gc.SizeQ | gc.LeftRead | RightRdwr | gc.SetCarry, 0, 0, 0},
+	x86.AANDW:      {gc.SizeW | gc.LeftRead | RightRdwr | gc.SetCarry, 0, 0, 0},
+	obj.ACALL:      {gc.RightAddr | gc.Call | gc.KillCarry, 0, 0, 0},
+	x86.ACDQ:       {gc.OK, AX, AX | DX, 0},
+	x86.ACQO:       {gc.OK, AX, AX | DX, 0},
+	x86.ACWD:       {gc.OK, AX, AX | DX, 0},
+	x86.ACLD:       {gc.OK, 0, 0, 0},
+	x86.ASTD:       {gc.OK, 0, 0, 0},
+	x86.ACMPB:      {gc.SizeB | gc.LeftRead | gc.RightRead | gc.SetCarry, 0, 0, 0},
+	x86.ACMPL:      {gc.SizeL | gc.LeftRead | gc.RightRead | gc.SetCarry, 0, 0, 0},
+	x86.ACMPQ:      {gc.SizeQ | gc.LeftRead | gc.RightRead | gc.SetCarry, 0, 0, 0},
+	x86.ACMPW:      {gc.SizeW | gc.LeftRead | gc.RightRead | gc.SetCarry, 0, 0, 0},
+	x86.ACOMISD:    {gc.SizeD | gc.LeftRead | gc.RightRead | gc.SetCarry, 0, 0, 0},
+	x86.ACOMISS:    {gc.SizeF | gc.LeftRead | gc.RightRead | gc.SetCarry, 0, 0, 0},
+	x86.ACVTSD2SL:  {gc.SizeL | gc.LeftRead | gc.RightWrite | gc.Conv, 0, 0, 0},
+	x86.ACVTSD2SQ:  {gc.SizeQ | gc.LeftRead | gc.RightWrite | gc.Conv, 0, 0, 0},
+	x86.ACVTSD2SS:  {gc.SizeF | gc.LeftRead | gc.RightWrite | gc.Conv, 0, 0, 0},
+	x86.ACVTSL2SD:  {gc.SizeD | gc.LeftRead | gc.RightWrite | gc.Conv, 0, 0, 0},
+	x86.ACVTSL2SS:  {gc.SizeF | gc.LeftRead | gc.RightWrite | gc.Conv, 0, 0, 0},
+	x86.ACVTSQ2SD:  {gc.SizeD | gc.LeftRead | gc.RightWrite | gc.Conv, 0, 0, 0},
+	x86.ACVTSQ2SS:  {gc.SizeF | gc.LeftRead | gc.RightWrite | gc.Conv, 0, 0, 0},
+	x86.ACVTSS2SD:  {gc.SizeD | gc.LeftRead | gc.RightWrite | gc.Conv, 0, 0, 0},
+	x86.ACVTSS2SL:  {gc.SizeL | gc.LeftRead | gc.RightWrite | gc.Conv, 0, 0, 0},
+	x86.ACVTSS2SQ:  {gc.SizeQ | gc.LeftRead | gc.RightWrite | gc.Conv, 0, 0, 0},
+	x86.ACVTTSD2SL: {gc.SizeL | gc.LeftRead | gc.RightWrite | gc.Conv, 0, 0, 0},
+	x86.ACVTTSD2SQ: {gc.SizeQ | gc.LeftRead | gc.RightWrite | gc.Conv, 0, 0, 0},
+	x86.ACVTTSS2SL: {gc.SizeL | gc.LeftRead | gc.RightWrite | gc.Conv, 0, 0, 0},
+	x86.ACVTTSS2SQ: {gc.SizeQ | gc.LeftRead | gc.RightWrite | gc.Conv, 0, 0, 0},
+	x86.ADECB:      {gc.SizeB | RightRdwr, 0, 0, 0},
+	x86.ADECL:      {gc.SizeL | RightRdwr, 0, 0, 0},
+	x86.ADECQ:      {gc.SizeQ | RightRdwr, 0, 0, 0},
+	x86.ADECW:      {gc.SizeW | RightRdwr, 0, 0, 0},
+	x86.ADIVB:      {gc.SizeB | gc.LeftRead | gc.SetCarry, AX, AX, 0},
+	x86.ADIVL:      {gc.SizeL | gc.LeftRead | gc.SetCarry, AX | DX, AX | DX, 0},
+	x86.ADIVQ:      {gc.SizeQ | gc.LeftRead | gc.SetCarry, AX | DX, AX | DX, 0},
+	x86.ADIVW:      {gc.SizeW | gc.LeftRead | gc.SetCarry, AX | DX, AX | DX, 0},
+	x86.ADIVSD:     {gc.SizeD | gc.LeftRead | RightRdwr, 0, 0, 0},
+	x86.ADIVSS:     {gc.SizeF | gc.LeftRead | RightRdwr, 0, 0, 0},
+	x86.AIDIVB:     {gc.SizeB | gc.LeftRead | gc.SetCarry, AX, AX, 0},
+	x86.AIDIVL:     {gc.SizeL | gc.LeftRead | gc.SetCarry, AX | DX, AX | DX, 0},
+	x86.AIDIVQ:     {gc.SizeQ | gc.LeftRead | gc.SetCarry, AX | DX, AX | DX, 0},
+	x86.AIDIVW:     {gc.SizeW | gc.LeftRead | gc.SetCarry, AX | DX, AX | DX, 0},
+	x86.AIMULB:     {gc.SizeB | gc.LeftRead | gc.SetCarry, AX, AX, 0},
+	x86.AIMULL:     {gc.SizeL | gc.LeftRead | gc.ImulAXDX | gc.SetCarry, 0, 0, 0},
+	x86.AIMULQ:     {gc.SizeQ | gc.LeftRead | gc.ImulAXDX | gc.SetCarry, 0, 0, 0},
+	x86.AIMULW:     {gc.SizeW | gc.LeftRead | gc.ImulAXDX | gc.SetCarry, 0, 0, 0},
+	x86.AINCB:      {gc.SizeB | RightRdwr, 0, 0, 0},
+	x86.AINCL:      {gc.SizeL | RightRdwr, 0, 0, 0},
+	x86.AINCQ:      {gc.SizeQ | RightRdwr, 0, 0, 0},
+	x86.AINCW:      {gc.SizeW | RightRdwr, 0, 0, 0},
+	x86.AJCC:       {gc.Cjmp | gc.UseCarry, 0, 0, 0},
+	x86.AJCS:       {gc.Cjmp | gc.UseCarry, 0, 0, 0},
+	x86.AJEQ:       {gc.Cjmp | gc.UseCarry, 0, 0, 0},
+	x86.AJGE:       {gc.Cjmp | gc.UseCarry, 0, 0, 0},
+	x86.AJGT:       {gc.Cjmp | gc.UseCarry, 0, 0, 0},
+	x86.AJHI:       {gc.Cjmp | gc.UseCarry, 0, 0, 0},
+	x86.AJLE:       {gc.Cjmp | gc.UseCarry, 0, 0, 0},
+	x86.AJLS:       {gc.Cjmp | gc.UseCarry, 0, 0, 0},
+	x86.AJLT:       {gc.Cjmp | gc.UseCarry, 0, 0, 0},
+	x86.AJMI:       {gc.Cjmp | gc.UseCarry, 0, 0, 0},
+	x86.AJNE:       {gc.Cjmp | gc.UseCarry, 0, 0, 0},
+	x86.AJOC:       {gc.Cjmp | gc.UseCarry, 0, 0, 0},
+	x86.AJOS:       {gc.Cjmp | gc.UseCarry, 0, 0, 0},
+	x86.AJPC:       {gc.Cjmp | gc.UseCarry, 0, 0, 0},
+	x86.AJPL:       {gc.Cjmp | gc.UseCarry, 0, 0, 0},
+	x86.AJPS:       {gc.Cjmp | gc.UseCarry, 0, 0, 0},
+	obj.AJMP:       {gc.Jump | gc.Break | gc.KillCarry, 0, 0, 0},
+	x86.ALEAL:      {gc.LeftAddr | gc.RightWrite, 0, 0, 0},
+	x86.ALEAQ:      {gc.LeftAddr | gc.RightWrite, 0, 0, 0},
+	x86.AMOVBLSX:   {gc.SizeL | gc.LeftRead | gc.RightWrite | gc.Conv, 0, 0, 0},
+	x86.AMOVBLZX:   {gc.SizeL | gc.LeftRead | gc.RightWrite | gc.Conv, 0, 0, 0},
+	x86.AMOVBQSX:   {gc.SizeQ | gc.LeftRead | gc.RightWrite | gc.Conv, 0, 0, 0},
+	x86.AMOVBQZX:   {gc.SizeQ | gc.LeftRead | gc.RightWrite | gc.Conv, 0, 0, 0},
+	x86.AMOVBWSX:   {gc.SizeW | gc.LeftRead | gc.RightWrite | gc.Conv, 0, 0, 0},
+	x86.AMOVBWZX:   {gc.SizeW | gc.LeftRead | gc.RightWrite | gc.Conv, 0, 0, 0},
+	x86.AMOVLQSX:   {gc.SizeQ | gc.LeftRead | gc.RightWrite | gc.Conv, 0, 0, 0},
+	x86.AMOVLQZX:   {gc.SizeQ | gc.LeftRead | gc.RightWrite | gc.Conv, 0, 0, 0},
+	x86.AMOVWLSX:   {gc.SizeL | gc.LeftRead | gc.RightWrite | gc.Conv, 0, 0, 0},
+	x86.AMOVWLZX:   {gc.SizeL | gc.LeftRead | gc.RightWrite | gc.Conv, 0, 0, 0},
+	x86.AMOVWQSX:   {gc.SizeQ | gc.LeftRead | gc.RightWrite | gc.Conv, 0, 0, 0},
+	x86.AMOVWQZX:   {gc.SizeQ | gc.LeftRead | gc.RightWrite | gc.Conv, 0, 0, 0},
+	x86.AMOVQL:     {gc.SizeL | gc.LeftRead | gc.RightWrite | gc.Conv, 0, 0, 0},
+	x86.AMOVB:      {gc.SizeB | gc.LeftRead | gc.RightWrite | gc.Move, 0, 0, 0},
+	x86.AMOVL:      {gc.SizeL | gc.LeftRead | gc.RightWrite | gc.Move, 0, 0, 0},
+	x86.AMOVQ:      {gc.SizeQ | gc.LeftRead | gc.RightWrite | gc.Move, 0, 0, 0},
+	x86.AMOVW:      {gc.SizeW | gc.LeftRead | gc.RightWrite | gc.Move, 0, 0, 0},
+	x86.AMOVSB:     {gc.OK, DI | SI, DI | SI, 0},
+	x86.AMOVSL:     {gc.OK, DI | SI, DI | SI, 0},
+	x86.AMOVSQ:     {gc.OK, DI | SI, DI | SI, 0},
+	x86.AMOVSW:     {gc.OK, DI | SI, DI | SI, 0},
+	obj.ADUFFCOPY:  {gc.OK, DI | SI, DI | SI | CX, 0},
+	x86.AMOVSD:     {gc.SizeD | gc.LeftRead | gc.RightWrite | gc.Move, 0, 0, 0},
+	x86.AMOVSS:     {gc.SizeF | gc.LeftRead | gc.RightWrite | gc.Move, 0, 0, 0},
 
 	// We use MOVAPD as a faster synonym for MOVSD.
-	x86.AMOVAPD:   gc.ProgInfo{gc.SizeD | gc.LeftRead | gc.RightWrite | gc.Move, 0, 0, 0},
-	x86.AMULB:     gc.ProgInfo{gc.SizeB | gc.LeftRead | gc.SetCarry, AX, AX, 0},
-	x86.AMULL:     gc.ProgInfo{gc.SizeL | gc.LeftRead | gc.SetCarry, AX, AX | DX, 0},
-	x86.AMULQ:     gc.ProgInfo{gc.SizeQ | gc.LeftRead | gc.SetCarry, AX, AX | DX, 0},
-	x86.AMULW:     gc.ProgInfo{gc.SizeW | gc.LeftRead | gc.SetCarry, AX, AX | DX, 0},
-	x86.AMULSD:    gc.ProgInfo{gc.SizeD | gc.LeftRead | RightRdwr, 0, 0, 0},
-	x86.AMULSS:    gc.ProgInfo{gc.SizeF | gc.LeftRead | RightRdwr, 0, 0, 0},
-	x86.ANEGB:     gc.ProgInfo{gc.SizeB | RightRdwr | gc.SetCarry, 0, 0, 0},
-	x86.ANEGL:     gc.ProgInfo{gc.SizeL | RightRdwr | gc.SetCarry, 0, 0, 0},
-	x86.ANEGQ:     gc.ProgInfo{gc.SizeQ | RightRdwr | gc.SetCarry, 0, 0, 0},
-	x86.ANEGW:     gc.ProgInfo{gc.SizeW | RightRdwr | gc.SetCarry, 0, 0, 0},
-	x86.ANOTB:     gc.ProgInfo{gc.SizeB | RightRdwr, 0, 0, 0},
-	x86.ANOTL:     gc.ProgInfo{gc.SizeL | RightRdwr, 0, 0, 0},
-	x86.ANOTQ:     gc.ProgInfo{gc.SizeQ | RightRdwr, 0, 0, 0},
-	x86.ANOTW:     gc.ProgInfo{gc.SizeW | RightRdwr, 0, 0, 0},
-	x86.AORB:      gc.ProgInfo{gc.SizeB | gc.LeftRead | RightRdwr | gc.SetCarry, 0, 0, 0},
-	x86.AORL:      gc.ProgInfo{gc.SizeL | gc.LeftRead | RightRdwr | gc.SetCarry, 0, 0, 0},
-	x86.AORQ:      gc.ProgInfo{gc.SizeQ | gc.LeftRead | RightRdwr | gc.SetCarry, 0, 0, 0},
-	x86.AORW:      gc.ProgInfo{gc.SizeW | gc.LeftRead | RightRdwr | gc.SetCarry, 0, 0, 0},
-	x86.APOPQ:     gc.ProgInfo{gc.SizeQ | gc.RightWrite, 0, 0, 0},
-	x86.APUSHQ:    gc.ProgInfo{gc.SizeQ | gc.LeftRead, 0, 0, 0},
-	x86.ARCLB:     gc.ProgInfo{gc.SizeB | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry | gc.UseCarry, 0, 0, 0},
-	x86.ARCLL:     gc.ProgInfo{gc.SizeL | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry | gc.UseCarry, 0, 0, 0},
-	x86.ARCLQ:     gc.ProgInfo{gc.SizeQ | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry | gc.UseCarry, 0, 0, 0},
-	x86.ARCLW:     gc.ProgInfo{gc.SizeW | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry | gc.UseCarry, 0, 0, 0},
-	x86.ARCRB:     gc.ProgInfo{gc.SizeB | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry | gc.UseCarry, 0, 0, 0},
-	x86.ARCRL:     gc.ProgInfo{gc.SizeL | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry | gc.UseCarry, 0, 0, 0},
-	x86.ARCRQ:     gc.ProgInfo{gc.SizeQ | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry | gc.UseCarry, 0, 0, 0},
-	x86.ARCRW:     gc.ProgInfo{gc.SizeW | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry | gc.UseCarry, 0, 0, 0},
-	x86.AREP:      gc.ProgInfo{gc.OK, CX, CX, 0},
-	x86.AREPN:     gc.ProgInfo{gc.OK, CX, CX, 0},
-	obj.ARET:      gc.ProgInfo{gc.Break | gc.KillCarry, 0, 0, 0},
-	x86.AROLB:     gc.ProgInfo{gc.SizeB | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry, 0, 0, 0},
-	x86.AROLL:     gc.ProgInfo{gc.SizeL | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry, 0, 0, 0},
-	x86.AROLQ:     gc.ProgInfo{gc.SizeQ | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry, 0, 0, 0},
-	x86.AROLW:     gc.ProgInfo{gc.SizeW | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry, 0, 0, 0},
-	x86.ARORB:     gc.ProgInfo{gc.SizeB | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry, 0, 0, 0},
-	x86.ARORL:     gc.ProgInfo{gc.SizeL | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry, 0, 0, 0},
-	x86.ARORQ:     gc.ProgInfo{gc.SizeQ | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry, 0, 0, 0},
-	x86.ARORW:     gc.ProgInfo{gc.SizeW | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry, 0, 0, 0},
-	x86.ASALB:     gc.ProgInfo{gc.SizeB | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry, 0, 0, 0},
-	x86.ASALL:     gc.ProgInfo{gc.SizeL | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry, 0, 0, 0},
-	x86.ASALQ:     gc.ProgInfo{gc.SizeQ | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry, 0, 0, 0},
-	x86.ASALW:     gc.ProgInfo{gc.SizeW | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry, 0, 0, 0},
-	x86.ASARB:     gc.ProgInfo{gc.SizeB | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry, 0, 0, 0},
-	x86.ASARL:     gc.ProgInfo{gc.SizeL | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry, 0, 0, 0},
-	x86.ASARQ:     gc.ProgInfo{gc.SizeQ | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry, 0, 0, 0},
-	x86.ASARW:     gc.ProgInfo{gc.SizeW | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry, 0, 0, 0},
-	x86.ASBBB:     gc.ProgInfo{gc.SizeB | gc.LeftRead | RightRdwr | gc.SetCarry | gc.UseCarry, 0, 0, 0},
-	x86.ASBBL:     gc.ProgInfo{gc.SizeL | gc.LeftRead | RightRdwr | gc.SetCarry | gc.UseCarry, 0, 0, 0},
-	x86.ASBBQ:     gc.ProgInfo{gc.SizeQ | gc.LeftRead | RightRdwr | gc.SetCarry | gc.UseCarry, 0, 0, 0},
-	x86.ASBBW:     gc.ProgInfo{gc.SizeW | gc.LeftRead | RightRdwr | gc.SetCarry | gc.UseCarry, 0, 0, 0},
-	x86.ASHLB:     gc.ProgInfo{gc.SizeB | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry, 0, 0, 0},
-	x86.ASHLL:     gc.ProgInfo{gc.SizeL | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry, 0, 0, 0},
-	x86.ASHLQ:     gc.ProgInfo{gc.SizeQ | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry, 0, 0, 0},
-	x86.ASHLW:     gc.ProgInfo{gc.SizeW | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry, 0, 0, 0},
-	x86.ASHRB:     gc.ProgInfo{gc.SizeB | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry, 0, 0, 0},
-	x86.ASHRL:     gc.ProgInfo{gc.SizeL | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry, 0, 0, 0},
-	x86.ASHRQ:     gc.ProgInfo{gc.SizeQ | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry, 0, 0, 0},
-	x86.ASHRW:     gc.ProgInfo{gc.SizeW | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry, 0, 0, 0},
-	x86.ASTOSB:    gc.ProgInfo{gc.OK, AX | DI, DI, 0},
-	x86.ASTOSL:    gc.ProgInfo{gc.OK, AX | DI, DI, 0},
-	x86.ASTOSQ:    gc.ProgInfo{gc.OK, AX | DI, DI, 0},
-	x86.ASTOSW:    gc.ProgInfo{gc.OK, AX | DI, DI, 0},
-	obj.ADUFFZERO: gc.ProgInfo{gc.OK, AX | DI, DI, 0},
-	x86.ASUBB:     gc.ProgInfo{gc.SizeB | gc.LeftRead | RightRdwr | gc.SetCarry, 0, 0, 0},
-	x86.ASUBL:     gc.ProgInfo{gc.SizeL | gc.LeftRead | RightRdwr | gc.SetCarry, 0, 0, 0},
-	x86.ASUBQ:     gc.ProgInfo{gc.SizeQ | gc.LeftRead | RightRdwr | gc.SetCarry, 0, 0, 0},
-	x86.ASUBW:     gc.ProgInfo{gc.SizeW | gc.LeftRead | RightRdwr | gc.SetCarry, 0, 0, 0},
-	x86.ASUBSD:    gc.ProgInfo{gc.SizeD | gc.LeftRead | RightRdwr, 0, 0, 0},
-	x86.ASUBSS:    gc.ProgInfo{gc.SizeF | gc.LeftRead | RightRdwr, 0, 0, 0},
-	x86.ATESTB:    gc.ProgInfo{gc.SizeB | gc.LeftRead | gc.RightRead | gc.SetCarry, 0, 0, 0},
-	x86.ATESTL:    gc.ProgInfo{gc.SizeL | gc.LeftRead | gc.RightRead | gc.SetCarry, 0, 0, 0},
-	x86.ATESTQ:    gc.ProgInfo{gc.SizeQ | gc.LeftRead | gc.RightRead | gc.SetCarry, 0, 0, 0},
-	x86.ATESTW:    gc.ProgInfo{gc.SizeW | gc.LeftRead | gc.RightRead | gc.SetCarry, 0, 0, 0},
-	x86.AUCOMISD:  gc.ProgInfo{gc.SizeD | gc.LeftRead | gc.RightRead, 0, 0, 0},
-	x86.AUCOMISS:  gc.ProgInfo{gc.SizeF | gc.LeftRead | gc.RightRead, 0, 0, 0},
-	x86.AXCHGB:    gc.ProgInfo{gc.SizeB | LeftRdwr | RightRdwr, 0, 0, 0},
-	x86.AXCHGL:    gc.ProgInfo{gc.SizeL | LeftRdwr | RightRdwr, 0, 0, 0},
-	x86.AXCHGQ:    gc.ProgInfo{gc.SizeQ | LeftRdwr | RightRdwr, 0, 0, 0},
-	x86.AXCHGW:    gc.ProgInfo{gc.SizeW | LeftRdwr | RightRdwr, 0, 0, 0},
-	x86.AXORB:     gc.ProgInfo{gc.SizeB | gc.LeftRead | RightRdwr | gc.SetCarry, 0, 0, 0},
-	x86.AXORL:     gc.ProgInfo{gc.SizeL | gc.LeftRead | RightRdwr | gc.SetCarry, 0, 0, 0},
-	x86.AXORQ:     gc.ProgInfo{gc.SizeQ | gc.LeftRead | RightRdwr | gc.SetCarry, 0, 0, 0},
-	x86.AXORW:     gc.ProgInfo{gc.SizeW | gc.LeftRead | RightRdwr | gc.SetCarry, 0, 0, 0},
+	x86.AMOVAPD:   {gc.SizeD | gc.LeftRead | gc.RightWrite | gc.Move, 0, 0, 0},
+	x86.AMULB:     {gc.SizeB | gc.LeftRead | gc.SetCarry, AX, AX, 0},
+	x86.AMULL:     {gc.SizeL | gc.LeftRead | gc.SetCarry, AX, AX | DX, 0},
+	x86.AMULQ:     {gc.SizeQ | gc.LeftRead | gc.SetCarry, AX, AX | DX, 0},
+	x86.AMULW:     {gc.SizeW | gc.LeftRead | gc.SetCarry, AX, AX | DX, 0},
+	x86.AMULSD:    {gc.SizeD | gc.LeftRead | RightRdwr, 0, 0, 0},
+	x86.AMULSS:    {gc.SizeF | gc.LeftRead | RightRdwr, 0, 0, 0},
+	x86.ANEGB:     {gc.SizeB | RightRdwr | gc.SetCarry, 0, 0, 0},
+	x86.ANEGL:     {gc.SizeL | RightRdwr | gc.SetCarry, 0, 0, 0},
+	x86.ANEGQ:     {gc.SizeQ | RightRdwr | gc.SetCarry, 0, 0, 0},
+	x86.ANEGW:     {gc.SizeW | RightRdwr | gc.SetCarry, 0, 0, 0},
+	x86.ANOTB:     {gc.SizeB | RightRdwr, 0, 0, 0},
+	x86.ANOTL:     {gc.SizeL | RightRdwr, 0, 0, 0},
+	x86.ANOTQ:     {gc.SizeQ | RightRdwr, 0, 0, 0},
+	x86.ANOTW:     {gc.SizeW | RightRdwr, 0, 0, 0},
+	x86.AORB:      {gc.SizeB | gc.LeftRead | RightRdwr | gc.SetCarry, 0, 0, 0},
+	x86.AORL:      {gc.SizeL | gc.LeftRead | RightRdwr | gc.SetCarry, 0, 0, 0},
+	x86.AORQ:      {gc.SizeQ | gc.LeftRead | RightRdwr | gc.SetCarry, 0, 0, 0},
+	x86.AORW:      {gc.SizeW | gc.LeftRead | RightRdwr | gc.SetCarry, 0, 0, 0},
+	x86.APOPQ:     {gc.SizeQ | gc.RightWrite, 0, 0, 0},
+	x86.APUSHQ:    {gc.SizeQ | gc.LeftRead, 0, 0, 0},
+	x86.ARCLB:     {gc.SizeB | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry | gc.UseCarry, 0, 0, 0},
+	x86.ARCLL:     {gc.SizeL | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry | gc.UseCarry, 0, 0, 0},
+	x86.ARCLQ:     {gc.SizeQ | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry | gc.UseCarry, 0, 0, 0},
+	x86.ARCLW:     {gc.SizeW | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry | gc.UseCarry, 0, 0, 0},
+	x86.ARCRB:     {gc.SizeB | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry | gc.UseCarry, 0, 0, 0},
+	x86.ARCRL:     {gc.SizeL | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry | gc.UseCarry, 0, 0, 0},
+	x86.ARCRQ:     {gc.SizeQ | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry | gc.UseCarry, 0, 0, 0},
+	x86.ARCRW:     {gc.SizeW | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry | gc.UseCarry, 0, 0, 0},
+	x86.AREP:      {gc.OK, CX, CX, 0},
+	x86.AREPN:     {gc.OK, CX, CX, 0},
+	obj.ARET:      {gc.Break | gc.KillCarry, 0, 0, 0},
+	x86.AROLB:     {gc.SizeB | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry, 0, 0, 0},
+	x86.AROLL:     {gc.SizeL | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry, 0, 0, 0},
+	x86.AROLQ:     {gc.SizeQ | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry, 0, 0, 0},
+	x86.AROLW:     {gc.SizeW | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry, 0, 0, 0},
+	x86.ARORB:     {gc.SizeB | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry, 0, 0, 0},
+	x86.ARORL:     {gc.SizeL | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry, 0, 0, 0},
+	x86.ARORQ:     {gc.SizeQ | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry, 0, 0, 0},
+	x86.ARORW:     {gc.SizeW | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry, 0, 0, 0},
+	x86.ASALB:     {gc.SizeB | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry, 0, 0, 0},
+	x86.ASALL:     {gc.SizeL | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry, 0, 0, 0},
+	x86.ASALQ:     {gc.SizeQ | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry, 0, 0, 0},
+	x86.ASALW:     {gc.SizeW | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry, 0, 0, 0},
+	x86.ASARB:     {gc.SizeB | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry, 0, 0, 0},
+	x86.ASARL:     {gc.SizeL | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry, 0, 0, 0},
+	x86.ASARQ:     {gc.SizeQ | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry, 0, 0, 0},
+	x86.ASARW:     {gc.SizeW | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry, 0, 0, 0},
+	x86.ASBBB:     {gc.SizeB | gc.LeftRead | RightRdwr | gc.SetCarry | gc.UseCarry, 0, 0, 0},
+	x86.ASBBL:     {gc.SizeL | gc.LeftRead | RightRdwr | gc.SetCarry | gc.UseCarry, 0, 0, 0},
+	x86.ASBBQ:     {gc.SizeQ | gc.LeftRead | RightRdwr | gc.SetCarry | gc.UseCarry, 0, 0, 0},
+	x86.ASBBW:     {gc.SizeW | gc.LeftRead | RightRdwr | gc.SetCarry | gc.UseCarry, 0, 0, 0},
+	x86.ASHLB:     {gc.SizeB | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry, 0, 0, 0},
+	x86.ASHLL:     {gc.SizeL | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry, 0, 0, 0},
+	x86.ASHLQ:     {gc.SizeQ | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry, 0, 0, 0},
+	x86.ASHLW:     {gc.SizeW | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry, 0, 0, 0},
+	x86.ASHRB:     {gc.SizeB | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry, 0, 0, 0},
+	x86.ASHRL:     {gc.SizeL | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry, 0, 0, 0},
+	x86.ASHRQ:     {gc.SizeQ | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry, 0, 0, 0},
+	x86.ASHRW:     {gc.SizeW | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry, 0, 0, 0},
+	x86.ASTOSB:    {gc.OK, AX | DI, DI, 0},
+	x86.ASTOSL:    {gc.OK, AX | DI, DI, 0},
+	x86.ASTOSQ:    {gc.OK, AX | DI, DI, 0},
+	x86.ASTOSW:    {gc.OK, AX | DI, DI, 0},
+	obj.ADUFFZERO: {gc.OK, AX | DI, DI, 0},
+	x86.ASUBB:     {gc.SizeB | gc.LeftRead | RightRdwr | gc.SetCarry, 0, 0, 0},
+	x86.ASUBL:     {gc.SizeL | gc.LeftRead | RightRdwr | gc.SetCarry, 0, 0, 0},
+	x86.ASUBQ:     {gc.SizeQ | gc.LeftRead | RightRdwr | gc.SetCarry, 0, 0, 0},
+	x86.ASUBW:     {gc.SizeW | gc.LeftRead | RightRdwr | gc.SetCarry, 0, 0, 0},
+	x86.ASUBSD:    {gc.SizeD | gc.LeftRead | RightRdwr, 0, 0, 0},
+	x86.ASUBSS:    {gc.SizeF | gc.LeftRead | RightRdwr, 0, 0, 0},
+	x86.ATESTB:    {gc.SizeB | gc.LeftRead | gc.RightRead | gc.SetCarry, 0, 0, 0},
+	x86.ATESTL:    {gc.SizeL | gc.LeftRead | gc.RightRead | gc.SetCarry, 0, 0, 0},
+	x86.ATESTQ:    {gc.SizeQ | gc.LeftRead | gc.RightRead | gc.SetCarry, 0, 0, 0},
+	x86.ATESTW:    {gc.SizeW | gc.LeftRead | gc.RightRead | gc.SetCarry, 0, 0, 0},
+	x86.AUCOMISD:  {gc.SizeD | gc.LeftRead | gc.RightRead, 0, 0, 0},
+	x86.AUCOMISS:  {gc.SizeF | gc.LeftRead | gc.RightRead, 0, 0, 0},
+	x86.AXCHGB:    {gc.SizeB | LeftRdwr | RightRdwr, 0, 0, 0},
+	x86.AXCHGL:    {gc.SizeL | LeftRdwr | RightRdwr, 0, 0, 0},
+	x86.AXCHGQ:    {gc.SizeQ | LeftRdwr | RightRdwr, 0, 0, 0},
+	x86.AXCHGW:    {gc.SizeW | LeftRdwr | RightRdwr, 0, 0, 0},
+	x86.AXORB:     {gc.SizeB | gc.LeftRead | RightRdwr | gc.SetCarry, 0, 0, 0},
+	x86.AXORL:     {gc.SizeL | gc.LeftRead | RightRdwr | gc.SetCarry, 0, 0, 0},
+	x86.AXORQ:     {gc.SizeQ | gc.LeftRead | RightRdwr | gc.SetCarry, 0, 0, 0},
+	x86.AXORW:     {gc.SizeW | gc.LeftRead | RightRdwr | gc.SetCarry, 0, 0, 0},
 }
 
-func proginfo(info *gc.ProgInfo, p *obj.Prog) {
+func progflags(p *obj.Prog) uint32 {
+	flags := progtable[p.As].Flags
+	if flags&gc.ImulAXDX != 0 && p.To.Type != obj.TYPE_NONE {
+		flags |= RightRdwr
+	}
+	return flags
+}
+
+func progcarryflags(p *obj.Prog) uint32 {
+	return progtable[p.As].Flags
+}
+
+func proginfo(p *obj.Prog) {
+	info := &p.Info
 	*info = progtable[p.As]
 	if info.Flags == 0 {
 		gc.Fatal("unknown instruction %v", p)
diff --git a/src/cmd/6g/reg.go b/src/cmd/6g/reg.go
index 3c5a699..dd06bc5 100644
--- a/src/cmd/6g/reg.go
+++ b/src/cmd/6g/reg.go
@@ -31,10 +31,10 @@
 package main
 
 import (
+	"cmd/internal/gc"
 	"cmd/internal/obj"
 	"cmd/internal/obj/x86"
 )
-import "cmd/internal/gc"
 
 const (
 	NREGVAR = 32
@@ -98,6 +98,16 @@
 	return b
 }
 
+// For ProgInfo.
+const (
+	AX = 1 << (x86.REG_AX - x86.REG_AX)
+	BX = 1 << (x86.REG_BX - x86.REG_AX)
+	CX = 1 << (x86.REG_CX - x86.REG_AX)
+	DX = 1 << (x86.REG_DX - x86.REG_AX)
+	DI = 1 << (x86.REG_DI - x86.REG_AX)
+	SI = 1 << (x86.REG_SI - x86.REG_AX)
+)
+
 func RtoB(r int) uint64 {
 	if r < x86.REG_AX || r > x86.REG_R15 {
 		return 0
diff --git a/src/cmd/6l/asm.go b/src/cmd/6l/asm.go
index 72e9dbf..1df166f 100644
--- a/src/cmd/6l/asm.go
+++ b/src/cmd/6l/asm.go
@@ -31,11 +31,11 @@
 package main
 
 import (
+	"cmd/internal/ld"
 	"cmd/internal/obj"
 	"fmt"
 	"log"
 )
-import "cmd/internal/ld"
 
 func PADDR(x uint32) uint32 {
 	return x &^ 0x80000000
@@ -44,17 +44,14 @@
 var zeroes string
 
 func needlib(name string) int {
-	var p string
-	var s *ld.LSym
-
 	if name[0] == '\x00' {
 		return 0
 	}
 
 	/* reuse hash code in symbol table */
-	p = fmt.Sprintf(".elfload.%s", name)
+	p := fmt.Sprintf(".elfload.%s", name)
 
-	s = ld.Linklookup(ld.Ctxt, p, 0)
+	s := ld.Linklookup(ld.Ctxt, p, 0)
 
 	if s.Type == 0 {
 		s.Type = 100 // avoid SDATA, etc.
@@ -74,11 +71,7 @@
 }
 
 func adddynrel(s *ld.LSym, r *ld.Reloc) {
-	var targ *ld.LSym
-	var rela *ld.LSym
-	var got *ld.LSym
-
-	targ = r.Sym
+	targ := r.Sym
 	ld.Ctxt.Cursym = s
 
 	switch r.Type {
@@ -141,11 +134,11 @@
 		r.Type = ld.R_ADDR
 		return
 
-		// TODO: What is the difference between all these?
 	// Handle relocations found in Mach-O object files.
 	case 512 + ld.MACHO_X86_64_RELOC_UNSIGNED*2 + 0,
 		512 + ld.MACHO_X86_64_RELOC_SIGNED*2 + 0,
 		512 + ld.MACHO_X86_64_RELOC_BRANCH*2 + 0:
+		// TODO: What is the difference between all these?
 		r.Type = ld.R_ADDR
 
 		if targ.Type == ld.SDYNIMPORT {
@@ -211,10 +204,16 @@
 	switch r.Type {
 	case ld.R_CALL,
 		ld.R_PCREL:
-		addpltsym(targ)
-		r.Sym = ld.Linklookup(ld.Ctxt, ".plt", 0)
-		r.Add = int64(targ.Plt)
-		return
+		if ld.HEADTYPE == ld.Hwindows {
+			// nothing to do, the relocation will be laid out in pereloc1
+			return
+		} else {
+			// for both ELF and Mach-O
+			addpltsym(targ)
+			r.Sym = ld.Linklookup(ld.Ctxt, ".plt", 0)
+			r.Add = int64(targ.Plt)
+			return
+		}
 
 	case ld.R_ADDR:
 		if s.Type == ld.STEXT && ld.Iself {
@@ -233,7 +232,7 @@
 		}
 		if ld.Iself {
 			adddynsym(ld.Ctxt, targ)
-			rela = ld.Linklookup(ld.Ctxt, ".rela", 0)
+			rela := ld.Linklookup(ld.Ctxt, ".rela", 0)
 			ld.Addaddrplus(ld.Ctxt, rela, s, int64(r.Off))
 			if r.Siz == 8 {
 				ld.Adduint64(ld.Ctxt, rela, ld.ELF64_R_INFO(uint32(targ.Dynid), ld.R_X86_64_64))
@@ -258,7 +257,7 @@
 			// but we only need to support cgo and that's all it needs.
 			adddynsym(ld.Ctxt, targ)
 
-			got = ld.Linklookup(ld.Ctxt, ".got", 0)
+			got := ld.Linklookup(ld.Ctxt, ".got", 0)
 			s.Type = got.Type | ld.SSUB
 			s.Outer = got
 			s.Sub = got.Sub
@@ -269,6 +268,11 @@
 			r.Type = 256 // ignore during relocsym
 			return
 		}
+
+		if ld.HEADTYPE == ld.Hwindows {
+			// nothing to do, the relocation will be laid out in pereloc1
+			return
+		}
 	}
 
 	ld.Ctxt.Cursym = s
@@ -276,11 +280,9 @@
 }
 
 func elfreloc1(r *ld.Reloc, sectoff int64) int {
-	var elfsym int32
-
 	ld.Thearch.Vput(uint64(sectoff))
 
-	elfsym = r.Xsym.Elfsym
+	elfsym := r.Xsym.Elfsym
 	switch r.Type {
 	default:
 		return -1
@@ -301,6 +303,13 @@
 			return -1
 		}
 
+	case ld.R_TLS_IE:
+		if r.Siz == 4 {
+			ld.Thearch.Vput(ld.R_X86_64_GOTTPOFF | uint64(elfsym)<<32)
+		} else {
+			return -1
+		}
+
 	case ld.R_CALL:
 		if r.Siz == 4 {
 			if r.Xsym.Type == ld.SDYNIMPORT {
@@ -337,9 +346,8 @@
 
 func machoreloc1(r *ld.Reloc, sectoff int64) int {
 	var v uint32
-	var rs *ld.LSym
 
-	rs = r.Xsym
+	rs := r.Xsym
 
 	if rs.Type == ld.SHOSTOBJ || r.Type == ld.R_PCREL {
 		if rs.Dynid < 0 {
@@ -396,6 +404,40 @@
 	return 0
 }
 
+func pereloc1(r *ld.Reloc, sectoff int64) bool {
+	var v uint32
+
+	rs := r.Xsym
+
+	if rs.Dynid < 0 {
+		ld.Diag("reloc %d to non-coff symbol %s type=%d", r.Type, rs.Name, rs.Type)
+		return false
+	}
+
+	ld.Thearch.Lput(uint32(sectoff))
+	ld.Thearch.Lput(uint32(rs.Dynid))
+
+	switch r.Type {
+	default:
+		return false
+
+	case ld.R_ADDR:
+		if r.Siz == 8 {
+			v = ld.IMAGE_REL_AMD64_ADDR64
+		} else {
+			v = ld.IMAGE_REL_AMD64_ADDR32
+		}
+
+	case ld.R_CALL,
+		ld.R_PCREL:
+		v = ld.IMAGE_REL_AMD64_REL32
+	}
+
+	ld.Thearch.Wput(uint16(v))
+
+	return true
+}
+
 func archreloc(r *ld.Reloc, s *ld.LSym, val *int64) int {
 	return -1
 }
@@ -406,11 +448,8 @@
 }
 
 func elfsetupplt() {
-	var plt *ld.LSym
-	var got *ld.LSym
-
-	plt = ld.Linklookup(ld.Ctxt, ".plt", 0)
-	got = ld.Linklookup(ld.Ctxt, ".got.plt", 0)
+	plt := ld.Linklookup(ld.Ctxt, ".plt", 0)
+	got := ld.Linklookup(ld.Ctxt, ".got.plt", 0)
 	if plt.Size == 0 {
 		// pushq got+8(IP)
 		ld.Adduint8(ld.Ctxt, plt, 0xff)
@@ -443,13 +482,9 @@
 	adddynsym(ld.Ctxt, s)
 
 	if ld.Iself {
-		var plt *ld.LSym
-		var got *ld.LSym
-		var rela *ld.LSym
-
-		plt = ld.Linklookup(ld.Ctxt, ".plt", 0)
-		got = ld.Linklookup(ld.Ctxt, ".got.plt", 0)
-		rela = ld.Linklookup(ld.Ctxt, ".rela.plt", 0)
+		plt := ld.Linklookup(ld.Ctxt, ".plt", 0)
+		got := ld.Linklookup(ld.Ctxt, ".got.plt", 0)
+		rela := ld.Linklookup(ld.Ctxt, ".rela.plt", 0)
 		if plt.Size == 0 {
 			elfsetupplt()
 		}
@@ -491,10 +526,8 @@
 		// http://networkpx.blogspot.com/2009/09/about-lcdyldinfoonly-command.html
 		// has details about what we're avoiding.
 
-		var plt *ld.LSym
-
 		addgotsym(s)
-		plt = ld.Linklookup(ld.Ctxt, ".plt", 0)
+		plt := ld.Linklookup(ld.Ctxt, ".plt", 0)
 
 		ld.Adduint32(ld.Ctxt, ld.Linklookup(ld.Ctxt, ".linkedit.plt", 0), uint32(s.Dynid))
 
@@ -510,20 +543,17 @@
 }
 
 func addgotsym(s *ld.LSym) {
-	var got *ld.LSym
-	var rela *ld.LSym
-
 	if s.Got >= 0 {
 		return
 	}
 
 	adddynsym(ld.Ctxt, s)
-	got = ld.Linklookup(ld.Ctxt, ".got", 0)
+	got := ld.Linklookup(ld.Ctxt, ".got", 0)
 	s.Got = int32(got.Size)
 	ld.Adduint64(ld.Ctxt, got, 0)
 
 	if ld.Iself {
-		rela = ld.Linklookup(ld.Ctxt, ".rela", 0)
+		rela := ld.Linklookup(ld.Ctxt, ".rela", 0)
 		ld.Addaddrplus(ld.Ctxt, rela, got, int64(s.Got))
 		ld.Adduint64(ld.Ctxt, rela, ld.ELF64_R_INFO(uint32(s.Dynid), ld.R_X86_64_GLOB_DAT))
 		ld.Adduint64(ld.Ctxt, rela, 0)
@@ -535,10 +565,6 @@
 }
 
 func adddynsym(ctxt *ld.Link, s *ld.LSym) {
-	var d *ld.LSym
-	var t int
-	var name string
-
 	if s.Dynid >= 0 {
 		return
 	}
@@ -547,13 +573,13 @@
 		s.Dynid = int32(ld.Nelfsym)
 		ld.Nelfsym++
 
-		d = ld.Linklookup(ctxt, ".dynsym", 0)
+		d := ld.Linklookup(ctxt, ".dynsym", 0)
 
-		name = s.Extname
+		name := s.Extname
 		ld.Adduint32(ctxt, d, uint32(ld.Addstring(ld.Linklookup(ctxt, ".dynstr", 0), name)))
 
 		/* type */
-		t = ld.STB_GLOBAL << 4
+		t := ld.STB_GLOBAL << 4
 
 		if s.Cgoexport != 0 && s.Type&ld.SMASK == ld.STEXT {
 			t |= ld.STT_FUNC
@@ -595,14 +621,12 @@
 }
 
 func adddynlib(lib string) {
-	var s *ld.LSym
-
 	if needlib(lib) == 0 {
 		return
 	}
 
 	if ld.Iself {
-		s = ld.Linklookup(ld.Ctxt, ".dynstr", 0)
+		s := ld.Linklookup(ld.Ctxt, ".dynstr", 0)
 		if s.Size == 0 {
 			ld.Addstring(s, "")
 		}
@@ -615,15 +639,6 @@
 }
 
 func asmb() {
-	var magic int32
-	var i int
-	var vl int64
-	var symo int64
-	var dwarfoff int64
-	var machlink int64
-	var sect *ld.Section
-	var sym *ld.LSym
-
 	if ld.Debug['v'] != 0 {
 		fmt.Fprintf(&ld.Bso, "%5.2f asmb\n", obj.Cputime())
 	}
@@ -638,7 +653,7 @@
 		ld.Asmbelfsetup()
 	}
 
-	sect = ld.Segtext.Sect
+	sect := ld.Segtext.Sect
 	ld.Cseek(int64(sect.Vaddr - ld.Segtext.Vaddr + ld.Segtext.Fileoff))
 	ld.Codeblk(int64(sect.Vaddr), int64(sect.Length))
 	for sect = sect.Next; sect != nil; sect = sect.Next {
@@ -664,13 +679,13 @@
 	ld.Cseek(int64(ld.Segdata.Fileoff))
 	ld.Datblk(int64(ld.Segdata.Vaddr), int64(ld.Segdata.Filelen))
 
-	machlink = 0
+	machlink := int64(0)
 	if ld.HEADTYPE == ld.Hdarwin {
 		if ld.Debug['v'] != 0 {
 			fmt.Fprintf(&ld.Bso, "%5.2f dwarf\n", obj.Cputime())
 		}
 
-		dwarfoff = ld.Rnd(int64(uint64(ld.HEADR)+ld.Segtext.Length), int64(ld.INITRND)) + ld.Rnd(int64(ld.Segdata.Filelen), int64(ld.INITRND))
+		dwarfoff := ld.Rnd(int64(uint64(ld.HEADR)+ld.Segtext.Length), int64(ld.INITRND)) + ld.Rnd(int64(ld.Segdata.Filelen), int64(ld.INITRND))
 		ld.Cseek(dwarfoff)
 
 		ld.Segdwarf.Fileoff = uint64(ld.Cpos())
@@ -708,7 +723,7 @@
 	ld.Symsize = 0
 	ld.Spsize = 0
 	ld.Lcsize = 0
-	symo = 0
+	symo := int64(0)
 	if ld.Debug['s'] == 0 {
 		if ld.Debug['v'] != 0 {
 			fmt.Fprintf(&ld.Bso, "%5.2f sym\n", obj.Cputime())
@@ -763,10 +778,10 @@
 			ld.Asmplan9sym()
 			ld.Cflush()
 
-			sym = ld.Linklookup(ld.Ctxt, "pclntab", 0)
+			sym := ld.Linklookup(ld.Ctxt, "pclntab", 0)
 			if sym != nil {
 				ld.Lcsize = int32(len(sym.P))
-				for i = 0; int32(i) < ld.Lcsize; i++ {
+				for i := 0; int32(i) < ld.Lcsize; i++ {
 					ld.Cput(uint8(sym.P[i]))
 				}
 
@@ -795,7 +810,7 @@
 	switch ld.HEADTYPE {
 	default:
 	case ld.Hplan9: /* plan9 */
-		magic = 4*26*26 + 7
+		magic := int32(4*26*26 + 7)
 
 		magic |= 0x00008000                  /* fat header */
 		ld.Lputb(uint32(magic))              /* magic */
@@ -803,7 +818,7 @@
 		ld.Lputb(uint32(ld.Segdata.Filelen))
 		ld.Lputb(uint32(ld.Segdata.Length - ld.Segdata.Filelen))
 		ld.Lputb(uint32(ld.Symsize)) /* nsyms */
-		vl = ld.Entryvalue()
+		vl := ld.Entryvalue()
 		ld.Lputb(PADDR(uint32(vl))) /* va of entry */
 		ld.Lputb(uint32(ld.Spsize)) /* sp offsets */
 		ld.Lputb(uint32(ld.Lcsize)) /* line offsets */
diff --git a/src/cmd/6l/l.go b/src/cmd/6l/l.go
index f698679..6b42088 100644
--- a/src/cmd/6l/l.go
+++ b/src/cmd/6l/l.go
@@ -1,37 +1,3 @@
-// Inferno utils/6l/asm.c
-// http://code.google.com/p/inferno-os/source/browse/utils/6l/asm.c
-//
-//	Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
-//	Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
-//	Portions Copyright © 1997-1999 Vita Nuova Limited
-//	Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
-//	Portions Copyright © 2004,2006 Bruce Ellis
-//	Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
-//	Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
-//	Portions Copyright © 2009 The Go Authors.  All rights reserved.
-//
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files (the "Software"), to deal
-// in the Software without restriction, including without limitation the rights
-// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-// copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-// THE SOFTWARE.
-
-package main
-
-// Writing object files.
-
 // Inferno utils/6l/l.h
 // http://code.google.com/p/inferno-os/source/browse/utils/6l/l.h
 //
@@ -62,9 +28,11 @@
 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 // THE SOFTWARE.
 
+package main
+
 const (
 	thechar   = '6'
-	MaxAlign  = 32
+	MaxAlign  = 32 // max data alignment
 	FuncAlign = 16
 )
 
diff --git a/src/cmd/6l/obj.go b/src/cmd/6l/obj.go
index a34e30d..f7165ab 100644
--- a/src/cmd/6l/obj.go
+++ b/src/cmd/6l/obj.go
@@ -31,11 +31,11 @@
 package main
 
 import (
+	"cmd/internal/ld"
 	"cmd/internal/obj"
 	"fmt"
 	"log"
 )
-import "cmd/internal/ld"
 
 // Reading object files.
 
@@ -71,6 +71,7 @@
 	ld.Thearch.Elfsetupplt = elfsetupplt
 	ld.Thearch.Gentext = gentext
 	ld.Thearch.Machoreloc1 = machoreloc1
+	ld.Thearch.PEreloc1 = pereloc1
 	ld.Thearch.Lput = ld.Lputl
 	ld.Thearch.Wput = ld.Wputl
 	ld.Thearch.Vput = ld.Vputl
@@ -110,7 +111,8 @@
 		ld.Hnacl,
 		ld.Hnetbsd,
 		ld.Hopenbsd,
-		ld.Hsolaris:
+		ld.Hsolaris,
+		ld.Hwindows:
 		break
 	}
 
diff --git a/src/cmd/7g/cgen.go b/src/cmd/7g/cgen.go
new file mode 100644
index 0000000..8d6dce4
--- /dev/null
+++ b/src/cmd/7g/cgen.go
@@ -0,0 +1,157 @@
+// 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/gc"
+	"cmd/internal/obj"
+	"cmd/internal/obj/arm64"
+)
+
+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.
+	// for example moving [4]byte must use 4 MOVB not 1 MOVW.
+	align := int(n.Type.Align)
+
+	var op int
+	switch align {
+	default:
+		gc.Fatal("sgen: invalid alignment %d for %v", align, gc.Tconv(n.Type, 0))
+
+	case 1:
+		op = arm64.AMOVB
+
+	case 2:
+		op = arm64.AMOVH
+
+	case 4:
+		op = arm64.AMOVW
+
+	case 8:
+		op = arm64.AMOVD
+	}
+
+	if w%int64(align) != 0 {
+		gc.Fatal("sgen: unaligned size %d (align=%d) for %v", w, align, gc.Tconv(n.Type, 0))
+	}
+	c := int32(w / int64(align))
+
+	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
+	}
+
+	var dst gc.Node
+	var src gc.Node
+	if n.Ullman >= res.Ullman {
+		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)
+		}
+		gc.Agen(res, &dst)
+	} else {
+		if res.Op == gc.ONAME {
+			gc.Gvardef(res)
+		}
+		gc.Agenr(res, &dst, res)
+		gc.Agenr(n, &src, nil)
+	}
+
+	var tmp gc.Node
+	gc.Regalloc(&tmp, gc.Types[gc.Tptr], nil)
+
+	// set up end marker
+	var nend gc.Node
+
+	// move src and dest to the end of block if necessary
+	if dir < 0 {
+		if c >= 4 {
+			gc.Regalloc(&nend, gc.Types[gc.Tptr], nil)
+			gins(arm64.AMOVD, &src, &nend)
+		}
+
+		p := gins(arm64.AADD, nil, &src)
+		p.From.Type = obj.TYPE_CONST
+		p.From.Offset = w
+
+		p = gins(arm64.AADD, nil, &dst)
+		p.From.Type = obj.TYPE_CONST
+		p.From.Offset = w
+	} else {
+		p := gins(arm64.AADD, nil, &src)
+		p.From.Type = obj.TYPE_CONST
+		p.From.Offset = int64(-dir)
+
+		p = gins(arm64.AADD, nil, &dst)
+		p.From.Type = obj.TYPE_CONST
+		p.From.Offset = int64(-dir)
+
+		if c >= 4 {
+			gc.Regalloc(&nend, gc.Types[gc.Tptr], nil)
+			p := gins(arm64.AMOVD, &src, &nend)
+			p.From.Type = obj.TYPE_ADDR
+			p.From.Offset = w
+		}
+	}
+
+	// move
+	// TODO: enable duffcopy for larger copies.
+	if c >= 4 {
+		p := gins(op, &src, &tmp)
+		p.From.Type = obj.TYPE_MEM
+		p.From.Offset = int64(dir)
+		p.Scond = arm64.C_XPRE
+		ploop := p
+
+		p = gins(op, &tmp, &dst)
+		p.To.Type = obj.TYPE_MEM
+		p.To.Offset = int64(dir)
+		p.Scond = arm64.C_XPRE
+
+		p = gcmp(arm64.ACMP, &src, &nend)
+
+		gc.Patch(gc.Gbranch(arm64.ABNE, nil, 0), ploop)
+		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
+		// generate the offsets directly and eliminate the
+		// ADDs.  That will produce shorter, more
+		// pipeline-able code.
+		var p *obj.Prog
+		for {
+			tmp14 := c
+			c--
+			if tmp14 <= 0 {
+				break
+			}
+
+			p = gins(op, &src, &tmp)
+			p.From.Type = obj.TYPE_MEM
+			p.From.Offset = int64(dir)
+			p.Scond = arm64.C_XPRE
+
+			p = gins(op, &tmp, &dst)
+			p.To.Type = obj.TYPE_MEM
+			p.To.Offset = int64(dir)
+			p.Scond = arm64.C_XPRE
+		}
+	}
+
+	gc.Regfree(&dst)
+	gc.Regfree(&src)
+	gc.Regfree(&tmp)
+}
diff --git a/src/cmd/7g/galign.go b/src/cmd/7g/galign.go
new file mode 100644
index 0000000..1c50c21
--- /dev/null
+++ b/src/cmd/7g/galign.go
@@ -0,0 +1,90 @@
+// 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/gc"
+	"cmd/internal/obj"
+	"cmd/internal/obj/arm64"
+)
+
+var thechar int = '7'
+
+var thestring string = "arm64"
+
+var thelinkarch *obj.LinkArch = &arm64.Linkarm64
+
+func linkarchinit() {
+}
+
+var MAXWIDTH int64 = 1 << 50
+
+/*
+ * go declares several platform-specific type aliases:
+ * int, uint, float, and uintptr
+ */
+var typedefs = []gc.Typedef{
+	gc.Typedef{"int", gc.TINT, gc.TINT64},
+	gc.Typedef{"uint", gc.TUINT, gc.TUINT64},
+	gc.Typedef{"uintptr", gc.TUINTPTR, gc.TUINT64},
+}
+
+func betypeinit() {
+	gc.Widthptr = 8
+	gc.Widthint = 8
+	gc.Widthreg = 8
+}
+
+func main() {
+	gc.Thearch.Thechar = thechar
+	gc.Thearch.Thestring = thestring
+	gc.Thearch.Thelinkarch = thelinkarch
+	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.ReservedRegs = resvd
+
+	gc.Thearch.Betypeinit = betypeinit
+	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.Gins = gins
+	gc.Thearch.Ginscon = ginscon
+	gc.Thearch.Ginsnop = ginsnop
+	gc.Thearch.Gmove = gmove
+	gc.Thearch.Linkarchinit = linkarchinit
+	gc.Thearch.Peep = peep
+	gc.Thearch.Proginfo = proginfo
+	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
+	gc.Thearch.BtoR = BtoR
+	gc.Thearch.BtoF = BtoF
+	gc.Thearch.Optoas = optoas
+	gc.Thearch.Doregbits = doregbits
+	gc.Thearch.Regnames = regnames
+
+	gc.Main()
+	gc.Exit(0)
+}
diff --git a/src/cmd/9g/gg.go b/src/cmd/7g/gg.go
similarity index 85%
rename from src/cmd/9g/gg.go
rename to src/cmd/7g/gg.go
index 068d8af..a267482 100644
--- a/src/cmd/9g/gg.go
+++ b/src/cmd/7g/gg.go
@@ -4,14 +4,14 @@
 
 package main
 
-import "cmd/internal/obj/ppc64"
+import "cmd/internal/obj/arm64"
 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 reg [arm64.NREG + arm64.NFREG]uint8
 
 var panicdiv *gc.Node
 
diff --git a/src/cmd/7g/ggen.go b/src/cmd/7g/ggen.go
new file mode 100644
index 0000000..0fc5854
--- /dev/null
+++ b/src/cmd/7g/ggen.go
@@ -0,0 +1,534 @@
+// 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/gc"
+	"cmd/internal/obj"
+	"cmd/internal/obj/arm64"
+	"fmt"
+)
+
+func defframe(ptxt *obj.Prog) {
+	var n *gc.Node
+
+	// fill in argument size, stack size
+	ptxt.To.Type = obj.TYPE_TEXTSIZE
+
+	ptxt.To.Val = int32(gc.Rnd(gc.Curfn.Type.Argwid, int64(gc.Widthptr)))
+	frame := uint32(gc.Rnd(gc.Stksize+gc.Maxarg, int64(gc.Widthreg)))
+	ptxt.To.Offset = int64(frame)
+
+	// insert code to zero ambiguously live variables
+	// so that the garbage collector only sees initialized values
+	// when it looks for pointers.
+	p := ptxt
+
+	hi := int64(0)
+	lo := hi
+
+	// iterate through declarations - they are sorted in decreasing xoffset order.
+	for l := gc.Curfn.Func.Dcl; l != nil; l = l.Next {
+		n = l.N
+		if !n.Needzero {
+			continue
+		}
+		if n.Class != gc.PAUTO {
+			gc.Fatal("needzero class %d", n.Class)
+		}
+		if n.Type.Width%int64(gc.Widthptr) != 0 || n.Xoffset%int64(gc.Widthptr) != 0 || n.Type.Width == 0 {
+			gc.Fatal("var %v has size %d offset %d", gc.Nconv(n, obj.FmtLong), int(n.Type.Width), int(n.Xoffset))
+		}
+
+		if lo != hi && n.Xoffset+n.Type.Width >= lo-int64(2*gc.Widthreg) {
+			// merge with range we already have
+			lo = n.Xoffset
+
+			continue
+		}
+
+		// zero old range
+		p = zerorange(p, int64(frame), lo, hi)
+
+		// set new range
+		hi = n.Xoffset + n.Type.Width
+
+		lo = n.Xoffset
+	}
+
+	// zero final range
+	zerorange(p, int64(frame), lo, hi)
+}
+
+func zerorange(p *obj.Prog, frame int64, lo int64, hi int64) *obj.Prog {
+	cnt := hi - lo
+	if cnt == 0 {
+		return p
+	}
+	if cnt < int64(4*gc.Widthptr) {
+		for i := int64(0); i < cnt; i += int64(gc.Widthptr) {
+			p = appendpp(p, arm64.AMOVD, obj.TYPE_REG, arm64.REGZERO, 0, obj.TYPE_MEM, arm64.REGSP, 8+frame+lo+i)
+		}
+	} else if cnt <= int64(128*gc.Widthptr) {
+		p = appendpp(p, arm64.AMOVD, obj.TYPE_REG, arm64.REGSP, 0, obj.TYPE_REG, arm64.REGRT1, 0)
+		p = appendpp(p, arm64.AADD, obj.TYPE_CONST, 0, 8+frame+lo-8, obj.TYPE_REG, arm64.REGRT1, 0)
+		p.Reg = arm64.REGRT1
+		p = appendpp(p, obj.ADUFFZERO, obj.TYPE_NONE, 0, 0, obj.TYPE_MEM, 0, 0)
+		f := gc.Sysfunc("duffzero")
+		gc.Naddr(&p.To, f)
+		gc.Afunclit(&p.To, f)
+		p.To.Offset = 4 * (128 - cnt/int64(gc.Widthptr))
+	} else {
+		p = appendpp(p, arm64.AMOVD, obj.TYPE_CONST, 0, 8+frame+lo-8, obj.TYPE_REG, arm64.REGTMP, 0)
+		p = appendpp(p, arm64.AMOVD, obj.TYPE_REG, arm64.REGSP, 0, obj.TYPE_REG, arm64.REGRT1, 0)
+		p = appendpp(p, arm64.AADD, obj.TYPE_REG, arm64.REGTMP, 0, obj.TYPE_REG, arm64.REGRT1, 0)
+		p.Reg = arm64.REGRT1
+		p = appendpp(p, arm64.AMOVD, obj.TYPE_CONST, 0, cnt, obj.TYPE_REG, arm64.REGTMP, 0)
+		p = appendpp(p, arm64.AADD, obj.TYPE_REG, arm64.REGTMP, 0, obj.TYPE_REG, arm64.REGRT2, 0)
+		p.Reg = arm64.REGRT1
+		p = appendpp(p, arm64.AMOVD, obj.TYPE_REG, arm64.REGZERO, 0, obj.TYPE_MEM, arm64.REGRT1, int64(gc.Widthptr))
+		p.Scond = arm64.C_XPRE
+		p1 := p
+		p = appendpp(p, arm64.ACMP, obj.TYPE_REG, arm64.REGRT1, 0, obj.TYPE_NONE, 0, 0)
+		p.Reg = arm64.REGRT2
+		p = appendpp(p, arm64.ABNE, obj.TYPE_NONE, 0, 0, obj.TYPE_BRANCH, 0, 0)
+		gc.Patch(p, p1)
+	}
+
+	return p
+}
+
+func appendpp(p *obj.Prog, as int, ftype int, freg int, foffset int64, ttype int, treg int, toffset int64) *obj.Prog {
+	q := gc.Ctxt.NewProg()
+	gc.Clearp(q)
+	q.As = int16(as)
+	q.Lineno = p.Lineno
+	q.From.Type = int16(ftype)
+	q.From.Reg = int16(freg)
+	q.From.Offset = foffset
+	q.To.Type = int16(ttype)
+	q.To.Reg = int16(treg)
+	q.To.Offset = toffset
+	q.Link = p.Link
+	p.Link = q
+	return q
+}
+
+func ginsnop() {
+	var con gc.Node
+	gc.Nodconst(&con, gc.Types[gc.TINT], 0)
+	gins(arm64.AHINT, &con, nil)
+}
+
+/*
+ * generate division.
+ * generates one of:
+ *	res = nl / nr
+ *	res = nl % nr
+ * according to op.
+ */
+func dodiv(op int, nl *gc.Node, nr *gc.Node, res *gc.Node) {
+	// Have to be careful about handling
+	// most negative int divided by -1 correctly.
+	// The hardware will generate undefined result.
+	// Also need to explicitly trap on division on zero,
+	// the hardware will silently generate undefined result.
+	// DIVW will leave unpredicable result in higher 32-bit,
+	// so always use DIVD/DIVDU.
+	t := nl.Type
+
+	t0 := t
+	check := 0
+	if gc.Issigned[t.Etype] {
+		check = 1
+		if gc.Isconst(nl, gc.CTINT) && gc.Mpgetfix(nl.Val.U.Xval) != -(1<<uint64(t.Width*8-1)) {
+			check = 0
+		} else if gc.Isconst(nr, gc.CTINT) && gc.Mpgetfix(nr.Val.U.Xval) != -1 {
+			check = 0
+		}
+	}
+
+	if t.Width < 8 {
+		if gc.Issigned[t.Etype] {
+			t = gc.Types[gc.TINT64]
+		} else {
+			t = gc.Types[gc.TUINT64]
+		}
+		check = 0
+	}
+
+	a := optoas(gc.ODIV, t)
+
+	var tl gc.Node
+	gc.Regalloc(&tl, t0, nil)
+	var tr gc.Node
+	gc.Regalloc(&tr, t0, nil)
+	if nl.Ullman >= nr.Ullman {
+		gc.Cgen(nl, &tl)
+		gc.Cgen(nr, &tr)
+	} else {
+		gc.Cgen(nr, &tr)
+		gc.Cgen(nl, &tl)
+	}
+
+	if t != t0 {
+		// Convert
+		tl2 := tl
+
+		tr2 := tr
+		tl.Type = t
+		tr.Type = t
+		gmove(&tl2, &tl)
+		gmove(&tr2, &tr)
+	}
+
+	// Handle divide-by-zero panic.
+	p1 := gins(optoas(gc.OCMP, t), &tr, nil)
+	p1.Reg = arm64.REGZERO
+	p1 = gc.Gbranch(optoas(gc.ONE, t), nil, +1)
+	if panicdiv == nil {
+		panicdiv = gc.Sysfunc("panicdivide")
+	}
+	gc.Ginscall(panicdiv, -1)
+	gc.Patch(p1, gc.Pc)
+
+	var p2 *obj.Prog
+	if check != 0 {
+		var nm1 gc.Node
+		gc.Nodconst(&nm1, t, -1)
+		gcmp(optoas(gc.OCMP, t), &tr, &nm1)
+		p1 := gc.Gbranch(optoas(gc.ONE, t), nil, +1)
+		if op == gc.ODIV {
+			// a / (-1) is -a.
+			gins(optoas(gc.OMINUS, t), &tl, &tl)
+
+			gmove(&tl, res)
+		} else {
+			// a % (-1) is 0.
+			var nz gc.Node
+			gc.Nodconst(&nz, t, 0)
+
+			gmove(&nz, res)
+		}
+
+		p2 = gc.Gbranch(obj.AJMP, nil, 0)
+		gc.Patch(p1, gc.Pc)
+	}
+
+	p1 = gins(a, &tr, &tl)
+	if op == gc.ODIV {
+		gc.Regfree(&tr)
+		gmove(&tl, res)
+	} else {
+		// A%B = A-(A/B*B)
+		var tm gc.Node
+		gc.Regalloc(&tm, t, nil)
+
+		// patch div to use the 3 register form
+		// TODO(minux): add gins3?
+		p1.Reg = p1.To.Reg
+
+		p1.To.Reg = tm.Val.U.Reg
+		gins(optoas(gc.OMUL, t), &tr, &tm)
+		gc.Regfree(&tr)
+		gins(optoas(gc.OSUB, t), &tm, &tl)
+		gc.Regfree(&tm)
+		gmove(&tl, res)
+	}
+
+	gc.Regfree(&tl)
+	if check != 0 {
+		gc.Patch(p2, gc.Pc)
+	}
+}
+
+/*
+ * generate high multiply:
+ *   res = (nl*nr) >> width
+ */
+func cgen_hmul(nl *gc.Node, nr *gc.Node, res *gc.Node) {
+	// largest ullman on left.
+	if nl.Ullman < nr.Ullman {
+		tmp := (*gc.Node)(nl)
+		nl = nr
+		nr = tmp
+	}
+
+	t := (*gc.Type)(nl.Type)
+	w := int(int(t.Width * 8))
+	var n1 gc.Node
+	gc.Cgenr(nl, &n1, res)
+	var n2 gc.Node
+	gc.Cgenr(nr, &n2, nil)
+	switch gc.Simtype[t.Etype] {
+	case gc.TINT8,
+		gc.TINT16,
+		gc.TINT32:
+		gins(optoas(gc.OMUL, t), &n2, &n1)
+		p := (*obj.Prog)(gins(arm64.AASR, nil, &n1))
+		p.From.Type = obj.TYPE_CONST
+		p.From.Offset = int64(w)
+
+	case gc.TUINT8,
+		gc.TUINT16,
+		gc.TUINT32:
+		gins(optoas(gc.OMUL, t), &n2, &n1)
+		p := (*obj.Prog)(gins(arm64.ALSR, nil, &n1))
+		p.From.Type = obj.TYPE_CONST
+		p.From.Offset = int64(w)
+
+	case gc.TINT64,
+		gc.TUINT64:
+		if gc.Issigned[t.Etype] {
+			gins(arm64.ASMULH, &n2, &n1)
+		} else {
+			gins(arm64.AUMULH, &n2, &n1)
+		}
+
+	default:
+		gc.Fatal("cgen_hmul %v", gc.Tconv(t, 0))
+	}
+
+	gc.Cgen(&n1, res)
+	gc.Regfree(&n1)
+	gc.Regfree(&n2)
+}
+
+/*
+ * generate shift according to op, one of:
+ *	res = nl << nr
+ *	res = nl >> nr
+ */
+func cgen_shift(op int, bounded bool, nl *gc.Node, nr *gc.Node, res *gc.Node) {
+	a := int(optoas(op, nl.Type))
+
+	if nr.Op == gc.OLITERAL {
+		var n1 gc.Node
+		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
+			var n3 gc.Node
+			gc.Nodconst(&n3, gc.Types[gc.TUINT32], nl.Type.Width*8-1)
+
+			gins(a, &n3, &n1)
+			gins(a, &n3, &n1)
+		} else {
+			gins(a, nr, &n1)
+		}
+		gmove(&n1, res)
+		gc.Regfree(&n1)
+		return
+	}
+
+	if nl.Ullman >= gc.UINF {
+		var n4 gc.Node
+		gc.Tempname(&n4, nl.Type)
+		gc.Cgen(nl, &n4)
+		nl = &n4
+	}
+
+	if nr.Ullman >= gc.UINF {
+		var n5 gc.Node
+		gc.Tempname(&n5, nr.Type)
+		gc.Cgen(nr, &n5)
+		nr = &n5
+	}
+
+	// Allow either uint32 or uint64 as shift type,
+	// to avoid unnecessary conversion from uint32 to uint64
+	// just to do the comparison.
+	tcount := gc.Types[gc.Simtype[nr.Type.Etype]]
+
+	if tcount.Etype < gc.TUINT32 {
+		tcount = gc.Types[gc.TUINT32]
+	}
+
+	var n1 gc.Node
+	gc.Regalloc(&n1, nr.Type, nil) // to hold the shift type in CX
+	var n3 gc.Node
+	gc.Regalloc(&n3, tcount, &n1) // to clear high bits of CX
+
+	var n2 gc.Node
+	gc.Regalloc(&n2, nl.Type, res)
+
+	if nl.Ullman >= nr.Ullman {
+		gc.Cgen(nl, &n2)
+		gc.Cgen(nr, &n1)
+		gmove(&n1, &n3)
+	} else {
+		gc.Cgen(nr, &n1)
+		gmove(&n1, &n3)
+		gc.Cgen(nl, &n2)
+	}
+
+	gc.Regfree(&n3)
+
+	// test and fix up large shifts
+	if !bounded {
+		gc.Nodconst(&n3, tcount, nl.Type.Width*8)
+		gcmp(optoas(gc.OCMP, tcount), &n1, &n3)
+		p1 := (*obj.Prog)(gc.Gbranch(optoas(gc.OLT, tcount), nil, +1))
+		if op == gc.ORSH && gc.Issigned[nl.Type.Etype] {
+			gc.Nodconst(&n3, gc.Types[gc.TUINT32], nl.Type.Width*8-1)
+			gins(a, &n3, &n2)
+		} else {
+			gc.Nodconst(&n3, nl.Type, 0)
+			gmove(&n3, &n2)
+		}
+
+		gc.Patch(p1, gc.Pc)
+	}
+
+	gins(a, &n1, &n2)
+
+	gmove(&n2, res)
+
+	gc.Regfree(&n1)
+	gc.Regfree(&n2)
+}
+
+func clearfat(nl *gc.Node) {
+	/* clear a fat object */
+	if gc.Debug['g'] != 0 {
+		fmt.Printf("clearfat %v (%v, size: %d)\n", gc.Nconv(nl, 0), gc.Tconv(nl.Type, 0), nl.Type.Width)
+	}
+
+	w := uint64(uint64(nl.Type.Width))
+
+	// Avoid taking the address for simple enough types.
+	//if gc.Componentgen(nil, nl) {
+	//	return
+	//}
+
+	c := uint64(w % 8) // bytes
+	q := uint64(w / 8) // dwords
+
+	if reg[arm64.REGRT1-arm64.REG_R0] > 0 {
+		gc.Fatal("R%d in use during clearfat", arm64.REGRT1-arm64.REG_R0)
+	}
+
+	var r0 gc.Node
+	gc.Nodreg(&r0, gc.Types[gc.TUINT64], arm64.REGZERO)
+	var dst gc.Node
+	gc.Nodreg(&dst, gc.Types[gc.Tptr], arm64.REGRT1)
+	reg[arm64.REGRT1-arm64.REG_R0]++
+	gc.Agen(nl, &dst)
+
+	var boff uint64
+	if q > 128 {
+		p := gins(arm64.ASUB, nil, &dst)
+		p.From.Type = obj.TYPE_CONST
+		p.From.Offset = 8
+
+		var end gc.Node
+		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)
+
+		p = gins(arm64.AMOVD, &r0, &dst)
+		p.To.Type = obj.TYPE_MEM
+		p.To.Offset = 8
+		p.Scond = arm64.C_XPRE
+		pl := (*obj.Prog)(p)
+
+		p = gcmp(arm64.ACMP, &dst, &end)
+		gc.Patch(gc.Gbranch(arm64.ABNE, nil, 0), pl)
+
+		gc.Regfree(&end)
+
+		// The loop leaves R16 on the last zeroed dword
+		boff = 8
+	} else if q >= 4 {
+		p := gins(arm64.ASUB, nil, &dst)
+		p.From.Type = obj.TYPE_CONST
+		p.From.Offset = 8
+		f := (*gc.Node)(gc.Sysfunc("duffzero"))
+		p = gins(obj.ADUFFZERO, nil, f)
+		gc.Afunclit(&p.To, f)
+
+		// 4 and 128 = magic constants: see ../../runtime/asm_arm64x.s
+		p.To.Offset = int64(4 * (128 - q))
+
+		// duffzero leaves R16 on the last zeroed dword
+		boff = 8
+	} else {
+		var p *obj.Prog
+		for t := uint64(0); t < q; t++ {
+			p = gins(arm64.AMOVD, &r0, &dst)
+			p.To.Type = obj.TYPE_MEM
+			p.To.Offset = int64(8 * t)
+		}
+
+		boff = 8 * q
+	}
+
+	var p *obj.Prog
+	for t := uint64(0); t < c; t++ {
+		p = gins(arm64.AMOVB, &r0, &dst)
+		p.To.Type = obj.TYPE_MEM
+		p.To.Offset = int64(t + boff)
+	}
+
+	reg[arm64.REGRT1-arm64.REG_R0]--
+}
+
+// Called after regopt and peep have run.
+// Expand CHECKNIL pseudo-op into actual nil pointer check.
+func expandchecks(firstp *obj.Prog) {
+	var p1 *obj.Prog
+	var p2 *obj.Prog
+
+	for p := (*obj.Prog)(firstp); p != nil; p = p.Link {
+		if gc.Debug_checknil != 0 && gc.Ctxt.Debugvlog != 0 {
+			fmt.Printf("expandchecks: %v\n", p)
+		}
+		if p.As != obj.ACHECKNIL {
+			continue
+		}
+		if gc.Debug_checknil != 0 && p.Lineno > 1 { // p->lineno==1 in generated wrappers
+			gc.Warnl(int(p.Lineno), "generated nil check")
+		}
+		if p.From.Type != obj.TYPE_REG {
+			gc.Fatal("invalid nil check %v\n", p)
+		}
+
+		// check is
+		//	CMP arg, ZR
+		//	BNE 2(PC) [likely]
+		//	MOVD ZR, 0(arg)
+		p1 = gc.Ctxt.NewProg()
+
+		p2 = gc.Ctxt.NewProg()
+		gc.Clearp(p1)
+		gc.Clearp(p2)
+		p1.Link = p2
+		p2.Link = p.Link
+		p.Link = p1
+		p1.Lineno = p.Lineno
+		p2.Lineno = p.Lineno
+		p1.Pc = 9999
+		p2.Pc = 9999
+		p.As = arm64.ACMP
+		p.Reg = arm64.REGZERO
+		p1.As = arm64.ABNE
+
+		//p1->from.type = TYPE_CONST;
+		//p1->from.offset = 1; // likely
+		p1.To.Type = obj.TYPE_BRANCH
+
+		p1.To.Val = p2.Link
+
+		// crash by write to memory address 0.
+		p2.As = arm64.AMOVD
+		p2.From.Type = obj.TYPE_REG
+		p2.From.Reg = arm64.REGZERO
+		p2.To.Type = obj.TYPE_MEM
+		p2.To.Reg = p.From.Reg
+		p2.To.Offset = 0
+	}
+}
diff --git a/src/cmd/7g/gsubr.go b/src/cmd/7g/gsubr.go
new file mode 100644
index 0000000..2d2bdb7
--- /dev/null
+++ b/src/cmd/7g/gsubr.go
@@ -0,0 +1,977 @@
+// Derived from Inferno utils/6c/txt.c
+// http://code.google.com/p/inferno-os/source/browse/utils/6c/txt.c
+//
+//	Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
+//	Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
+//	Portions Copyright © 1997-1999 Vita Nuova Limited
+//	Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
+//	Portions Copyright © 2004,2006 Bruce Ellis
+//	Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
+//	Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
+//	Portions Copyright © 2009 The Go Authors.  All rights reserved.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+package main
+
+import (
+	"cmd/internal/gc"
+	"cmd/internal/obj"
+	"cmd/internal/obj/arm64"
+	"fmt"
+)
+
+// TODO(rsc): Can make this bigger if we move
+// the text segment up higher in 6l for all GOOS.
+// At the same time, can raise StackBig in ../../runtime/stack.h.
+var unmappedzero int64 = 4096
+
+var resvd = []int{
+	arm64.REGTMP,
+	arm64.REGG,
+	arm64.REGRT1,
+	arm64.REGRT2,
+	arm64.REG_R31, // REGZERO and REGSP
+	arm64.FREGZERO,
+	arm64.FREGHALF,
+	arm64.FREGONE,
+	arm64.FREGTWO,
+}
+
+/*
+ * generate
+ *	as $c, n
+ */
+func ginscon(as int, c int64, n2 *gc.Node) {
+	var n1 gc.Node
+
+	gc.Nodconst(&n1, gc.Types[gc.TINT64], c)
+
+	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
+		gc.Regalloc(&ntmp, gc.Types[gc.TINT64], nil)
+
+		gins(arm64.AMOVD, &n1, &ntmp)
+		gins(as, &ntmp, n2)
+		gc.Regfree(&ntmp)
+		return
+	}
+
+	rawgins(as, &n1, n2)
+}
+
+/*
+ * generate
+ *	as n, $c (CMP)
+ */
+func ginscon2(as int, n2 *gc.Node, c int64) {
+	var n1 gc.Node
+
+	gc.Nodconst(&n1, gc.Types[gc.TINT64], c)
+
+	switch as {
+	default:
+		gc.Fatal("ginscon2")
+
+	case arm64.ACMP:
+		if -arm64.BIG <= c && c <= arm64.BIG {
+			gcmp(as, n2, &n1)
+			return
+		}
+	}
+
+	// MOV n1 into register first
+	var ntmp gc.Node
+	gc.Regalloc(&ntmp, gc.Types[gc.TINT64], nil)
+
+	rawgins(arm64.AMOVD, &n1, &ntmp)
+	gcmp(as, n2, &ntmp)
+	gc.Regfree(&ntmp)
+}
+
+/*
+ * generate move:
+ *	t = f
+ * hard part is conversions.
+ */
+func gmove(f *gc.Node, t *gc.Node) {
+	if gc.Debug['M'] != 0 {
+		fmt.Printf("gmove %v -> %v\n", gc.Nconv(f, obj.FmtLong), gc.Nconv(t, obj.FmtLong))
+	}
+
+	ft := int(gc.Simsimtype(f.Type))
+	tt := int(gc.Simsimtype(t.Type))
+	cvt := (*gc.Type)(t.Type)
+
+	if gc.Iscomplex[ft] || gc.Iscomplex[tt] {
+		gc.Complexmove(f, t)
+		return
+	}
+
+	// cannot have two memory operands
+	var r1 gc.Node
+	var a int
+	if gc.Ismem(f) && gc.Ismem(t) {
+		goto hard
+	}
+
+	// convert constant to desired type
+	if f.Op == gc.OLITERAL {
+		var con gc.Node
+		switch tt {
+		default:
+			gc.Convconst(&con, t.Type, &f.Val)
+
+		case gc.TINT32,
+			gc.TINT16,
+			gc.TINT8:
+			var con gc.Node
+			gc.Convconst(&con, gc.Types[gc.TINT64], &f.Val)
+			var r1 gc.Node
+			gc.Regalloc(&r1, con.Type, t)
+			gins(arm64.AMOVD, &con, &r1)
+			gmove(&r1, t)
+			gc.Regfree(&r1)
+			return
+
+		case gc.TUINT32,
+			gc.TUINT16,
+			gc.TUINT8:
+			var con gc.Node
+			gc.Convconst(&con, gc.Types[gc.TUINT64], &f.Val)
+			var r1 gc.Node
+			gc.Regalloc(&r1, con.Type, t)
+			gins(arm64.AMOVD, &con, &r1)
+			gmove(&r1, t)
+			gc.Regfree(&r1)
+			return
+		}
+
+		f = &con
+		ft = tt // so big switch will choose a simple mov
+
+		// constants can't move directly to memory.
+		if gc.Ismem(t) {
+			goto hard
+		}
+	}
+
+	// value -> value copy, first operand in memory.
+	// any floating point operand requires register
+	// src, so goto hard to copy to register first.
+	if gc.Ismem(f) && ft != tt && (gc.Isfloat[ft] || gc.Isfloat[tt]) {
+		cvt = gc.Types[ft]
+		goto hard
+	}
+
+	// value -> value copy, only one memory operand.
+	// figure out the instruction to use.
+	// break out of switch for one-instruction gins.
+	// goto rdst for "destination must be register".
+	// goto hard for "convert to cvt type first".
+	// otherwise handle and return.
+
+	switch uint32(ft)<<16 | uint32(tt) {
+	default:
+		gc.Fatal("gmove %v -> %v", gc.Tconv(f.Type, obj.FmtLong), gc.Tconv(t.Type, obj.FmtLong))
+
+		/*
+		 * integer copy and truncate
+		 */
+	case gc.TINT8<<16 | gc.TINT8, // same size
+		gc.TUINT8<<16 | gc.TINT8,
+		gc.TINT16<<16 | gc.TINT8,
+		// truncate
+		gc.TUINT16<<16 | gc.TINT8,
+		gc.TINT32<<16 | gc.TINT8,
+		gc.TUINT32<<16 | gc.TINT8,
+		gc.TINT64<<16 | gc.TINT8,
+		gc.TUINT64<<16 | gc.TINT8:
+		a = arm64.AMOVB
+
+	case gc.TINT8<<16 | gc.TUINT8, // same size
+		gc.TUINT8<<16 | gc.TUINT8,
+		gc.TINT16<<16 | gc.TUINT8,
+		// truncate
+		gc.TUINT16<<16 | gc.TUINT8,
+		gc.TINT32<<16 | gc.TUINT8,
+		gc.TUINT32<<16 | gc.TUINT8,
+		gc.TINT64<<16 | gc.TUINT8,
+		gc.TUINT64<<16 | gc.TUINT8:
+		a = arm64.AMOVBU
+
+	case gc.TINT16<<16 | gc.TINT16, // same size
+		gc.TUINT16<<16 | gc.TINT16,
+		gc.TINT32<<16 | gc.TINT16,
+		// truncate
+		gc.TUINT32<<16 | gc.TINT16,
+		gc.TINT64<<16 | gc.TINT16,
+		gc.TUINT64<<16 | gc.TINT16:
+		a = arm64.AMOVH
+
+	case gc.TINT16<<16 | gc.TUINT16, // same size
+		gc.TUINT16<<16 | gc.TUINT16,
+		gc.TINT32<<16 | gc.TUINT16,
+		// truncate
+		gc.TUINT32<<16 | gc.TUINT16,
+		gc.TINT64<<16 | gc.TUINT16,
+		gc.TUINT64<<16 | gc.TUINT16:
+		a = arm64.AMOVHU
+
+	case gc.TINT32<<16 | gc.TINT32, // same size
+		gc.TUINT32<<16 | gc.TINT32,
+		gc.TINT64<<16 | gc.TINT32,
+		// truncate
+		gc.TUINT64<<16 | gc.TINT32:
+		a = arm64.AMOVW
+
+	case gc.TINT32<<16 | gc.TUINT32, // same size
+		gc.TUINT32<<16 | gc.TUINT32,
+		gc.TINT64<<16 | gc.TUINT32,
+		gc.TUINT64<<16 | gc.TUINT32:
+		a = arm64.AMOVWU
+
+	case gc.TINT64<<16 | gc.TINT64, // same size
+		gc.TINT64<<16 | gc.TUINT64,
+		gc.TUINT64<<16 | gc.TINT64,
+		gc.TUINT64<<16 | gc.TUINT64:
+		a = arm64.AMOVD
+
+		/*
+		 * integer up-conversions
+		 */
+	case gc.TINT8<<16 | gc.TINT16, // sign extend int8
+		gc.TINT8<<16 | gc.TUINT16,
+		gc.TINT8<<16 | gc.TINT32,
+		gc.TINT8<<16 | gc.TUINT32,
+		gc.TINT8<<16 | gc.TINT64,
+		gc.TINT8<<16 | gc.TUINT64:
+		a = arm64.AMOVB
+
+		goto rdst
+
+	case gc.TUINT8<<16 | gc.TINT16, // zero extend uint8
+		gc.TUINT8<<16 | gc.TUINT16,
+		gc.TUINT8<<16 | gc.TINT32,
+		gc.TUINT8<<16 | gc.TUINT32,
+		gc.TUINT8<<16 | gc.TINT64,
+		gc.TUINT8<<16 | gc.TUINT64:
+		a = arm64.AMOVBU
+
+		goto rdst
+
+	case gc.TINT16<<16 | gc.TINT32, // sign extend int16
+		gc.TINT16<<16 | gc.TUINT32,
+		gc.TINT16<<16 | gc.TINT64,
+		gc.TINT16<<16 | gc.TUINT64:
+		a = arm64.AMOVH
+
+		goto rdst
+
+	case gc.TUINT16<<16 | gc.TINT32, // zero extend uint16
+		gc.TUINT16<<16 | gc.TUINT32,
+		gc.TUINT16<<16 | gc.TINT64,
+		gc.TUINT16<<16 | gc.TUINT64:
+		a = arm64.AMOVHU
+
+		goto rdst
+
+	case gc.TINT32<<16 | gc.TINT64, // sign extend int32
+		gc.TINT32<<16 | gc.TUINT64:
+		a = arm64.AMOVW
+
+		goto rdst
+
+	case gc.TUINT32<<16 | gc.TINT64, // zero extend uint32
+		gc.TUINT32<<16 | gc.TUINT64:
+		a = arm64.AMOVWU
+
+		goto rdst
+
+	/*
+	* float to integer
+	 */
+	case gc.TFLOAT32<<16 | gc.TINT32:
+		a = arm64.AFCVTZSSW
+		goto rdst
+
+	case gc.TFLOAT64<<16 | gc.TINT32:
+		a = arm64.AFCVTZSDW
+		goto rdst
+
+	case gc.TFLOAT32<<16 | gc.TINT64:
+		a = arm64.AFCVTZSS
+		goto rdst
+
+	case gc.TFLOAT64<<16 | gc.TINT64:
+		a = arm64.AFCVTZSD
+		goto rdst
+
+	case gc.TFLOAT32<<16 | gc.TUINT32:
+		a = arm64.AFCVTZUSW
+		goto rdst
+
+	case gc.TFLOAT64<<16 | gc.TUINT32:
+		a = arm64.AFCVTZUDW
+		goto rdst
+
+	case gc.TFLOAT32<<16 | gc.TUINT64:
+		a = arm64.AFCVTZUS
+		goto rdst
+
+	case gc.TFLOAT64<<16 | gc.TUINT64:
+		a = arm64.AFCVTZUD
+		goto rdst
+
+	case gc.TFLOAT32<<16 | gc.TINT16,
+		gc.TFLOAT32<<16 | gc.TINT8,
+		gc.TFLOAT64<<16 | gc.TINT16,
+		gc.TFLOAT64<<16 | gc.TINT8:
+		cvt = gc.Types[gc.TINT32]
+
+		goto hard
+
+	case gc.TFLOAT32<<16 | gc.TUINT16,
+		gc.TFLOAT32<<16 | gc.TUINT8,
+		gc.TFLOAT64<<16 | gc.TUINT16,
+		gc.TFLOAT64<<16 | gc.TUINT8:
+		cvt = gc.Types[gc.TUINT32]
+
+		goto hard
+
+	/*
+	 * integer to float
+	 */
+	case gc.TINT8<<16 | gc.TFLOAT32,
+		gc.TINT16<<16 | gc.TFLOAT32,
+		gc.TINT32<<16 | gc.TFLOAT32:
+		a = arm64.ASCVTFWS
+
+		goto rdst
+
+	case gc.TINT8<<16 | gc.TFLOAT64,
+		gc.TINT16<<16 | gc.TFLOAT64,
+		gc.TINT32<<16 | gc.TFLOAT64:
+		a = arm64.ASCVTFWD
+
+		goto rdst
+
+	case gc.TINT64<<16 | gc.TFLOAT32:
+		a = arm64.ASCVTFS
+		goto rdst
+
+	case gc.TINT64<<16 | gc.TFLOAT64:
+		a = arm64.ASCVTFD
+		goto rdst
+
+	case gc.TUINT8<<16 | gc.TFLOAT32,
+		gc.TUINT16<<16 | gc.TFLOAT32,
+		gc.TUINT32<<16 | gc.TFLOAT32:
+		a = arm64.AUCVTFWS
+
+		goto rdst
+
+	case gc.TUINT8<<16 | gc.TFLOAT64,
+		gc.TUINT16<<16 | gc.TFLOAT64,
+		gc.TUINT32<<16 | gc.TFLOAT64:
+		a = arm64.AUCVTFWD
+
+		goto rdst
+
+	case gc.TUINT64<<16 | gc.TFLOAT32:
+		a = arm64.AUCVTFS
+		goto rdst
+
+	case gc.TUINT64<<16 | gc.TFLOAT64:
+		a = arm64.AUCVTFD
+		goto rdst
+
+		/*
+		 * float to float
+		 */
+	case gc.TFLOAT32<<16 | gc.TFLOAT32:
+		a = arm64.AFMOVS
+
+	case gc.TFLOAT64<<16 | gc.TFLOAT64:
+		a = arm64.AFMOVD
+
+	case gc.TFLOAT32<<16 | gc.TFLOAT64:
+		a = arm64.AFCVTSD
+		goto rdst
+
+	case gc.TFLOAT64<<16 | gc.TFLOAT32:
+		a = arm64.AFCVTDS
+		goto rdst
+	}
+
+	gins(a, f, t)
+	return
+
+	// requires register destination
+rdst:
+	gc.Regalloc(&r1, t.Type, t)
+
+	gins(a, f, &r1)
+	gmove(&r1, t)
+	gc.Regfree(&r1)
+	return
+
+	// requires register intermediate
+hard:
+	gc.Regalloc(&r1, cvt, t)
+
+	gmove(f, &r1)
+	gmove(&r1, t)
+	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 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)
+
+	p := gc.Prog(as)
+	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)
+	}
+
+	w := int32(0)
+	switch as {
+	case arm64.AMOVB,
+		arm64.AMOVBU:
+		w = 1
+
+	case arm64.AMOVH,
+		arm64.AMOVHU:
+		w = 2
+
+	case arm64.AMOVW,
+		arm64.AMOVWU:
+		w = 4
+
+	case arm64.AMOVD:
+		if p.From.Type == obj.TYPE_CONST || p.From.Type == obj.TYPE_ADDR {
+			break
+		}
+		w = 8
+	}
+
+	if w != 0 && ((f != nil && p.From.Width < int64(w)) || (t != nil && p.To.Type != obj.TYPE_REG && p.To.Width > int64(w))) {
+		gc.Dump("f", f)
+		gc.Dump("t", t)
+		gc.Fatal("bad width: %v (%d, %d)\n", p, p.From.Width, p.To.Width)
+	}
+
+	return p
+}
+
+func fixlargeoffset(n *gc.Node) {
+	if n == nil {
+		return
+	}
+	if n.Op != gc.OINDREG {
+		return
+	}
+	if -4096 <= n.Xoffset && n.Xoffset < 4096 {
+		return
+	}
+	a := gc.Node(*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
+}
+
+/*
+ * insert n into reg slot of p
+ */
+func raddr(n *gc.Node, p *obj.Prog) {
+	var a obj.Addr
+
+	gc.Naddr(&a, n)
+	if a.Type != obj.TYPE_REG {
+		if n != nil {
+			gc.Fatal("bad in raddr: %v", gc.Oconv(int(n.Op), 0))
+		} else {
+			gc.Fatal("bad in raddr: <null>")
+		}
+		p.Reg = 0
+	} else {
+		p.Reg = a.Reg
+	}
+}
+
+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 := rawgins(as, rhs, nil)
+	raddr(lhs, p)
+	return p
+}
+
+/*
+ * return Axxx for Oxxx on type t.
+ */
+func optoas(op int, t *gc.Type) int {
+	if t == nil {
+		gc.Fatal("optoas: t is nil")
+	}
+
+	a := int(obj.AXXX)
+	switch uint32(op)<<16 | uint32(gc.Simtype[t.Etype]) {
+	default:
+		gc.Fatal("optoas: no entry for op=%v type=%v", gc.Oconv(int(op), 0), gc.Tconv(t, 0))
+
+	case gc.OEQ<<16 | gc.TBOOL,
+		gc.OEQ<<16 | gc.TINT8,
+		gc.OEQ<<16 | gc.TUINT8,
+		gc.OEQ<<16 | gc.TINT16,
+		gc.OEQ<<16 | gc.TUINT16,
+		gc.OEQ<<16 | gc.TINT32,
+		gc.OEQ<<16 | gc.TUINT32,
+		gc.OEQ<<16 | gc.TINT64,
+		gc.OEQ<<16 | gc.TUINT64,
+		gc.OEQ<<16 | gc.TPTR32,
+		gc.OEQ<<16 | gc.TPTR64,
+		gc.OEQ<<16 | gc.TFLOAT32,
+		gc.OEQ<<16 | gc.TFLOAT64:
+		a = arm64.ABEQ
+
+	case gc.ONE<<16 | gc.TBOOL,
+		gc.ONE<<16 | gc.TINT8,
+		gc.ONE<<16 | gc.TUINT8,
+		gc.ONE<<16 | gc.TINT16,
+		gc.ONE<<16 | gc.TUINT16,
+		gc.ONE<<16 | gc.TINT32,
+		gc.ONE<<16 | gc.TUINT32,
+		gc.ONE<<16 | gc.TINT64,
+		gc.ONE<<16 | gc.TUINT64,
+		gc.ONE<<16 | gc.TPTR32,
+		gc.ONE<<16 | gc.TPTR64,
+		gc.ONE<<16 | gc.TFLOAT32,
+		gc.ONE<<16 | gc.TFLOAT64:
+		a = arm64.ABNE
+
+	case gc.OLT<<16 | gc.TINT8,
+		gc.OLT<<16 | gc.TINT16,
+		gc.OLT<<16 | gc.TINT32,
+		gc.OLT<<16 | gc.TINT64:
+		a = arm64.ABLT
+
+	case gc.OLT<<16 | gc.TUINT8,
+		gc.OLT<<16 | gc.TUINT16,
+		gc.OLT<<16 | gc.TUINT32,
+		gc.OLT<<16 | gc.TUINT64,
+		gc.OLT<<16 | gc.TFLOAT32,
+		gc.OLT<<16 | gc.TFLOAT64:
+		a = arm64.ABLO
+
+	case gc.OLE<<16 | gc.TINT8,
+		gc.OLE<<16 | gc.TINT16,
+		gc.OLE<<16 | gc.TINT32,
+		gc.OLE<<16 | gc.TINT64:
+		a = arm64.ABLE
+
+	case gc.OLE<<16 | gc.TUINT8,
+		gc.OLE<<16 | gc.TUINT16,
+		gc.OLE<<16 | gc.TUINT32,
+		gc.OLE<<16 | gc.TUINT64,
+		gc.OLE<<16 | gc.TFLOAT32,
+		gc.OLE<<16 | gc.TFLOAT64:
+		a = arm64.ABLS
+
+	case gc.OGT<<16 | gc.TINT8,
+		gc.OGT<<16 | gc.TINT16,
+		gc.OGT<<16 | gc.TINT32,
+		gc.OGT<<16 | gc.TINT64,
+		gc.OGT<<16 | gc.TFLOAT32,
+		gc.OGT<<16 | gc.TFLOAT64:
+		a = arm64.ABGT
+
+	case gc.OGT<<16 | gc.TUINT8,
+		gc.OGT<<16 | gc.TUINT16,
+		gc.OGT<<16 | gc.TUINT32,
+		gc.OGT<<16 | gc.TUINT64:
+		a = arm64.ABHI
+
+	case gc.OGE<<16 | gc.TINT8,
+		gc.OGE<<16 | gc.TINT16,
+		gc.OGE<<16 | gc.TINT32,
+		gc.OGE<<16 | gc.TINT64,
+		gc.OGE<<16 | gc.TFLOAT32,
+		gc.OGE<<16 | gc.TFLOAT64:
+		a = arm64.ABGE
+
+	case gc.OGE<<16 | gc.TUINT8,
+		gc.OGE<<16 | gc.TUINT16,
+		gc.OGE<<16 | gc.TUINT32,
+		gc.OGE<<16 | gc.TUINT64:
+		a = arm64.ABHS
+
+	case gc.OCMP<<16 | gc.TBOOL,
+		gc.OCMP<<16 | gc.TINT8,
+		gc.OCMP<<16 | gc.TINT16,
+		gc.OCMP<<16 | gc.TINT32,
+		gc.OCMP<<16 | gc.TPTR32,
+		gc.OCMP<<16 | gc.TINT64,
+		gc.OCMP<<16 | gc.TUINT8,
+		gc.OCMP<<16 | gc.TUINT16,
+		gc.OCMP<<16 | gc.TUINT32,
+		gc.OCMP<<16 | gc.TUINT64,
+		gc.OCMP<<16 | gc.TPTR64:
+		a = arm64.ACMP
+
+	case gc.OCMP<<16 | gc.TFLOAT32:
+		a = arm64.AFCMPS
+
+	case gc.OCMP<<16 | gc.TFLOAT64:
+		a = arm64.AFCMPD
+
+	case gc.OAS<<16 | gc.TBOOL,
+		gc.OAS<<16 | gc.TINT8:
+		a = arm64.AMOVB
+
+	case gc.OAS<<16 | gc.TUINT8:
+		a = arm64.AMOVBU
+
+	case gc.OAS<<16 | gc.TINT16:
+		a = arm64.AMOVH
+
+	case gc.OAS<<16 | gc.TUINT16:
+		a = arm64.AMOVHU
+
+	case gc.OAS<<16 | gc.TINT32:
+		a = arm64.AMOVW
+
+	case gc.OAS<<16 | gc.TUINT32,
+		gc.OAS<<16 | gc.TPTR32:
+		a = arm64.AMOVWU
+
+	case gc.OAS<<16 | gc.TINT64,
+		gc.OAS<<16 | gc.TUINT64,
+		gc.OAS<<16 | gc.TPTR64:
+		a = arm64.AMOVD
+
+	case gc.OAS<<16 | gc.TFLOAT32:
+		a = arm64.AFMOVS
+
+	case gc.OAS<<16 | gc.TFLOAT64:
+		a = arm64.AFMOVD
+
+	case gc.OADD<<16 | gc.TINT8,
+		gc.OADD<<16 | gc.TUINT8,
+		gc.OADD<<16 | gc.TINT16,
+		gc.OADD<<16 | gc.TUINT16,
+		gc.OADD<<16 | gc.TINT32,
+		gc.OADD<<16 | gc.TUINT32,
+		gc.OADD<<16 | gc.TPTR32,
+		gc.OADD<<16 | gc.TINT64,
+		gc.OADD<<16 | gc.TUINT64,
+		gc.OADD<<16 | gc.TPTR64:
+		a = arm64.AADD
+
+	case gc.OADD<<16 | gc.TFLOAT32:
+		a = arm64.AFADDS
+
+	case gc.OADD<<16 | gc.TFLOAT64:
+		a = arm64.AFADDD
+
+	case gc.OSUB<<16 | gc.TINT8,
+		gc.OSUB<<16 | gc.TUINT8,
+		gc.OSUB<<16 | gc.TINT16,
+		gc.OSUB<<16 | gc.TUINT16,
+		gc.OSUB<<16 | gc.TINT32,
+		gc.OSUB<<16 | gc.TUINT32,
+		gc.OSUB<<16 | gc.TPTR32,
+		gc.OSUB<<16 | gc.TINT64,
+		gc.OSUB<<16 | gc.TUINT64,
+		gc.OSUB<<16 | gc.TPTR64:
+		a = arm64.ASUB
+
+	case gc.OSUB<<16 | gc.TFLOAT32:
+		a = arm64.AFSUBS
+
+	case gc.OSUB<<16 | gc.TFLOAT64:
+		a = arm64.AFSUBD
+
+	case gc.OMINUS<<16 | gc.TINT8,
+		gc.OMINUS<<16 | gc.TUINT8,
+		gc.OMINUS<<16 | gc.TINT16,
+		gc.OMINUS<<16 | gc.TUINT16,
+		gc.OMINUS<<16 | gc.TINT32,
+		gc.OMINUS<<16 | gc.TUINT32,
+		gc.OMINUS<<16 | gc.TPTR32,
+		gc.OMINUS<<16 | gc.TINT64,
+		gc.OMINUS<<16 | gc.TUINT64,
+		gc.OMINUS<<16 | gc.TPTR64:
+		a = arm64.ANEG
+
+	case gc.OMINUS<<16 | gc.TFLOAT32:
+		a = arm64.AFNEGS
+
+	case gc.OMINUS<<16 | gc.TFLOAT64:
+		a = arm64.AFNEGD
+
+	case gc.OAND<<16 | gc.TINT8,
+		gc.OAND<<16 | gc.TUINT8,
+		gc.OAND<<16 | gc.TINT16,
+		gc.OAND<<16 | gc.TUINT16,
+		gc.OAND<<16 | gc.TINT32,
+		gc.OAND<<16 | gc.TUINT32,
+		gc.OAND<<16 | gc.TPTR32,
+		gc.OAND<<16 | gc.TINT64,
+		gc.OAND<<16 | gc.TUINT64,
+		gc.OAND<<16 | gc.TPTR64:
+		a = arm64.AAND
+
+	case gc.OOR<<16 | gc.TINT8,
+		gc.OOR<<16 | gc.TUINT8,
+		gc.OOR<<16 | gc.TINT16,
+		gc.OOR<<16 | gc.TUINT16,
+		gc.OOR<<16 | gc.TINT32,
+		gc.OOR<<16 | gc.TUINT32,
+		gc.OOR<<16 | gc.TPTR32,
+		gc.OOR<<16 | gc.TINT64,
+		gc.OOR<<16 | gc.TUINT64,
+		gc.OOR<<16 | gc.TPTR64:
+		a = arm64.AORR
+
+	case gc.OXOR<<16 | gc.TINT8,
+		gc.OXOR<<16 | gc.TUINT8,
+		gc.OXOR<<16 | gc.TINT16,
+		gc.OXOR<<16 | gc.TUINT16,
+		gc.OXOR<<16 | gc.TINT32,
+		gc.OXOR<<16 | gc.TUINT32,
+		gc.OXOR<<16 | gc.TPTR32,
+		gc.OXOR<<16 | gc.TINT64,
+		gc.OXOR<<16 | gc.TUINT64,
+		gc.OXOR<<16 | gc.TPTR64:
+		a = arm64.AEOR
+
+		// TODO(minux): handle rotates
+	//case CASE(OLROT, TINT8):
+	//case CASE(OLROT, TUINT8):
+	//case CASE(OLROT, TINT16):
+	//case CASE(OLROT, TUINT16):
+	//case CASE(OLROT, TINT32):
+	//case CASE(OLROT, TUINT32):
+	//case CASE(OLROT, TPTR32):
+	//case CASE(OLROT, TINT64):
+	//case CASE(OLROT, TUINT64):
+	//case CASE(OLROT, TPTR64):
+	//	a = 0//???; RLDC?
+	//	break;
+
+	case gc.OLSH<<16 | gc.TINT8,
+		gc.OLSH<<16 | gc.TUINT8,
+		gc.OLSH<<16 | gc.TINT16,
+		gc.OLSH<<16 | gc.TUINT16,
+		gc.OLSH<<16 | gc.TINT32,
+		gc.OLSH<<16 | gc.TUINT32,
+		gc.OLSH<<16 | gc.TPTR32,
+		gc.OLSH<<16 | gc.TINT64,
+		gc.OLSH<<16 | gc.TUINT64,
+		gc.OLSH<<16 | gc.TPTR64:
+		a = arm64.ALSL
+
+	case gc.ORSH<<16 | gc.TUINT8,
+		gc.ORSH<<16 | gc.TUINT16,
+		gc.ORSH<<16 | gc.TUINT32,
+		gc.ORSH<<16 | gc.TPTR32,
+		gc.ORSH<<16 | gc.TUINT64,
+		gc.ORSH<<16 | gc.TPTR64:
+		a = arm64.ALSR
+
+	case gc.ORSH<<16 | gc.TINT8,
+		gc.ORSH<<16 | gc.TINT16,
+		gc.ORSH<<16 | gc.TINT32,
+		gc.ORSH<<16 | gc.TINT64:
+		a = arm64.AASR
+
+		// TODO(minux): handle rotates
+	//case CASE(ORROTC, TINT8):
+	//case CASE(ORROTC, TUINT8):
+	//case CASE(ORROTC, TINT16):
+	//case CASE(ORROTC, TUINT16):
+	//case CASE(ORROTC, TINT32):
+	//case CASE(ORROTC, TUINT32):
+	//case CASE(ORROTC, TINT64):
+	//case CASE(ORROTC, TUINT64):
+	//	a = 0//??? RLDC??
+	//	break;
+
+	case gc.OHMUL<<16 | gc.TINT64:
+		a = arm64.ASMULH
+
+	case gc.OHMUL<<16 | gc.TUINT64,
+		gc.OHMUL<<16 | gc.TPTR64:
+		a = arm64.AUMULH
+
+	case gc.OMUL<<16 | gc.TINT8,
+		gc.OMUL<<16 | gc.TINT16,
+		gc.OMUL<<16 | gc.TINT32:
+		a = arm64.ASMULL
+
+	case gc.OMUL<<16 | gc.TINT64:
+		a = arm64.AMUL
+
+	case gc.OMUL<<16 | gc.TUINT8,
+		gc.OMUL<<16 | gc.TUINT16,
+		gc.OMUL<<16 | gc.TUINT32,
+		gc.OMUL<<16 | gc.TPTR32:
+		// don't use word multiply, the high 32-bit are undefined.
+		a = arm64.AUMULL
+
+	case gc.OMUL<<16 | gc.TUINT64,
+		gc.OMUL<<16 | gc.TPTR64:
+		a = arm64.AMUL // for 64-bit multiplies, signedness doesn't matter.
+
+	case gc.OMUL<<16 | gc.TFLOAT32:
+		a = arm64.AFMULS
+
+	case gc.OMUL<<16 | gc.TFLOAT64:
+		a = arm64.AFMULD
+
+	case gc.ODIV<<16 | gc.TINT8,
+		gc.ODIV<<16 | gc.TINT16,
+		gc.ODIV<<16 | gc.TINT32,
+		gc.ODIV<<16 | gc.TINT64:
+		a = arm64.ASDIV
+
+	case gc.ODIV<<16 | gc.TUINT8,
+		gc.ODIV<<16 | gc.TUINT16,
+		gc.ODIV<<16 | gc.TUINT32,
+		gc.ODIV<<16 | gc.TPTR32,
+		gc.ODIV<<16 | gc.TUINT64,
+		gc.ODIV<<16 | gc.TPTR64:
+		a = arm64.AUDIV
+
+	case gc.ODIV<<16 | gc.TFLOAT32:
+		a = arm64.AFDIVS
+
+	case gc.ODIV<<16 | gc.TFLOAT64:
+		a = arm64.AFDIVD
+	}
+
+	return a
+}
+
+const (
+	ODynam   = 1 << 0
+	OAddable = 1 << 1
+)
+
+func xgen(n *gc.Node, a *gc.Node, o int) bool {
+	// TODO(minux)
+
+	return -1 != 0 /*TypeKind(100016)*/
+}
+
+func sudoclean() {
+	return
+}
+
+/*
+ * generate code to compute address of n,
+ * a reference to a (perhaps nested) field inside
+ * an array or struct.
+ * return 0 on failure, 1 on success.
+ * on success, leaves usable address in a.
+ *
+ * caller is responsible for calling sudoclean
+ * after successful sudoaddable,
+ * to release the register used for a.
+ */
+func sudoaddable(as int, n *gc.Node, a *obj.Addr) bool {
+	// TODO(minux)
+
+	*a = obj.Addr{}
+	return false
+}
diff --git a/src/cmd/7g/peep.go b/src/cmd/7g/peep.go
new file mode 100644
index 0000000..7faef1a
--- /dev/null
+++ b/src/cmd/7g/peep.go
@@ -0,0 +1,81 @@
+// Derived from Inferno utils/6c/peep.c
+// http://code.google.com/p/inferno-os/source/browse/utils/6c/peep.c
+//
+//	Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
+//	Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
+//	Portions Copyright © 1997-1999 Vita Nuova Limited
+//	Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
+//	Portions Copyright © 2004,2006 Bruce Ellis
+//	Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
+//	Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
+//	Portions Copyright © 2009 The Go Authors.  All rights reserved.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+package main
+
+import (
+	"cmd/internal/gc"
+	"cmd/internal/obj"
+	"cmd/internal/obj/arm64"
+	"fmt"
+)
+
+var gactive uint32
+
+func peep(firstp *obj.Prog) {
+	// TODO(aram)
+}
+
+func excise(r *gc.Flow) {
+	p := (*obj.Prog)(r.Prog)
+	if gc.Debug['P'] != 0 && gc.Debug['v'] != 0 {
+		fmt.Printf("%v ===delete===\n", p)
+	}
+	obj.Nopout(p)
+	gc.Ostats.Ndelmov++
+}
+
+func regtyp(a *obj.Addr) bool {
+	// TODO(rsc): Floating point register exclusions?
+	return a.Type == obj.TYPE_REG && arm64.REG_R0 <= a.Reg && a.Reg <= arm64.REG_F31 && a.Reg != arm64.REGZERO
+}
+
+func sameaddr(a *obj.Addr, v *obj.Addr) bool {
+	if a.Type != v.Type {
+		return false
+	}
+	if regtyp(v) && a.Reg == v.Reg {
+		return true
+	}
+	if v.Type == obj.NAME_AUTO || v.Type == obj.NAME_PARAM {
+		if v.Offset == a.Offset {
+			return true
+		}
+	}
+	return false
+}
+
+func smallindir(a *obj.Addr, reg *obj.Addr) bool {
+	return reg.Type == obj.TYPE_REG && a.Type == obj.TYPE_MEM && a.Reg == reg.Reg && 0 <= a.Offset && a.Offset < 4096
+}
+
+func stackaddr(a *obj.Addr) bool {
+	return a.Type == obj.TYPE_REG && a.Reg == arm64.REGSP
+}
diff --git a/src/cmd/7g/prog.go b/src/cmd/7g/prog.go
new file mode 100644
index 0000000..4afb29b
--- /dev/null
+++ b/src/cmd/7g/prog.go
@@ -0,0 +1,171 @@
+// 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.
+
+package main
+
+import (
+	"cmd/internal/gc"
+	"cmd/internal/obj"
+	"cmd/internal/obj/arm64"
+)
+
+const (
+	LeftRdwr  uint32 = gc.LeftRead | gc.LeftWrite
+	RightRdwr uint32 = gc.RightRead | gc.RightWrite
+)
+
+// This table gives the basic information about instruction
+// generated by the compiler and processed in the optimizer.
+// See opt.h for bit definitions.
+//
+// Instructions not generated need not be listed.
+// As an exception to that rule, we typically write down all the
+// size variants of an operation even if we just use a subset.
+//
+// The table is formatted for 8-space tabs.
+var progtable = [arm64.ALAST]obj.ProgInfo{
+	obj.ATYPE:     {gc.Pseudo | gc.Skip, 0, 0, 0},
+	obj.ATEXT:     {gc.Pseudo, 0, 0, 0},
+	obj.AFUNCDATA: {gc.Pseudo, 0, 0, 0},
+	obj.APCDATA:   {gc.Pseudo, 0, 0, 0},
+	obj.AUNDEF:    {gc.Break, 0, 0, 0},
+	obj.AUSEFIELD: {gc.OK, 0, 0, 0},
+	obj.ACHECKNIL: {gc.LeftRead, 0, 0, 0},
+	obj.AVARDEF:   {gc.Pseudo | gc.RightWrite, 0, 0, 0},
+	obj.AVARKILL:  {gc.Pseudo | gc.RightWrite, 0, 0, 0},
+
+	// NOP is an internal no-op that also stands
+	// for USED and SET annotations, not the Power opcode.
+	obj.ANOP:    {gc.LeftRead | gc.RightWrite, 0, 0, 0},
+	arm64.AHINT: {gc.OK, 0, 0, 0},
+
+	// Integer
+	arm64.AADD:   {gc.SizeQ | gc.LeftRead | gc.RegRead | gc.RightWrite, 0, 0, 0},
+	arm64.ASUB:   {gc.SizeQ | gc.LeftRead | gc.RegRead | gc.RightWrite, 0, 0, 0},
+	arm64.ANEG:   {gc.SizeQ | gc.LeftRead | gc.RegRead | gc.RightWrite, 0, 0, 0},
+	arm64.AAND:   {gc.SizeQ | gc.LeftRead | gc.RegRead | gc.RightWrite, 0, 0, 0},
+	arm64.AORR:   {gc.SizeQ | gc.LeftRead | gc.RegRead | gc.RightWrite, 0, 0, 0},
+	arm64.AEOR:   {gc.SizeQ | gc.LeftRead | gc.RegRead | gc.RightWrite, 0, 0, 0},
+	arm64.AMUL:   {gc.SizeQ | gc.LeftRead | gc.RegRead | gc.RightWrite, 0, 0, 0},
+	arm64.ASMULL: {gc.SizeQ | gc.LeftRead | gc.RegRead | gc.RightWrite, 0, 0, 0},
+	arm64.AUMULL: {gc.SizeQ | gc.LeftRead | gc.RegRead | gc.RightWrite, 0, 0, 0},
+	arm64.ASMULH: {gc.SizeL | gc.LeftRead | gc.RegRead | gc.RightWrite, 0, 0, 0},
+	arm64.AUMULH: {gc.SizeL | gc.LeftRead | gc.RegRead | gc.RightWrite, 0, 0, 0},
+	arm64.ASDIV:  {gc.SizeQ | gc.LeftRead | gc.RegRead | gc.RightWrite, 0, 0, 0},
+	arm64.AUDIV:  {gc.SizeQ | gc.LeftRead | gc.RegRead | gc.RightWrite, 0, 0, 0},
+	arm64.ALSL:   {gc.SizeQ | gc.LeftRead | gc.RegRead | gc.RightWrite, 0, 0, 0},
+	arm64.ALSR:   {gc.SizeQ | gc.LeftRead | gc.RegRead | gc.RightWrite, 0, 0, 0},
+	arm64.AASR:   {gc.SizeQ | gc.LeftRead | gc.RegRead | gc.RightWrite, 0, 0, 0},
+	arm64.ACMP:   {gc.SizeQ | gc.LeftRead | gc.RightRead, 0, 0, 0},
+
+	// Floating point.
+	arm64.AFADDD: {gc.SizeD | gc.LeftRead | gc.RegRead | gc.RightWrite, 0, 0, 0},
+	arm64.AFADDS: {gc.SizeF | gc.LeftRead | gc.RegRead | gc.RightWrite, 0, 0, 0},
+	arm64.AFSUBD: {gc.SizeD | gc.LeftRead | gc.RegRead | gc.RightWrite, 0, 0, 0},
+	arm64.AFSUBS: {gc.SizeF | gc.LeftRead | gc.RegRead | gc.RightWrite, 0, 0, 0},
+	arm64.AFNEGD: {gc.SizeD | gc.LeftRead | gc.RightWrite, 0, 0, 0},
+	arm64.AFNEGS: {gc.SizeF | gc.LeftRead | gc.RightWrite, 0, 0, 0},
+	arm64.AFMULD: {gc.SizeD | gc.LeftRead | gc.RegRead | gc.RightWrite, 0, 0, 0},
+	arm64.AFMULS: {gc.SizeF | gc.LeftRead | gc.RegRead | gc.RightWrite, 0, 0, 0},
+	arm64.AFDIVD: {gc.SizeD | gc.LeftRead | gc.RegRead | gc.RightWrite, 0, 0, 0},
+	arm64.AFDIVS: {gc.SizeF | gc.LeftRead | gc.RegRead | gc.RightWrite, 0, 0, 0},
+	arm64.AFCMPD: {gc.SizeD | gc.LeftRead | gc.RightRead, 0, 0, 0},
+	arm64.AFCMPS: {gc.SizeF | gc.LeftRead | gc.RightRead, 0, 0, 0},
+
+	// float -> integer
+	arm64.AFCVTZSD:  {gc.SizeD | gc.LeftRead | gc.RightWrite | gc.Conv, 0, 0, 0},
+	arm64.AFCVTZSS:  {gc.SizeF | gc.LeftRead | gc.RightWrite | gc.Conv, 0, 0, 0},
+	arm64.AFCVTZSDW: {gc.SizeD | gc.LeftRead | gc.RightWrite | gc.Conv, 0, 0, 0},
+	arm64.AFCVTZSSW: {gc.SizeF | gc.LeftRead | gc.RightWrite | gc.Conv, 0, 0, 0},
+	arm64.AFCVTZUD:  {gc.SizeD | gc.LeftRead | gc.RightWrite | gc.Conv, 0, 0, 0},
+	arm64.AFCVTZUS:  {gc.SizeF | gc.LeftRead | gc.RightWrite | gc.Conv, 0, 0, 0},
+	arm64.AFCVTZUDW: {gc.SizeD | gc.LeftRead | gc.RightWrite | gc.Conv, 0, 0, 0},
+	arm64.AFCVTZUSW: {gc.SizeF | gc.LeftRead | gc.RightWrite | gc.Conv, 0, 0, 0},
+
+	// float -> float
+	arm64.AFCVTSD: {gc.SizeD | gc.LeftRead | gc.RightWrite | gc.Conv, 0, 0, 0},
+	arm64.AFCVTDS: {gc.SizeD | gc.LeftRead | gc.RightWrite | gc.Conv, 0, 0, 0},
+
+	// integer -> float
+	arm64.ASCVTFD:  {gc.SizeQ | gc.LeftRead | gc.RightWrite | gc.Conv, 0, 0, 0},
+	arm64.ASCVTFS:  {gc.SizeQ | gc.LeftRead | gc.RightWrite | gc.Conv, 0, 0, 0},
+	arm64.ASCVTFWD: {gc.SizeL | gc.LeftRead | gc.RightWrite | gc.Conv, 0, 0, 0},
+	arm64.ASCVTFWS: {gc.SizeL | gc.LeftRead | gc.RightWrite | gc.Conv, 0, 0, 0},
+	arm64.AUCVTFD:  {gc.SizeQ | gc.LeftRead | gc.RightWrite | gc.Conv, 0, 0, 0},
+	arm64.AUCVTFS:  {gc.SizeQ | gc.LeftRead | gc.RightWrite | gc.Conv, 0, 0, 0},
+	arm64.AUCVTFWD: {gc.SizeL | gc.LeftRead | gc.RightWrite | gc.Conv, 0, 0, 0},
+	arm64.AUCVTFWS: {gc.SizeL | gc.LeftRead | gc.RightWrite | gc.Conv, 0, 0, 0},
+
+	// Moves
+	arm64.AMOVB:  {gc.SizeB | gc.LeftRead | gc.RightWrite | gc.Move | gc.Conv, 0, 0, 0},
+	arm64.AMOVBU: {gc.SizeB | gc.LeftRead | gc.RightWrite | gc.Move | gc.Conv, 0, 0, 0},
+	arm64.AMOVH:  {gc.SizeW | gc.LeftRead | gc.RightWrite | gc.Move | gc.Conv, 0, 0, 0},
+	arm64.AMOVHU: {gc.SizeW | gc.LeftRead | gc.RightWrite | gc.Move | gc.Conv, 0, 0, 0},
+	arm64.AMOVW:  {gc.SizeL | gc.LeftRead | gc.RightWrite | gc.Move | gc.Conv, 0, 0, 0},
+	arm64.AMOVWU: {gc.SizeL | gc.LeftRead | gc.RightWrite | gc.Move | gc.Conv, 0, 0, 0},
+	arm64.AMOVD:  {gc.SizeQ | gc.LeftRead | gc.RightWrite | gc.Move, 0, 0, 0},
+	arm64.AFMOVS: {gc.SizeF | gc.LeftRead | gc.RightWrite | gc.Move | gc.Conv, 0, 0, 0},
+	arm64.AFMOVD: {gc.SizeD | gc.LeftRead | gc.RightWrite | gc.Move, 0, 0, 0},
+
+	// Jumps
+	arm64.AB:      {gc.Jump | gc.Break, 0, 0, 0},
+	arm64.ABL:     {gc.Call, 0, 0, 0},
+	arm64.ABEQ:    {gc.Cjmp, 0, 0, 0},
+	arm64.ABNE:    {gc.Cjmp, 0, 0, 0},
+	arm64.ABGE:    {gc.Cjmp, 0, 0, 0},
+	arm64.ABLT:    {gc.Cjmp, 0, 0, 0},
+	arm64.ABGT:    {gc.Cjmp, 0, 0, 0},
+	arm64.ABLE:    {gc.Cjmp, 0, 0, 0},
+	arm64.ABLO:    {gc.Cjmp, 0, 0, 0},
+	arm64.ABLS:    {gc.Cjmp, 0, 0, 0},
+	arm64.ABHI:    {gc.Cjmp, 0, 0, 0},
+	arm64.ABHS:    {gc.Cjmp, 0, 0, 0},
+	obj.ARET:      {gc.Break, 0, 0, 0},
+	obj.ADUFFZERO: {gc.Call, 0, 0, 0},
+	obj.ADUFFCOPY: {gc.Call, 0, 0, 0},
+}
+
+func proginfo(p *obj.Prog) {
+	info := &p.Info
+	*info = progtable[p.As]
+	if info.Flags == 0 {
+		gc.Fatal("proginfo: unknown instruction %v", p)
+	}
+
+	if (info.Flags&gc.RegRead != 0) && p.Reg == 0 {
+		info.Flags &^= gc.RegRead
+		info.Flags |= gc.RightRead /*CanRegRead |*/
+	}
+
+	if (p.From.Type == obj.TYPE_MEM || p.From.Type == obj.TYPE_ADDR) && p.From.Reg != 0 {
+		info.Regindex |= RtoB(int(p.From.Reg))
+		if p.Scond != 0 {
+			info.Regset |= RtoB(int(p.From.Reg))
+		}
+	}
+
+	if (p.To.Type == obj.TYPE_MEM || p.To.Type == obj.TYPE_ADDR) && p.To.Reg != 0 {
+		info.Regindex |= RtoB(int(p.To.Reg))
+		if p.Scond != 0 {
+			info.Regset |= RtoB(int(p.To.Reg))
+		}
+	}
+
+	if p.From.Type == obj.TYPE_ADDR && p.From.Sym != nil && (info.Flags&gc.LeftRead != 0) {
+		info.Flags &^= gc.LeftRead
+		info.Flags |= gc.LeftAddr
+	}
+
+	if p.As == obj.ADUFFZERO {
+		info.Reguse |= RtoB(arm64.REGRT1)
+		info.Regset |= RtoB(arm64.REGRT1)
+	}
+
+	if p.As == obj.ADUFFCOPY {
+		// TODO(austin) Revisit when duffcopy is implemented
+		info.Reguse |= RtoB(arm64.REGRT1) | RtoB(arm64.REGRT2) | RtoB(arm64.REG_R5)
+
+		info.Regset |= RtoB(arm64.REGRT1) | RtoB(arm64.REGRT2)
+	}
+}
diff --git a/src/cmd/7g/reg.go b/src/cmd/7g/reg.go
new file mode 100644
index 0000000..c8035f5
--- /dev/null
+++ b/src/cmd/7g/reg.go
@@ -0,0 +1,164 @@
+// Derived from Inferno utils/6c/reg.c
+// http://code.google.com/p/inferno-os/source/browse/utils/6c/reg.c
+//
+//	Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
+//	Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
+//	Portions Copyright © 1997-1999 Vita Nuova Limited
+//	Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
+//	Portions Copyright © 2004,2006 Bruce Ellis
+//	Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
+//	Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
+//	Portions Copyright © 2009 The Go Authors.  All rights reserved.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+package main
+
+import (
+	"cmd/internal/gc"
+	"cmd/internal/obj/arm64"
+)
+
+const (
+	NREGVAR = 64 /* 32 general + 32 floating */
+)
+
+var regname = []string{
+	".R0",
+	".R1",
+	".R2",
+	".R3",
+	".R4",
+	".R5",
+	".R6",
+	".R7",
+	".R8",
+	".R9",
+	".R10",
+	".R11",
+	".R12",
+	".R13",
+	".R14",
+	".R15",
+	".R16",
+	".R17",
+	".R18",
+	".R19",
+	".R20",
+	".R21",
+	".R22",
+	".R23",
+	".R24",
+	".R25",
+	".R26",
+	".R27",
+	".R28",
+	".R29",
+	".R30",
+	".R31",
+	".F0",
+	".F1",
+	".F2",
+	".F3",
+	".F4",
+	".F5",
+	".F6",
+	".F7",
+	".F8",
+	".F9",
+	".F10",
+	".F11",
+	".F12",
+	".F13",
+	".F14",
+	".F15",
+	".F16",
+	".F17",
+	".F18",
+	".F19",
+	".F20",
+	".F21",
+	".F22",
+	".F23",
+	".F24",
+	".F25",
+	".F26",
+	".F27",
+	".F28",
+	".F29",
+	".F30",
+	".F31",
+}
+
+func regnames(n *int) []string {
+	*n = NREGVAR
+	return regname
+}
+
+func excludedregs() uint64 {
+	// Exclude registers with fixed functions
+	regbits := uint64(RtoB(arm64.REGRT1) | RtoB(arm64.REGRT2) | RtoB(arm64.REGPR))
+
+	// Also exclude floating point registers with fixed constants
+	regbits |= RtoB(arm64.REG_F27) | RtoB(arm64.REG_F28) | RtoB(arm64.REG_F29) | RtoB(arm64.REG_F30) | RtoB(arm64.REG_F31)
+
+	return regbits
+}
+
+func doregbits(r int) uint64 {
+	return 0
+}
+
+/*
+ * track register variables including external registers:
+ *	bit	reg
+ *	0	R0
+ *	1	R1
+ *	...	...
+ *	31	R31
+ *	32+0	F0
+ *	32+1	F1
+ *	...	...
+ *	32+31	F31
+ */
+func RtoB(r int) uint64 {
+	if r >= arm64.REG_R0 && r <= arm64.REG_R31 {
+		return 1 << uint(r-arm64.REG_R0)
+	}
+	if r >= arm64.REG_F0 && r <= arm64.REG_F31 {
+		return 1 << uint(32+r-arm64.REG_F0)
+	}
+	return 0
+}
+
+func BtoR(b uint64) int {
+	b &= 0xffffffff
+	if b == 0 {
+		return 0
+	}
+	return gc.Bitno(b) + arm64.REG_R0
+}
+
+func BtoF(b uint64) int {
+	b >>= 32
+	if b == 0 {
+		return 0
+	}
+	return gc.Bitno(b) + arm64.REG_F0
+}
diff --git a/src/cmd/internal/obj/i386/util.go b/src/cmd/7g/util.go
similarity index 94%
rename from src/cmd/internal/obj/i386/util.go
rename to src/cmd/7g/util.go
index b3e9643..bb5eedb 100644
--- a/src/cmd/internal/obj/i386/util.go
+++ b/src/cmd/7g/util.go
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-package i386
+package main
 
 func bool2int(b bool) int {
 	if b {
diff --git a/src/cmd/7l/asm.go b/src/cmd/7l/asm.go
new file mode 100644
index 0000000..d597ace
--- /dev/null
+++ b/src/cmd/7l/asm.go
@@ -0,0 +1,260 @@
+// Inferno utils/5l/asm.c
+// http://code.google.com/p/inferno-os/source/browse/utils/5l/asm.c
+//
+//	Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
+//	Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
+//	Portions Copyright © 1997-1999 Vita Nuova Limited
+//	Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
+//	Portions Copyright © 2004,2006 Bruce Ellis
+//	Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
+//	Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
+//	Portions Copyright © 2009 The Go Authors.  All rights reserved.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+package main
+
+import (
+	"cmd/internal/ld"
+	"cmd/internal/obj"
+	"fmt"
+	"log"
+)
+
+func gentext() {}
+
+func needlib(name string) int {
+	if name[0] == '\x00' {
+		return 0
+	}
+
+	/* reuse hash code in symbol table */
+	p := fmt.Sprintf(".dynlib.%s", name)
+
+	s := ld.Linklookup(ld.Ctxt, p, 0)
+
+	if s.Type == 0 {
+		s.Type = 100 // avoid SDATA, etc.
+		return 1
+	}
+
+	return 0
+}
+
+func adddynrela(rel *ld.LSym, s *ld.LSym, r *ld.Reloc) {
+	log.Fatalf("adddynrela not implemented")
+}
+
+func adddynrel(s *ld.LSym, r *ld.Reloc) {
+	log.Fatalf("adddynrel not implemented")
+}
+
+func elfreloc1(r *ld.Reloc, sectoff int64) int {
+	// TODO(minux)
+	return -1
+}
+
+func elfsetupplt() {
+	// TODO(aram)
+	return
+}
+
+func machoreloc1(r *ld.Reloc, sectoff int64) int {
+	return -1
+}
+
+func archreloc(r *ld.Reloc, s *ld.LSym, val *int64) int {
+	if ld.Linkmode == ld.LinkExternal {
+		// TODO(minux): translate R_CALLARM64 into standard ELF relocation.
+		return -1
+	}
+
+	switch r.Type {
+	case ld.R_CONST:
+		*val = r.Add
+		return 0
+
+	case ld.R_GOTOFF:
+		*val = ld.Symaddr(r.Sym) + r.Add - ld.Symaddr(ld.Linklookup(ld.Ctxt, ".got", 0))
+		return 0
+
+	case ld.R_CALLARM64:
+		*val = int64((0xfc000000 & uint32(r.Add)) | uint32((ld.Symaddr(r.Sym)+r.Add*4-(s.Value+int64(r.Off)))/4))
+		return 0
+	}
+
+	return -1
+}
+
+func archrelocvariant(r *ld.Reloc, s *ld.LSym, t int64) int64 {
+	log.Fatalf("unexpected relocation variant")
+	return -1
+}
+
+func adddynsym(ctxt *ld.Link, s *ld.LSym) {
+	log.Fatalf("adddynsym not implemented")
+}
+
+func adddynlib(lib string) {
+	if needlib(lib) == 0 {
+		return
+	}
+
+	if ld.Iself {
+		s := ld.Linklookup(ld.Ctxt, ".dynstr", 0)
+		if s.Size == 0 {
+			ld.Addstring(s, "")
+		}
+		ld.Elfwritedynent(ld.Linklookup(ld.Ctxt, ".dynamic", 0), ld.DT_NEEDED, uint64(ld.Addstring(s, lib)))
+	} else {
+		ld.Diag("adddynlib: unsupported binary format")
+	}
+}
+
+func asmb() {
+	if ld.Debug['v'] != 0 {
+		fmt.Fprintf(&ld.Bso, "%5.2f asmb\n", obj.Cputime())
+	}
+	ld.Bflush(&ld.Bso)
+
+	if ld.Iself {
+		ld.Asmbelfsetup()
+	}
+
+	sect := ld.Segtext.Sect
+	ld.Cseek(int64(sect.Vaddr - ld.Segtext.Vaddr + ld.Segtext.Fileoff))
+	ld.Codeblk(int64(sect.Vaddr), int64(sect.Length))
+	for sect = sect.Next; sect != nil; sect = sect.Next {
+		ld.Cseek(int64(sect.Vaddr - ld.Segtext.Vaddr + ld.Segtext.Fileoff))
+		ld.Datblk(int64(sect.Vaddr), int64(sect.Length))
+	}
+
+	if ld.Segrodata.Filelen > 0 {
+		if ld.Debug['v'] != 0 {
+			fmt.Fprintf(&ld.Bso, "%5.2f rodatblk\n", obj.Cputime())
+		}
+		ld.Bflush(&ld.Bso)
+
+		ld.Cseek(int64(ld.Segrodata.Fileoff))
+		ld.Datblk(int64(ld.Segrodata.Vaddr), int64(ld.Segrodata.Filelen))
+	}
+
+	if ld.Debug['v'] != 0 {
+		fmt.Fprintf(&ld.Bso, "%5.2f datblk\n", obj.Cputime())
+	}
+	ld.Bflush(&ld.Bso)
+
+	ld.Cseek(int64(ld.Segdata.Fileoff))
+	ld.Datblk(int64(ld.Segdata.Vaddr), int64(ld.Segdata.Filelen))
+
+	/* output symbol table */
+	ld.Symsize = 0
+
+	ld.Lcsize = 0
+	symo := uint32(0)
+	if ld.Debug['s'] == 0 {
+		// TODO: rationalize
+		if ld.Debug['v'] != 0 {
+			fmt.Fprintf(&ld.Bso, "%5.2f sym\n", obj.Cputime())
+		}
+		ld.Bflush(&ld.Bso)
+		switch ld.HEADTYPE {
+		default:
+			if ld.Iself {
+				symo = uint32(ld.Segdata.Fileoff + ld.Segdata.Filelen)
+				symo = uint32(ld.Rnd(int64(symo), int64(ld.INITRND)))
+			}
+
+		case ld.Hplan9:
+			symo = uint32(ld.Segdata.Fileoff + ld.Segdata.Filelen)
+		}
+
+		ld.Cseek(int64(symo))
+		switch ld.HEADTYPE {
+		default:
+			if ld.Iself {
+				if ld.Debug['v'] != 0 {
+					fmt.Fprintf(&ld.Bso, "%5.2f elfsym\n", obj.Cputime())
+				}
+				ld.Asmelfsym()
+				ld.Cflush()
+				ld.Cwrite(ld.Elfstrdat)
+
+				if ld.Debug['v'] != 0 {
+					fmt.Fprintf(&ld.Bso, "%5.2f dwarf\n", obj.Cputime())
+				}
+				ld.Dwarfemitdebugsections()
+
+				if ld.Linkmode == ld.LinkExternal {
+					ld.Elfemitreloc()
+				}
+			}
+
+		case ld.Hplan9:
+			ld.Asmplan9sym()
+			ld.Cflush()
+
+			sym := ld.Linklookup(ld.Ctxt, "pclntab", 0)
+			if sym != nil {
+				ld.Lcsize = int32(len(sym.P))
+				for i := 0; int32(i) < ld.Lcsize; i++ {
+					ld.Cput(uint8(sym.P[i]))
+				}
+
+				ld.Cflush()
+			}
+		}
+	}
+
+	ld.Ctxt.Cursym = nil
+	if ld.Debug['v'] != 0 {
+		fmt.Fprintf(&ld.Bso, "%5.2f header\n", obj.Cputime())
+	}
+	ld.Bflush(&ld.Bso)
+	ld.Cseek(0)
+	switch ld.HEADTYPE {
+	default:
+	case ld.Hplan9: /* plan 9 */
+		ld.Thearch.Lput(0x647)                      /* magic */
+		ld.Thearch.Lput(uint32(ld.Segtext.Filelen)) /* sizes */
+		ld.Thearch.Lput(uint32(ld.Segdata.Filelen))
+		ld.Thearch.Lput(uint32(ld.Segdata.Length - ld.Segdata.Filelen))
+		ld.Thearch.Lput(uint32(ld.Symsize))      /* nsyms */
+		ld.Thearch.Lput(uint32(ld.Entryvalue())) /* va of entry */
+		ld.Thearch.Lput(0)
+		ld.Thearch.Lput(uint32(ld.Lcsize))
+
+	case ld.Hlinux,
+		ld.Hfreebsd,
+		ld.Hnetbsd,
+		ld.Hopenbsd,
+		ld.Hnacl:
+		ld.Asmbelf(int64(symo))
+	}
+
+	ld.Cflush()
+	if ld.Debug['c'] != 0 {
+		fmt.Printf("textsize=%d\n", ld.Segtext.Filelen)
+		fmt.Printf("datsize=%d\n", ld.Segdata.Filelen)
+		fmt.Printf("bsssize=%d\n", ld.Segdata.Length-ld.Segdata.Filelen)
+		fmt.Printf("symsize=%d\n", ld.Symsize)
+		fmt.Printf("lcsize=%d\n", ld.Lcsize)
+		fmt.Printf("total=%d\n", ld.Segtext.Filelen+ld.Segdata.Length+uint64(ld.Symsize)+uint64(ld.Lcsize))
+	}
+}
diff --git a/src/cmd/7l/l.go b/src/cmd/7l/l.go
new file mode 100644
index 0000000..6f90acb
--- /dev/null
+++ b/src/cmd/7l/l.go
@@ -0,0 +1,77 @@
+// Inferno utils/5l/asm.c
+// http://code.google.com/p/inferno-os/source/browse/utils/5l/asm.c
+//
+//	Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
+//	Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
+//	Portions Copyright © 1997-1999 Vita Nuova Limited
+//	Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
+//	Portions Copyright © 2004,2006 Bruce Ellis
+//	Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
+//	Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
+//	Portions Copyright © 2009 The Go Authors.  All rights reserved.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+package main
+
+// Writing object files.
+
+// cmd/9l/l.h from Vita Nuova.
+//
+//	Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
+//	Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
+//	Portions Copyright © 1997-1999 Vita Nuova Limited
+//	Portions Copyright © 2000-2008 Vita Nuova Holdings Limited (www.vitanuova.com)
+//	Portions Copyright © 2004,2006 Bruce Ellis
+//	Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
+//	Revisions Copyright © 2000-2008 Lucent Technologies Inc. and others
+//	Portions Copyright © 2009 The Go Authors.  All rights reserved.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+const (
+	thechar   = '7'
+	PtrSize   = 8
+	IntSize   = 8
+	RegSize   = 8
+	MaxAlign  = 32 // max data alignment
+	FuncAlign = 8
+	MINLC     = 4
+)
+
+/* Used by ../ld/dwarf.c */
+const (
+	DWARFREGSP = 31
+)
diff --git a/src/cmd/7l/obj.go b/src/cmd/7l/obj.go
new file mode 100644
index 0000000..3fa70f2
--- /dev/null
+++ b/src/cmd/7l/obj.go
@@ -0,0 +1,152 @@
+// Inferno utils/5l/obj.c
+// http://code.google.com/p/inferno-os/source/browse/utils/5l/obj.c
+//
+//	Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
+//	Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
+//	Portions Copyright © 1997-1999 Vita Nuova Limited
+//	Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
+//	Portions Copyright © 2004,2006 Bruce Ellis
+//	Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
+//	Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
+//	Portions Copyright © 2009 The Go Authors.  All rights reserved.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+package main
+
+import (
+	"cmd/internal/ld"
+	"cmd/internal/obj"
+	"fmt"
+	"log"
+)
+
+// Reading object files.
+
+func main() {
+	linkarchinit()
+	ld.Ldmain()
+}
+
+func linkarchinit() {
+	ld.Thestring = obj.Getgoarch()
+	ld.Thelinkarch = &ld.Linkarm64
+
+	ld.Thearch.Thechar = thechar
+	ld.Thearch.Ptrsize = ld.Thelinkarch.Ptrsize
+	ld.Thearch.Intsize = ld.Thelinkarch.Ptrsize
+	ld.Thearch.Regsize = ld.Thelinkarch.Regsize
+	ld.Thearch.Funcalign = FuncAlign
+	ld.Thearch.Maxalign = MaxAlign
+	ld.Thearch.Minlc = MINLC
+	ld.Thearch.Dwarfregsp = DWARFREGSP
+
+	ld.Thearch.Adddynlib = adddynlib
+	ld.Thearch.Adddynrel = adddynrel
+	ld.Thearch.Adddynsym = adddynsym
+	ld.Thearch.Archinit = archinit
+	ld.Thearch.Archreloc = archreloc
+	ld.Thearch.Archrelocvariant = archrelocvariant
+	ld.Thearch.Asmb = asmb
+	ld.Thearch.Elfreloc1 = elfreloc1
+	ld.Thearch.Elfsetupplt = elfsetupplt
+	ld.Thearch.Gentext = gentext
+	ld.Thearch.Machoreloc1 = machoreloc1
+	ld.Thearch.Lput = ld.Lputl
+	ld.Thearch.Wput = ld.Wputl
+	ld.Thearch.Vput = ld.Vputl
+
+	ld.Thearch.Linuxdynld = "/lib/ld-linux-aarch64.so.1"
+
+	ld.Thearch.Freebsddynld = "XXX"
+	ld.Thearch.Openbsddynld = "XXX"
+	ld.Thearch.Netbsddynld = "XXX"
+	ld.Thearch.Dragonflydynld = "XXX"
+	ld.Thearch.Solarisdynld = "XXX"
+}
+
+func archinit() {
+	// getgoextlinkenabled is based on GO_EXTLINK_ENABLED when
+	// Go was built; see ../../make.bash.
+	if ld.Linkmode == ld.LinkAuto && obj.Getgoextlinkenabled() == "0" {
+		ld.Linkmode = ld.LinkInternal
+	}
+
+	switch ld.HEADTYPE {
+	default:
+		if ld.Linkmode == ld.LinkAuto {
+			ld.Linkmode = ld.LinkInternal
+		}
+		if ld.Linkmode == ld.LinkExternal && obj.Getgoextlinkenabled() != "1" {
+			log.Fatalf("cannot use -linkmode=external with -H %s", ld.Headstr(int(ld.HEADTYPE)))
+		}
+	}
+
+	switch ld.HEADTYPE {
+	default:
+		ld.Diag("unknown -H option")
+		ld.Errorexit()
+		fallthrough
+
+	case ld.Hplan9: /* plan 9 */
+		ld.HEADR = 32
+
+		if ld.INITTEXT == -1 {
+			ld.INITTEXT = 4128
+		}
+		if ld.INITDAT == -1 {
+			ld.INITDAT = 0
+		}
+		if ld.INITRND == -1 {
+			ld.INITRND = 4096
+		}
+
+	case ld.Hlinux: /* ppc64 elf */
+		ld.Debug['d'] = 1 // TODO(aram): dynamic linking is not supported yet.
+		ld.Elfinit()
+		ld.HEADR = ld.ELFRESERVE
+		if ld.INITTEXT == -1 {
+			ld.INITTEXT = 0x10000 + int64(ld.HEADR)
+		}
+		if ld.INITDAT == -1 {
+			ld.INITDAT = 0
+		}
+		if ld.INITRND == -1 {
+			ld.INITRND = 0x10000
+		}
+
+	case ld.Hnacl:
+		ld.Elfinit()
+		ld.HEADR = 0x10000
+		ld.Funcalign = 16
+		if ld.INITTEXT == -1 {
+			ld.INITTEXT = 0x20000
+		}
+		if ld.INITDAT == -1 {
+			ld.INITDAT = 0
+		}
+		if ld.INITRND == -1 {
+			ld.INITRND = 0x10000
+		}
+	}
+
+	if ld.INITDAT != 0 && ld.INITRND != 0 {
+		fmt.Printf("warning: -D0x%x is ignored because of -R0x%x\n", uint64(ld.INITDAT), uint32(ld.INITRND))
+	}
+}
diff --git a/src/cmd/8g/cgen.go b/src/cmd/8g/cgen.go
index ba8953a..5546aba3 100644
--- a/src/cmd/8g/cgen.go
+++ b/src/cmd/8g/cgen.go
@@ -5,513 +5,24 @@
 package main
 
 import (
+	"cmd/internal/gc"
 	"cmd/internal/obj"
-	"cmd/internal/obj/i386"
-	"fmt"
+	"cmd/internal/obj/x86"
 )
-import "cmd/internal/gc"
-
-/*
- * 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] != 0 {
-		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] != 0 && gc.Isfloat[nl.Type.Etype] != 0 {
-		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)
-		goto uop
-
-		// symmetric binary
-	case gc.OAND,
-		gc.OOR,
-		gc.OXOR,
-		gc.OADD,
-		gc.OMUL:
-		a = optoas(int(n.Op), nl.Type)
-
-		if a == i386.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 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(i386.ALEAL, nil, &n1)
-			gc.Datastring(nl.Val.U.Sval.S, &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
-
-sbop: // symmetric binary
-	if nl.Ullman < nr.Ullman || nl.Op == gc.OLITERAL {
-		r := nl
-		nl = nr
-		nr = r
-	}
-
-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
-
-uop: // unary
-	var n1 gc.Node
-	gc.Tempname(&n1, nl.Type)
-
-	cgen(nl, &n1)
-	gins(a, nil, &n1)
-	gmove(&n1, res)
-	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
@@ -519,861 +30,42 @@
 
 	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
 	}
 
 	var zero gc.Node
 	gc.Nodconst(&zero, gc.Types[gc.TINT32], 0)
-	gins(i386.ACMPL, &hi, &zero)
+	gins(x86.ACMPL, &hi, &zero)
 	splitclean()
-	return gc.Gbranch(i386.AJNE, nil, +1)
+	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(i386.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(i386.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:
-		p2 := (*obj.Prog)(nil) // 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] != 0 {
-			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.S)))
-			} 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(i386.ALEAL, nil, &n3)
-			gc.Datastring(nl.Val.U.Sval.S, &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(i386.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] == 0 {
-			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 != i386.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 = i386.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] != 0 && gc.Isfixedarray(n.Left.Left.Type)) {
-			if gc.Isconst(n.Right, gc.CTINT) {
-				// Compute &a.
-				if gc.Isptr[n.Left.Type.Etype] == 0 {
-					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
-	nr := (*gc.Node)(nil)
-
-	if nl != nil && gc.Isfloat[nl.Type.Etype] != 0 {
-		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 := i386.AJNE
-		if !true_ {
-			a = i386.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] != 0 {
-			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 := i386.AJNE
-	if !true_ {
-		a = i386.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] != 0 {
-			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] != 0 {
-			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 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], i386.REG_DI)
+	gc.Nodreg(&dst, gc.Types[gc.Tptr], x86.REG_DI)
 	var src gc.Node
-	gc.Nodreg(&src, gc.Types[gc.Tptr], i386.REG_SI)
+	gc.Nodreg(&src, gc.Types[gc.Tptr], x86.REG_SI)
 
 	var tsrc gc.Node
 	gc.Tempname(&tsrc, gc.Types[gc.Tptr])
 	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)
 	}
@@ -1383,7 +75,7 @@
 	}
 
 	if res.Addable != 0 {
-		agen(res, &dst)
+		gc.Agen(res, &dst)
 	} else {
 		gmove(&tdst, &dst)
 	}
@@ -1395,40 +87,40 @@
 	// the src and dst overlap, then reverse direction
 	if osrc < odst && int64(odst) < int64(osrc)+w {
 		// reverse direction
-		gins(i386.ASTD, nil, nil) // set direction flag
+		gins(x86.ASTD, nil, nil) // set direction flag
 		if c > 0 {
-			gconreg(i386.AADDL, w-1, i386.REG_SI)
-			gconreg(i386.AADDL, w-1, i386.REG_DI)
+			gconreg(x86.AADDL, w-1, x86.REG_SI)
+			gconreg(x86.AADDL, w-1, x86.REG_DI)
 
-			gconreg(i386.AMOVL, int64(c), i386.REG_CX)
-			gins(i386.AREP, nil, nil)   // repeat
-			gins(i386.AMOVSB, nil, nil) // MOVB *(SI)-,*(DI)-
+			gconreg(x86.AMOVL, int64(c), x86.REG_CX)
+			gins(x86.AREP, nil, nil)   // repeat
+			gins(x86.AMOVSB, nil, nil) // MOVB *(SI)-,*(DI)-
 		}
 
 		if q > 0 {
 			if c > 0 {
-				gconreg(i386.AADDL, -3, i386.REG_SI)
-				gconreg(i386.AADDL, -3, i386.REG_DI)
+				gconreg(x86.AADDL, -3, x86.REG_SI)
+				gconreg(x86.AADDL, -3, x86.REG_DI)
 			} else {
-				gconreg(i386.AADDL, w-4, i386.REG_SI)
-				gconreg(i386.AADDL, w-4, i386.REG_DI)
+				gconreg(x86.AADDL, w-4, x86.REG_SI)
+				gconreg(x86.AADDL, w-4, x86.REG_DI)
 			}
 
-			gconreg(i386.AMOVL, int64(q), i386.REG_CX)
-			gins(i386.AREP, nil, nil)   // repeat
-			gins(i386.AMOVSL, nil, nil) // MOVL *(SI)-,*(DI)-
+			gconreg(x86.AMOVL, int64(q), x86.REG_CX)
+			gins(x86.AREP, nil, nil)   // repeat
+			gins(x86.AMOVSL, nil, nil) // MOVL *(SI)-,*(DI)-
 		}
 
 		// we leave with the flag clear
-		gins(i386.ACLD, nil, nil)
+		gins(x86.ACLD, nil, nil)
 	} else {
-		gins(i386.ACLD, nil, nil) // paranoia.  TODO(rsc): remove?
+		gins(x86.ACLD, nil, nil) // paranoia.  TODO(rsc): remove?
 
 		// normal direction
 		if q > 128 || (q >= 4 && gc.Nacl) {
-			gconreg(i386.AMOVL, int64(q), i386.REG_CX)
-			gins(i386.AREP, nil, nil)   // repeat
-			gins(i386.AMOVSL, nil, nil) // MOVL *(SI)+,*(DI)+
+			gconreg(x86.AMOVL, int64(q), x86.REG_CX)
+			gins(x86.AREP, nil, nil)   // repeat
+			gins(x86.AMOVSL, nil, nil) // MOVL *(SI)+,*(DI)+
 		} else if q >= 4 {
 			p := gins(obj.ADUFFCOPY, nil, nil)
 			p.To.Type = obj.TYPE_ADDR
@@ -1438,7 +130,7 @@
 			p.To.Offset = 10 * (128 - int64(q))
 		} else if !gc.Nacl && c == 0 {
 			var cx gc.Node
-			gc.Nodreg(&cx, gc.Types[gc.TINT32], i386.REG_CX)
+			gc.Nodreg(&cx, gc.Types[gc.TINT32], x86.REG_CX)
 
 			// We don't need the MOVSL side-effect of updating SI and DI,
 			// and issuing a sequence of MOVLs directly is faster.
@@ -1454,279 +146,14 @@
 			}
 		} else {
 			for q > 0 {
-				gins(i386.AMOVSL, nil, nil) // MOVL *(SI)+,*(DI)+
+				gins(x86.AMOVSL, nil, nil) // MOVL *(SI)+,*(DI)+
 				q--
 			}
 		}
 
 		for c > 0 {
-			gins(i386.AMOVSB, nil, nil) // MOVB *(SI)+,*(DI)+
+			gins(x86.AMOVSB, nil, nil) // MOVB *(SI)+,*(DI)+
 			c--
 		}
 	}
 }
-
-func cadable(n *gc.Node) bool {
-	if n.Addable == 0 {
-		// dont know how it happens,
-		// but it does
-		return false
-	}
-
-	switch n.Op {
-	case gc.ONAME:
-		return true
-	}
-
-	return false
-}
-
-/*
- * copy a composite value by moving its individual components.
- * Slices, strings and interfaces are supported.
- * Small structs or arrays with elements of basic type are
- * also supported.
- * nr is N when assigning a zero value.
- * return 1 if can do, 0 if can't.
- */
-func componentgen(nr *gc.Node, nl *gc.Node) bool {
-	var nodl gc.Node
-	var nodr gc.Node
-
-	freel := 0
-	freer := 0
-
-	switch nl.Type.Etype {
-	default:
-		goto no
-
-	case gc.TARRAY:
-		t := nl.Type
-
-		// Slices are ok.
-		if gc.Isslice(t) {
-			break
-		}
-
-		// Small arrays are ok.
-		if t.Bound > 0 && t.Bound <= 3 && !gc.Isfat(t.Type) {
-			break
-		}
-
-		goto no
-
-		// Small structs with non-fat types are ok.
-	// Zero-sized structs are treated separately elsewhere.
-	case gc.TSTRUCT:
-		fldcount := int64(0)
-
-		for t := nl.Type.Type; t != nil; t = t.Down {
-			if gc.Isfat(t.Type) {
-				goto no
-			}
-			if t.Etype != gc.TFIELD {
-				gc.Fatal("componentgen: not a TFIELD: %v", gc.Tconv(t, obj.FmtLong))
-			}
-			fldcount++
-		}
-
-		if fldcount == 0 || fldcount > 4 {
-			goto no
-		}
-
-	case gc.TSTRING,
-		gc.TINTER:
-		break
-	}
-
-	nodl = *nl
-	if !cadable(nl) {
-		if nr != nil && !cadable(nr) {
-			goto no
-		}
-		igen(nl, &nodl, nil)
-		freel = 1
-	}
-
-	if nr != nil {
-		nodr = *nr
-		if !cadable(nr) {
-			igen(nr, &nodr, nil)
-			freer = 1
-		}
-	} else {
-		// When zeroing, prepare a register containing zero.
-		var tmp gc.Node
-		gc.Nodconst(&tmp, nl.Type, 0)
-
-		regalloc(&nodr, gc.Types[gc.TUINT], nil)
-		gmove(&tmp, &nodr)
-		freer = 1
-	}
-
-	// nl and nr are 'cadable' which basically means they are names (variables) now.
-	// If they are the same variable, don't generate any code, because the
-	// VARDEF we generate will mark the old value as dead incorrectly.
-	// (And also the assignments are useless.)
-	if nr != nil && nl.Op == gc.ONAME && nr.Op == gc.ONAME && nl == nr {
-		goto yes
-	}
-
-	switch nl.Type.Etype {
-	// componentgen for arrays.
-	case gc.TARRAY:
-		if nl.Op == gc.ONAME {
-			gc.Gvardef(nl)
-		}
-		t := nl.Type
-		if !gc.Isslice(t) {
-			nodl.Type = t.Type
-			nodr.Type = nodl.Type
-			for fldcount := int64(0); fldcount < t.Bound; fldcount++ {
-				if nr == nil {
-					gc.Clearslim(&nodl)
-				} else {
-					gmove(&nodr, &nodl)
-				}
-				nodl.Xoffset += t.Type.Width
-				nodr.Xoffset += t.Type.Width
-			}
-
-			goto yes
-		}
-
-		// componentgen for slices.
-		nodl.Xoffset += int64(gc.Array_array)
-
-		nodl.Type = gc.Ptrto(nl.Type.Type)
-
-		if nr != nil {
-			nodr.Xoffset += int64(gc.Array_array)
-			nodr.Type = nodl.Type
-		}
-
-		gmove(&nodr, &nodl)
-
-		nodl.Xoffset += int64(gc.Array_nel) - int64(gc.Array_array)
-		nodl.Type = gc.Types[gc.Simtype[gc.TUINT]]
-
-		if nr != nil {
-			nodr.Xoffset += int64(gc.Array_nel) - int64(gc.Array_array)
-			nodr.Type = nodl.Type
-		}
-
-		gmove(&nodr, &nodl)
-
-		nodl.Xoffset += int64(gc.Array_cap) - int64(gc.Array_nel)
-		nodl.Type = gc.Types[gc.Simtype[gc.TUINT]]
-
-		if nr != nil {
-			nodr.Xoffset += int64(gc.Array_cap) - int64(gc.Array_nel)
-			nodr.Type = nodl.Type
-		}
-
-		gmove(&nodr, &nodl)
-
-		goto yes
-
-	case gc.TSTRING:
-		if nl.Op == gc.ONAME {
-			gc.Gvardef(nl)
-		}
-		nodl.Xoffset += int64(gc.Array_array)
-		nodl.Type = gc.Ptrto(gc.Types[gc.TUINT8])
-
-		if nr != nil {
-			nodr.Xoffset += int64(gc.Array_array)
-			nodr.Type = nodl.Type
-		}
-
-		gmove(&nodr, &nodl)
-
-		nodl.Xoffset += int64(gc.Array_nel) - int64(gc.Array_array)
-		nodl.Type = gc.Types[gc.Simtype[gc.TUINT]]
-
-		if nr != nil {
-			nodr.Xoffset += int64(gc.Array_nel) - int64(gc.Array_array)
-			nodr.Type = nodl.Type
-		}
-
-		gmove(&nodr, &nodl)
-
-		goto yes
-
-	case gc.TINTER:
-		if nl.Op == gc.ONAME {
-			gc.Gvardef(nl)
-		}
-		nodl.Xoffset += int64(gc.Array_array)
-		nodl.Type = gc.Ptrto(gc.Types[gc.TUINT8])
-
-		if nr != nil {
-			nodr.Xoffset += int64(gc.Array_array)
-			nodr.Type = nodl.Type
-		}
-
-		gmove(&nodr, &nodl)
-
-		nodl.Xoffset += int64(gc.Array_nel) - int64(gc.Array_array)
-		nodl.Type = gc.Ptrto(gc.Types[gc.TUINT8])
-
-		if nr != nil {
-			nodr.Xoffset += int64(gc.Array_nel) - int64(gc.Array_array)
-			nodr.Type = nodl.Type
-		}
-
-		gmove(&nodr, &nodl)
-
-		goto yes
-
-	case gc.TSTRUCT:
-		if nl.Op == gc.ONAME {
-			gc.Gvardef(nl)
-		}
-		loffset := nodl.Xoffset
-		roffset := nodr.Xoffset
-
-		// funarg structs may not begin at offset zero.
-		if nl.Type.Etype == gc.TSTRUCT && nl.Type.Funarg != 0 && nl.Type.Type != nil {
-			loffset -= nl.Type.Type.Width
-		}
-		if nr != nil && nr.Type.Etype == gc.TSTRUCT && nr.Type.Funarg != 0 && nr.Type.Type != nil {
-			roffset -= nr.Type.Type.Width
-		}
-
-		for t := nl.Type.Type; t != nil; t = t.Down {
-			nodl.Xoffset = loffset + t.Width
-			nodl.Type = t.Type
-
-			if nr == nil {
-				gc.Clearslim(&nodl)
-			} else {
-				nodr.Xoffset = roffset + t.Width
-				nodr.Type = nodl.Type
-				gmove(&nodr, &nodl)
-			}
-		}
-
-		goto yes
-	}
-
-no:
-	if freer != 0 {
-		regfree(&nodr)
-	}
-	if freel != 0 {
-		regfree(&nodl)
-	}
-	return false
-
-yes:
-	if freer != 0 {
-		regfree(&nodr)
-	}
-	if freel != 0 {
-		regfree(&nodl)
-	}
-	return true
-}
diff --git a/src/cmd/8g/cgen64.go b/src/cmd/8g/cgen64.go
index 0755f0e..ee04bdb 100644
--- a/src/cmd/8g/cgen64.go
+++ b/src/cmd/8g/cgen64.go
@@ -5,10 +5,10 @@
 package main
 
 import (
+	"cmd/internal/gc"
 	"cmd/internal/obj"
-	"cmd/internal/obj/i386"
+	"cmd/internal/obj/x86"
 )
-import "cmd/internal/gc"
 
 /*
  * attempt to generate 64-bit
@@ -27,23 +27,23 @@
 		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)
-		gins(i386.ANEGL, nil, &lo1)
-		gins(i386.AADCL, ncon(0), &hi1)
-		gins(i386.ANEGL, nil, &hi1)
+		gins(x86.ANEGL, nil, &lo1)
+		gins(x86.AADCL, ncon(0), &hi1)
+		gins(x86.ANEGL, nil, &hi1)
 		splitclean()
 		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)
-		gins(i386.ANOTL, nil, &lo1)
-		gins(i386.ANOTL, nil, &hi1)
+		gins(x86.ANOTL, nil, &lo1)
+		gins(x86.ANOTL, nil, &hi1)
 		splitclean()
 		return
 
@@ -66,23 +66,23 @@
 	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
 	}
 
 	var ax gc.Node
-	gc.Nodreg(&ax, gc.Types[gc.TINT32], i386.REG_AX)
+	gc.Nodreg(&ax, gc.Types[gc.TINT32], x86.REG_AX)
 	var cx gc.Node
-	gc.Nodreg(&cx, gc.Types[gc.TINT32], i386.REG_CX)
+	gc.Nodreg(&cx, gc.Types[gc.TINT32], x86.REG_CX)
 	var dx gc.Node
-	gc.Nodreg(&dx, gc.Types[gc.TINT32], i386.REG_DX)
+	gc.Nodreg(&dx, gc.Types[gc.TINT32], x86.REG_DX)
 
 	// Setup for binary operation.
 	var hi1 gc.Node
@@ -99,57 +99,57 @@
 	switch n.Op {
 	// TODO: Constants
 	case gc.OADD:
-		gins(i386.AMOVL, &lo1, &ax)
+		gins(x86.AMOVL, &lo1, &ax)
 
-		gins(i386.AMOVL, &hi1, &dx)
-		gins(i386.AADDL, &lo2, &ax)
-		gins(i386.AADCL, &hi2, &dx)
+		gins(x86.AMOVL, &hi1, &dx)
+		gins(x86.AADDL, &lo2, &ax)
+		gins(x86.AADCL, &hi2, &dx)
 
 		// TODO: Constants.
 	case gc.OSUB:
-		gins(i386.AMOVL, &lo1, &ax)
+		gins(x86.AMOVL, &lo1, &ax)
 
-		gins(i386.AMOVL, &hi1, &dx)
-		gins(i386.ASUBL, &lo2, &ax)
-		gins(i386.ASBBL, &hi2, &dx)
+		gins(x86.AMOVL, &hi1, &dx)
+		gins(x86.ASUBL, &lo2, &ax)
+		gins(x86.ASBBL, &hi2, &dx)
 
 		// 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(i386.AMOVL, &lo1, &ax)
+		gins(x86.AMOVL, &lo1, &ax)
 
-		gins(i386.AMOVL, &hi1, &dx)
-		gins(i386.AMOVL, &lo2, &cx)
-		gins(i386.AMOVL, &hi2, &ex)
+		gins(x86.AMOVL, &hi1, &dx)
+		gins(x86.AMOVL, &lo2, &cx)
+		gins(x86.AMOVL, &hi2, &ex)
 
 		// if DX and EX are zero, use 32 x 32 -> 64 unsigned multiply.
-		gins(i386.AMOVL, &dx, &fx)
+		gins(x86.AMOVL, &dx, &fx)
 
-		gins(i386.AORL, &ex, &fx)
-		p1 := gc.Gbranch(i386.AJNE, nil, 0)
-		gins(i386.AMULL, &cx, nil) // implicit &ax
+		gins(x86.AORL, &ex, &fx)
+		p1 := gc.Gbranch(x86.AJNE, nil, 0)
+		gins(x86.AMULL, &cx, nil) // implicit &ax
 		p2 := gc.Gbranch(obj.AJMP, nil, 0)
 		gc.Patch(p1, gc.Pc)
 
 		// full 64x64 -> 64, from 32x32 -> 64.
-		gins(i386.AIMULL, &cx, &dx)
+		gins(x86.AIMULL, &cx, &dx)
 
-		gins(i386.AMOVL, &ax, &fx)
-		gins(i386.AIMULL, &ex, &fx)
-		gins(i386.AADDL, &dx, &fx)
-		gins(i386.AMOVL, &cx, &dx)
-		gins(i386.AMULL, &dx, nil) // implicit &ax
-		gins(i386.AADDL, &fx, &dx)
+		gins(x86.AMOVL, &ax, &fx)
+		gins(x86.AIMULL, &ex, &fx)
+		gins(x86.AADDL, &dx, &fx)
+		gins(x86.AMOVL, &cx, &dx)
+		gins(x86.AMULL, &dx, nil) // implicit &ax
+		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:
@@ -168,22 +168,22 @@
 			// reverse during load to do the first 32 bits of rotate
 			v -= 32
 
-			gins(i386.AMOVL, &lo1, &dx)
-			gins(i386.AMOVL, &hi1, &ax)
+			gins(x86.AMOVL, &lo1, &dx)
+			gins(x86.AMOVL, &hi1, &ax)
 		} else {
-			gins(i386.AMOVL, &lo1, &ax)
-			gins(i386.AMOVL, &hi1, &dx)
+			gins(x86.AMOVL, &lo1, &ax)
+			gins(x86.AMOVL, &hi1, &dx)
 		}
 
 		if v == 0 {
 		} else // done
 		{
-			gins(i386.AMOVL, &dx, &cx)
-			p1 := gins(i386.ASHLL, ncon(uint32(v)), &dx)
-			p1.From.Index = i386.REG_AX // double-width shift
+			gins(x86.AMOVL, &dx, &cx)
+			p1 := gins(x86.ASHLL, ncon(uint32(v)), &dx)
+			p1.From.Index = x86.REG_AX // double-width shift
 			p1.From.Scale = 0
-			p1 = gins(i386.ASHLL, ncon(uint32(v)), &ax)
-			p1.From.Index = i386.REG_CX // double-width shift
+			p1 = gins(x86.ASHLL, ncon(uint32(v)), &ax)
+			p1.From.Index = x86.REG_CX // double-width shift
 			p1.From.Scale = 0
 		}
 
@@ -196,10 +196,10 @@
 				}
 				splitclean()
 				split64(res, &lo2, &hi2)
-				gins(i386.AMOVL, ncon(0), &lo2)
-				gins(i386.AMOVL, ncon(0), &hi2)
+				gins(x86.AMOVL, ncon(0), &lo2)
+				gins(x86.AMOVL, ncon(0), &hi2)
 				splitclean()
-				goto out
+				return
 			}
 
 			if v >= 32 {
@@ -209,71 +209,71 @@
 				split64(res, &lo2, &hi2)
 				gmove(&lo1, &hi2)
 				if v > 32 {
-					gins(i386.ASHLL, ncon(uint32(v-32)), &hi2)
+					gins(x86.ASHLL, ncon(uint32(v-32)), &hi2)
 				}
 
-				gins(i386.AMOVL, ncon(0), &lo2)
+				gins(x86.AMOVL, ncon(0), &lo2)
 				splitclean()
 				splitclean()
-				goto out
+				return
 			}
 
 			// general shift
-			gins(i386.AMOVL, &lo1, &ax)
+			gins(x86.AMOVL, &lo1, &ax)
 
-			gins(i386.AMOVL, &hi1, &dx)
-			p1 := gins(i386.ASHLL, ncon(uint32(v)), &dx)
-			p1.From.Index = i386.REG_AX // double-width shift
+			gins(x86.AMOVL, &hi1, &dx)
+			p1 := gins(x86.ASHLL, ncon(uint32(v)), &dx)
+			p1.From.Index = x86.REG_AX // double-width shift
 			p1.From.Scale = 0
-			gins(i386.ASHLL, ncon(uint32(v)), &ax)
+			gins(x86.ASHLL, ncon(uint32(v)), &ax)
 			break
 		}
 
 		// load value into DX:AX.
-		gins(i386.AMOVL, &lo1, &ax)
+		gins(x86.AMOVL, &lo1, &ax)
 
-		gins(i386.AMOVL, &hi1, &dx)
+		gins(x86.AMOVL, &hi1, &dx)
 
 		// load shift value into register.
 		// if high bits are set, zero value.
-		p1 := (*obj.Prog)(nil)
+		var p1 *obj.Prog
 
 		if gc.Is64(r.Type) {
-			gins(i386.ACMPL, &hi2, ncon(0))
-			p1 = gc.Gbranch(i386.AJNE, nil, +1)
-			gins(i386.AMOVL, &lo2, &cx)
+			gins(x86.ACMPL, &hi2, ncon(0))
+			p1 = gc.Gbranch(x86.AJNE, nil, +1)
+			gins(x86.AMOVL, &lo2, &cx)
 		} else {
 			cx.Type = gc.Types[gc.TUINT32]
 			gmove(r, &cx)
 		}
 
 		// if shift count is >=64, zero value
-		gins(i386.ACMPL, &cx, ncon(64))
+		gins(x86.ACMPL, &cx, ncon(64))
 
 		p2 := gc.Gbranch(optoas(gc.OLT, gc.Types[gc.TUINT32]), nil, +1)
 		if p1 != nil {
 			gc.Patch(p1, gc.Pc)
 		}
-		gins(i386.AXORL, &dx, &dx)
-		gins(i386.AXORL, &ax, &ax)
+		gins(x86.AXORL, &dx, &dx)
+		gins(x86.AXORL, &ax, &ax)
 		gc.Patch(p2, gc.Pc)
 
 		// if shift count is >= 32, zero low.
-		gins(i386.ACMPL, &cx, ncon(32))
+		gins(x86.ACMPL, &cx, ncon(32))
 
 		p1 = gc.Gbranch(optoas(gc.OLT, gc.Types[gc.TUINT32]), nil, +1)
-		gins(i386.AMOVL, &ax, &dx)
-		gins(i386.ASHLL, &cx, &dx) // SHLL only uses bottom 5 bits of count
-		gins(i386.AXORL, &ax, &ax)
+		gins(x86.AMOVL, &ax, &dx)
+		gins(x86.ASHLL, &cx, &dx) // SHLL only uses bottom 5 bits of count
+		gins(x86.AXORL, &ax, &ax)
 		p2 = gc.Gbranch(obj.AJMP, nil, 0)
 		gc.Patch(p1, gc.Pc)
 
 		// general shift
-		p1 = gins(i386.ASHLL, &cx, &dx)
+		p1 = gins(x86.ASHLL, &cx, &dx)
 
-		p1.From.Index = i386.REG_AX // double-width shift
+		p1.From.Index = x86.REG_AX // double-width shift
 		p1.From.Scale = 0
-		gins(i386.ASHLL, &cx, &ax)
+		gins(x86.ASHLL, &cx, &ax)
 		gc.Patch(p2, gc.Pc)
 
 	case gc.ORSH:
@@ -287,16 +287,16 @@
 				split64(res, &lo2, &hi2)
 				if hi1.Type.Etype == gc.TINT32 {
 					gmove(&hi1, &lo2)
-					gins(i386.ASARL, ncon(31), &lo2)
+					gins(x86.ASARL, ncon(31), &lo2)
 					gmove(&hi1, &hi2)
-					gins(i386.ASARL, ncon(31), &hi2)
+					gins(x86.ASARL, ncon(31), &hi2)
 				} else {
-					gins(i386.AMOVL, ncon(0), &lo2)
-					gins(i386.AMOVL, ncon(0), &hi2)
+					gins(x86.AMOVL, ncon(0), &lo2)
+					gins(x86.AMOVL, ncon(0), &hi2)
 				}
 
 				splitclean()
-				goto out
+				return
 			}
 
 			if v >= 32 {
@@ -310,81 +310,81 @@
 				}
 				if hi1.Type.Etype == gc.TINT32 {
 					gmove(&hi1, &hi2)
-					gins(i386.ASARL, ncon(31), &hi2)
+					gins(x86.ASARL, ncon(31), &hi2)
 				} else {
-					gins(i386.AMOVL, ncon(0), &hi2)
+					gins(x86.AMOVL, ncon(0), &hi2)
 				}
 				splitclean()
 				splitclean()
-				goto out
+				return
 			}
 
 			// general shift
-			gins(i386.AMOVL, &lo1, &ax)
+			gins(x86.AMOVL, &lo1, &ax)
 
-			gins(i386.AMOVL, &hi1, &dx)
-			p1 := gins(i386.ASHRL, ncon(uint32(v)), &ax)
-			p1.From.Index = i386.REG_DX // double-width shift
+			gins(x86.AMOVL, &hi1, &dx)
+			p1 := gins(x86.ASHRL, ncon(uint32(v)), &ax)
+			p1.From.Index = x86.REG_DX // double-width shift
 			p1.From.Scale = 0
 			gins(optoas(gc.ORSH, hi1.Type), ncon(uint32(v)), &dx)
 			break
 		}
 
 		// load value into DX:AX.
-		gins(i386.AMOVL, &lo1, &ax)
+		gins(x86.AMOVL, &lo1, &ax)
 
-		gins(i386.AMOVL, &hi1, &dx)
+		gins(x86.AMOVL, &hi1, &dx)
 
 		// load shift value into register.
 		// if high bits are set, zero value.
-		p1 := (*obj.Prog)(nil)
+		var p1 *obj.Prog
 
 		if gc.Is64(r.Type) {
-			gins(i386.ACMPL, &hi2, ncon(0))
-			p1 = gc.Gbranch(i386.AJNE, nil, +1)
-			gins(i386.AMOVL, &lo2, &cx)
+			gins(x86.ACMPL, &hi2, ncon(0))
+			p1 = gc.Gbranch(x86.AJNE, nil, +1)
+			gins(x86.AMOVL, &lo2, &cx)
 		} else {
 			cx.Type = gc.Types[gc.TUINT32]
 			gmove(r, &cx)
 		}
 
 		// if shift count is >=64, zero or sign-extend value
-		gins(i386.ACMPL, &cx, ncon(64))
+		gins(x86.ACMPL, &cx, ncon(64))
 
 		p2 := gc.Gbranch(optoas(gc.OLT, gc.Types[gc.TUINT32]), nil, +1)
 		if p1 != nil {
 			gc.Patch(p1, gc.Pc)
 		}
 		if hi1.Type.Etype == gc.TINT32 {
-			gins(i386.ASARL, ncon(31), &dx)
-			gins(i386.AMOVL, &dx, &ax)
+			gins(x86.ASARL, ncon(31), &dx)
+			gins(x86.AMOVL, &dx, &ax)
 		} else {
-			gins(i386.AXORL, &dx, &dx)
-			gins(i386.AXORL, &ax, &ax)
+			gins(x86.AXORL, &dx, &dx)
+			gins(x86.AXORL, &ax, &ax)
 		}
 
 		gc.Patch(p2, gc.Pc)
 
 		// if shift count is >= 32, sign-extend hi.
-		gins(i386.ACMPL, &cx, ncon(32))
+		gins(x86.ACMPL, &cx, ncon(32))
 
 		p1 = gc.Gbranch(optoas(gc.OLT, gc.Types[gc.TUINT32]), nil, +1)
-		gins(i386.AMOVL, &dx, &ax)
+		gins(x86.AMOVL, &dx, &ax)
 		if hi1.Type.Etype == gc.TINT32 {
-			gins(i386.ASARL, &cx, &ax) // SARL only uses bottom 5 bits of count
-			gins(i386.ASARL, ncon(31), &dx)
+			gins(x86.ASARL, &cx, &ax) // SARL only uses bottom 5 bits of count
+			gins(x86.ASARL, ncon(31), &dx)
 		} else {
-			gins(i386.ASHRL, &cx, &ax)
-			gins(i386.AXORL, &dx, &dx)
+			gins(x86.ASHRL, &cx, &ax)
+			gins(x86.AXORL, &dx, &dx)
 		}
 
 		p2 = gc.Gbranch(obj.AJMP, nil, 0)
 		gc.Patch(p1, gc.Pc)
 
 		// general shift
-		p1 = gins(i386.ASHRL, &cx, &ax)
+		p1 = gins(x86.ASHRL, &cx, &ax)
 
-		p1.From.Index = i386.REG_DX // double-width shift
+		p1.From.Index = x86.REG_DX // double-width shift
 		p1.From.Scale = 0
 		gins(optoas(gc.ORSH, hi1.Type), &cx, &dx)
 		gc.Patch(p2, gc.Pc)
@@ -414,10 +414,10 @@
 					break
 
 				case 0xffffffff:
-					gins(i386.ANOTL, nil, &lo2)
+					gins(x86.ANOTL, nil, &lo2)
 
 				default:
-					gins(i386.AXORL, ncon(lv), &lo2)
+					gins(x86.AXORL, ncon(lv), &lo2)
 				}
 
 				switch hv {
@@ -425,32 +425,32 @@
 					break
 
 				case 0xffffffff:
-					gins(i386.ANOTL, nil, &hi2)
+					gins(x86.ANOTL, nil, &hi2)
 
 				default:
-					gins(i386.AXORL, ncon(hv), &hi2)
+					gins(x86.AXORL, ncon(hv), &hi2)
 				}
 
 			case gc.OAND:
 				switch lv {
 				case 0:
-					gins(i386.AMOVL, ncon(0), &lo2)
+					gins(x86.AMOVL, ncon(0), &lo2)
 
 				default:
 					gmove(&lo1, &lo2)
 					if lv != 0xffffffff {
-						gins(i386.AANDL, ncon(lv), &lo2)
+						gins(x86.AANDL, ncon(lv), &lo2)
 					}
 				}
 
 				switch hv {
 				case 0:
-					gins(i386.AMOVL, ncon(0), &hi2)
+					gins(x86.AMOVL, ncon(0), &hi2)
 
 				default:
 					gmove(&hi1, &hi2)
 					if hv != 0xffffffff {
-						gins(i386.AANDL, ncon(hv), &hi2)
+						gins(x86.AANDL, ncon(hv), &hi2)
 					}
 				}
 
@@ -460,11 +460,11 @@
 					gmove(&lo1, &lo2)
 
 				case 0xffffffff:
-					gins(i386.AMOVL, ncon(0xffffffff), &lo2)
+					gins(x86.AMOVL, ncon(0xffffffff), &lo2)
 
 				default:
 					gmove(&lo1, &lo2)
-					gins(i386.AORL, ncon(lv), &lo2)
+					gins(x86.AORL, ncon(lv), &lo2)
 				}
 
 				switch hv {
@@ -472,21 +472,21 @@
 					gmove(&hi1, &hi2)
 
 				case 0xffffffff:
-					gins(i386.AMOVL, ncon(0xffffffff), &hi2)
+					gins(x86.AMOVL, ncon(0xffffffff), &hi2)
 
 				default:
 					gmove(&hi1, &hi2)
-					gins(i386.AORL, ncon(hv), &hi2)
+					gins(x86.AORL, ncon(hv), &hi2)
 				}
 			}
 
 			splitclean()
 			splitclean()
-			goto out
+			return
 		}
 
-		gins(i386.AMOVL, &lo1, &ax)
-		gins(i386.AMOVL, &hi1, &dx)
+		gins(x86.AMOVL, &lo1, &ax)
+		gins(x86.AMOVL, &hi1, &dx)
 		gins(optoas(int(n.Op), lo1.Type), &lo2, &ax)
 		gins(optoas(int(n.Op), lo1.Type), &hi2, &dx)
 	}
@@ -497,11 +497,9 @@
 	splitclean()
 
 	split64(res, &lo1, &hi1)
-	gins(i386.AMOVL, &ax, &lo1)
-	gins(i386.AMOVL, &dx, &hi1)
+	gins(x86.AMOVL, &ax, &lo1)
+	gins(x86.AMOVL, &dx, &hi1)
 	splitclean()
-
-out:
 }
 
 /*
@@ -523,15 +521,15 @@
 	t := hi1.Type
 
 	if nl.Op == gc.OLITERAL || nr.Op == gc.OLITERAL {
-		gins(i386.ACMPL, &hi1, &hi2)
+		gins(x86.ACMPL, &hi1, &hi2)
 	} else {
-		regalloc(&rr, gc.Types[gc.TINT32], nil)
-		gins(i386.AMOVL, &hi1, &rr)
-		gins(i386.ACMPL, &rr, &hi2)
-		regfree(&rr)
+		gc.Regalloc(&rr, gc.Types[gc.TINT32], nil)
+		gins(x86.AMOVL, &hi1, &rr)
+		gins(x86.ACMPL, &rr, &hi2)
+		gc.Regfree(&rr)
 	}
 
-	br := (*obj.Prog)(nil)
+	var br *obj.Prog
 	switch op {
 	default:
 		gc.Fatal("cmp64 %v %v", gc.Oconv(int(op), 0), gc.Tconv(t, 0))
@@ -542,14 +540,14 @@
 	// jeq to
 	// L:
 	case gc.OEQ:
-		br = gc.Gbranch(i386.AJNE, nil, -likely)
+		br = gc.Gbranch(x86.AJNE, nil, -likely)
 
 		// cmp hi
 	// jne to
 	// cmp lo
 	// jne to
 	case gc.ONE:
-		gc.Patch(gc.Gbranch(i386.AJNE, nil, likely), to)
+		gc.Patch(gc.Gbranch(x86.AJNE, nil, likely), to)
 
 		// cmp hi
 	// jgt to
@@ -580,12 +578,12 @@
 	t = lo1.Type
 
 	if nl.Op == gc.OLITERAL || nr.Op == gc.OLITERAL {
-		gins(i386.ACMPL, &lo1, &lo2)
+		gins(x86.ACMPL, &lo1, &lo2)
 	} else {
-		regalloc(&rr, gc.Types[gc.TINT32], nil)
-		gins(i386.AMOVL, &lo1, &rr)
-		gins(i386.ACMPL, &rr, &lo2)
-		regfree(&rr)
+		gc.Regalloc(&rr, gc.Types[gc.TINT32], nil)
+		gins(x86.AMOVL, &lo1, &rr)
+		gins(x86.ACMPL, &rr, &lo2)
+		gc.Regfree(&rr)
 	}
 
 	// jump again
diff --git a/src/cmd/8g/galign.go b/src/cmd/8g/galign.go
index 45ef130..e92802d 100644
--- a/src/cmd/8g/galign.go
+++ b/src/cmd/8g/galign.go
@@ -5,16 +5,16 @@
 package main
 
 import (
+	"cmd/internal/gc"
 	"cmd/internal/obj"
-	"cmd/internal/obj/i386"
+	"cmd/internal/obj/x86"
 )
-import "cmd/internal/gc"
 
 var thechar int = '8'
 
 var thestring string = "386"
 
-var thelinkarch *obj.LinkArch = &i386.Link386
+var thelinkarch *obj.LinkArch = &x86.Link386
 
 func linkarchinit() {
 }
@@ -43,34 +43,54 @@
 	gc.Thearch.Thestring = thestring
 	gc.Thearch.Thelinkarch = thelinkarch
 	gc.Thearch.Typedefs = typedefs
-	gc.Thearch.REGSP = i386.REGSP
-	gc.Thearch.REGCTXT = i386.REGCTXT
+	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
+	switch v := obj.Getgo386(); v {
+	case "387":
+		gc.Thearch.FREGMIN = x86.REG_F0
+		gc.Thearch.FREGMAX = x86.REG_F7
+	case "sse2":
+		gc.Thearch.FREGMIN = x86.REG_X0
+		gc.Thearch.FREGMAX = x86.REG_X7
+	default:
+		gc.Fatal("unsupported setting GO386=%s", v)
+	}
 	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.Igen = igen
+	gc.Thearch.Ginscon = ginscon
+	gc.Thearch.Ginsnop = ginsnop
+	gc.Thearch.Gmove = gmove
+	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/gg.go b/src/cmd/8g/gg.go
index 4aeff92..bfbd12e 100644
--- a/src/cmd/8g/gg.go
+++ b/src/cmd/8g/gg.go
@@ -4,7 +4,7 @@
 
 package main
 
-import "cmd/internal/obj/i386"
+import "cmd/internal/obj/x86"
 import "cmd/internal/gc"
 
 // TODO(rsc):
@@ -21,7 +21,7 @@
 	Fpop2 = 1 << 2
 )
 
-var reg [i386.MAXREG]uint8
+var reg [x86.MAXREG]uint8
 
 var panicdiv *gc.Node
 
diff --git a/src/cmd/8g/ggen.go b/src/cmd/8g/ggen.go
index ca2a79f..949156e 100644
--- a/src/cmd/8g/ggen.go
+++ b/src/cmd/8g/ggen.go
@@ -5,10 +5,10 @@
 package main
 
 import (
+	"cmd/internal/gc"
 	"cmd/internal/obj"
-	"cmd/internal/obj/i386"
+	"cmd/internal/obj/x86"
 )
-import "cmd/internal/gc"
 
 func defframe(ptxt *obj.Prog) {
 	var n *gc.Node
@@ -16,7 +16,7 @@
 	// fill in argument size, stack size
 	ptxt.To.Type = obj.TYPE_TEXTSIZE
 
-	ptxt.To.U.Argsize = int32(gc.Rnd(gc.Curfn.Type.Argwid, int64(gc.Widthptr)))
+	ptxt.To.Val = int32(gc.Rnd(gc.Curfn.Type.Argwid, int64(gc.Widthptr)))
 	frame := uint32(gc.Rnd(gc.Stksize+gc.Maxarg, int64(gc.Widthreg)))
 	ptxt.To.Offset = int64(frame)
 
@@ -28,9 +28,9 @@
 	hi := int64(0)
 	lo := hi
 	ax := uint32(0)
-	for l := gc.Curfn.Dcl; l != nil; l = l.Next {
+	for l := gc.Curfn.Func.Dcl; l != nil; l = l.Next {
 		n = l.N
-		if n.Needzero == 0 {
+		if !n.Needzero {
 			continue
 		}
 		if n.Class != gc.PAUTO {
@@ -65,23 +65,23 @@
 		return p
 	}
 	if *ax == 0 {
-		p = appendpp(p, i386.AMOVL, obj.TYPE_CONST, 0, 0, obj.TYPE_REG, i386.REG_AX, 0)
+		p = appendpp(p, x86.AMOVL, obj.TYPE_CONST, 0, 0, obj.TYPE_REG, x86.REG_AX, 0)
 		*ax = 1
 	}
 
 	if cnt <= int64(4*gc.Widthreg) {
 		for i := int64(0); i < cnt; i += int64(gc.Widthreg) {
-			p = appendpp(p, i386.AMOVL, obj.TYPE_REG, i386.REG_AX, 0, obj.TYPE_MEM, i386.REG_SP, frame+lo+i)
+			p = appendpp(p, x86.AMOVL, obj.TYPE_REG, x86.REG_AX, 0, obj.TYPE_MEM, x86.REG_SP, frame+lo+i)
 		}
 	} else if !gc.Nacl && cnt <= int64(128*gc.Widthreg) {
-		p = appendpp(p, i386.ALEAL, obj.TYPE_MEM, i386.REG_SP, frame+lo, obj.TYPE_REG, i386.REG_DI, 0)
+		p = appendpp(p, x86.ALEAL, obj.TYPE_MEM, x86.REG_SP, frame+lo, obj.TYPE_REG, x86.REG_DI, 0)
 		p = appendpp(p, obj.ADUFFZERO, obj.TYPE_NONE, 0, 0, obj.TYPE_ADDR, 0, 1*(128-cnt/int64(gc.Widthreg)))
 		p.To.Sym = gc.Linksym(gc.Pkglookup("duffzero", gc.Runtimepkg))
 	} else {
-		p = appendpp(p, i386.AMOVL, obj.TYPE_CONST, 0, cnt/int64(gc.Widthreg), obj.TYPE_REG, i386.REG_CX, 0)
-		p = appendpp(p, i386.ALEAL, obj.TYPE_MEM, i386.REG_SP, frame+lo, obj.TYPE_REG, i386.REG_DI, 0)
-		p = appendpp(p, i386.AREP, obj.TYPE_NONE, 0, 0, obj.TYPE_NONE, 0, 0)
-		p = appendpp(p, i386.ASTOSL, obj.TYPE_NONE, 0, 0, obj.TYPE_NONE, 0, 0)
+		p = appendpp(p, x86.AMOVL, obj.TYPE_CONST, 0, cnt/int64(gc.Widthreg), obj.TYPE_REG, x86.REG_CX, 0)
+		p = appendpp(p, x86.ALEAL, obj.TYPE_MEM, x86.REG_SP, frame+lo, obj.TYPE_REG, x86.REG_DI, 0)
+		p = appendpp(p, x86.AREP, obj.TYPE_NONE, 0, 0, obj.TYPE_NONE, 0, 0)
+		p = appendpp(p, x86.ASTOSL, obj.TYPE_NONE, 0, 0, obj.TYPE_NONE, 0, 0)
 	}
 
 	return p
@@ -112,7 +112,7 @@
 	w := uint32(nl.Type.Width)
 
 	// Avoid taking the address for simple enough types.
-	if componentgen(nil, nl) {
+	if gc.Componentgen(nil, nl) {
 		return
 	}
 
@@ -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)
@@ -140,7 +140,7 @@
 				break
 			}
 			n1.Type = z.Type
-			gins(i386.AMOVL, &z, &n1)
+			gins(x86.AMOVL, &z, &n1)
 			n1.Xoffset += 4
 		}
 
@@ -152,23 +152,23 @@
 				break
 			}
 			n1.Type = z.Type
-			gins(i386.AMOVB, &z, &n1)
+			gins(x86.AMOVB, &z, &n1)
 			n1.Xoffset++
 		}
 
-		regfree(&n1)
+		gc.Regfree(&n1)
 		return
 	}
 
 	var n1 gc.Node
-	gc.Nodreg(&n1, gc.Types[gc.Tptr], i386.REG_DI)
-	agen(nl, &n1)
-	gconreg(i386.AMOVL, 0, i386.REG_AX)
+	gc.Nodreg(&n1, gc.Types[gc.Tptr], x86.REG_DI)
+	gc.Agen(nl, &n1)
+	gconreg(x86.AMOVL, 0, x86.REG_AX)
 
 	if q > 128 || (q >= 4 && gc.Nacl) {
-		gconreg(i386.AMOVL, int64(q), i386.REG_CX)
-		gins(i386.AREP, nil, nil)   // repeat
-		gins(i386.ASTOSL, nil, nil) // STOL AL,*(DI)+
+		gconreg(x86.AMOVL, int64(q), x86.REG_CX)
+		gins(x86.AREP, nil, nil)   // repeat
+		gins(x86.ASTOSL, nil, nil) // STOL AL,*(DI)+
 	} else if q >= 4 {
 		p := gins(obj.ADUFFZERO, nil, nil)
 		p.To.Type = obj.TYPE_ADDR
@@ -178,324 +178,18 @@
 		p.To.Offset = 1 * (128 - int64(q))
 	} else {
 		for q > 0 {
-			gins(i386.ASTOSL, nil, nil) // STOL AL,*(DI)+
+			gins(x86.ASTOSL, nil, nil) // STOL AL,*(DI)+
 			q--
 		}
 	}
 
 	for c > 0 {
-		gins(i386.ASTOSB, nil, nil) // STOB AL,*(DI)+
+		gins(x86.ASTOSB, nil, nil) // STOB AL,*(DI)+
 		c--
 	}
 }
 
 /*
- * 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], i386.REG_AX)
-
-				gins(i386.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], i386.REG_DX)
-		var r1 gc.Node
-		gc.Nodreg(&r1, gc.Types[gc.Tptr], i386.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)
-		stk := gc.Node{}
-
-		stk.Op = gc.OINDREG
-		stk.Val.U.Reg = i386.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(i386.AMOVL, &con, &stk)
-
-		// FuncVal* at 4(SP)
-		stk.Xoffset = int64(gc.Widthptr)
-
-		gins(i386.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], i386.REG_AX)
-			gins(i386.ATESTL, &reg, &reg)
-			p := gc.Gbranch(i386.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], i386.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(i386.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")
-	}
-
-	nod := gc.Node{}
-	nod.Op = gc.OINDREG
-	nod.Val.U.Reg = i386.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] != 0 {
-		t = t.Type
-	}
-
-	var flist gc.Iter
-	fp := gc.Structfirst(&flist, gc.Getoutarg(t))
-	if fp == nil {
-		gc.Fatal("cgen_aret: nil")
-	}
-
-	nod1 := gc.Node{}
-	nod1.Op = gc.OINDREG
-	nod1.Val.U.Reg = i386.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(i386.ALEAL, &nod1, &nod2)
-		gins(i386.AMOVL, &nod2, res)
-		regfree(&nod2)
-	} else {
-		gins(i386.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
@@ -518,7 +212,7 @@
 
 	t0 := t
 	check := 0
-	if gc.Issigned[t.Etype] != 0 {
+	if gc.Issigned[t.Etype] {
 		check = 1
 		if gc.Isconst(nl, gc.CTINT) && gc.Mpgetfix(nl.Val.U.Xval) != -1<<uint64(t.Width*8-1) {
 			check = 0
@@ -528,7 +222,7 @@
 	}
 
 	if t.Width < 4 {
-		if gc.Issigned[t.Etype] != 0 {
+		if gc.Issigned[t.Etype] {
 			t = gc.Types[gc.TINT32]
 		} else {
 			t = gc.Types[gc.TUINT32]
@@ -545,27 +239,27 @@
 		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)
-	p2 := (*obj.Prog)(nil)
+	var p2 *obj.Prog
 	var n4 gc.Node
 	if gc.Nacl {
 		// Native Client does not relay the divide-by-zero trap
@@ -578,7 +272,7 @@
 		if panicdiv == nil {
 			panicdiv = gc.Sysfunc("panicdivide")
 		}
-		ginscall(panicdiv, -1)
+		gc.Ginscall(panicdiv, -1)
 		gc.Patch(p1, gc.Pc)
 	}
 
@@ -602,7 +296,7 @@
 		gc.Patch(p1, gc.Pc)
 	}
 
-	if gc.Issigned[t.Etype] == 0 {
+	if !gc.Issigned[t.Etype] {
 		var nz gc.Node
 		gc.Nodconst(&nz, t, 0)
 		gmove(&nz, dx)
@@ -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]
@@ -658,17 +352,17 @@
 	}
 
 	var t *gc.Type
-	if gc.Issigned[nl.Type.Etype] != 0 {
+	if gc.Issigned[nl.Type.Etype] {
 		t = gc.Types[gc.TINT32]
 	} else {
 		t = gc.Types[gc.TUINT32]
 	}
 	var ax gc.Node
 	var oldax gc.Node
-	savex(i386.REG_AX, &ax, &oldax, res, t)
+	savex(x86.REG_AX, &ax, &oldax, res, t)
 	var olddx gc.Node
 	var dx gc.Node
-	savex(i386.REG_DX, &dx, &olddx, res, t)
+	savex(x86.REG_DX, &dx, &olddx, res, t)
 	dodiv(op, nl, nr, res, &ax, &dx)
 	restx(&dx, &olddx)
 	restx(&ax, &oldax)
@@ -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,14 +399,14 @@
 			gins(a, nr, &n1)
 		}
 		gmove(&n1, res)
-		regfree(&n1)
+		gc.Regfree(&n1)
 		return
 	}
 
-	oldcx := gc.Node{}
+	var oldcx gc.Node
 	var cx gc.Node
-	gc.Nodreg(&cx, gc.Types[gc.TUINT32], i386.REG_CX)
-	if reg[i386.REG_CX] > 1 && !gc.Samereg(&cx, res) {
+	gc.Nodreg(&cx, gc.Types[gc.TUINT32], x86.REG_CX)
+	if reg[x86.REG_CX] > 1 && !gc.Samereg(&cx, res) {
 		gc.Tempname(&oldcx, gc.Types[gc.TUINT32])
 		gmove(&cx, &oldcx)
 	}
@@ -723,31 +417,31 @@
 		gc.Tempname(&nt, nr.Type)
 		n1 = nt
 	} else {
-		gc.Nodreg(&n1, gc.Types[gc.TUINT32], i386.REG_CX)
-		regalloc(&n1, nr.Type, &n1) // to hold the shift type in CX
+		gc.Nodreg(&n1, gc.Types[gc.TUINT32], x86.REG_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
 	if bounded {
 		if nr.Type.Width > 4 {
 			// delayed reg alloc
-			gc.Nodreg(&n1, gc.Types[gc.TUINT32], i386.REG_CX)
+			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)
@@ -758,9 +452,9 @@
 		var p1 *obj.Prog
 		if nr.Type.Width > 4 {
 			// delayed reg alloc
-			gc.Nodreg(&n1, gc.Types[gc.TUINT32], i386.REG_CX)
+			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)
@@ -776,7 +470,7 @@
 			p1 = gc.Gbranch(optoas(gc.OLT, gc.Types[gc.TUINT32]), nil, +1)
 		}
 
-		if op == gc.ORSH && gc.Issigned[nl.Type.Etype] != 0 {
+		if op == gc.ORSH && gc.Issigned[nl.Type.Etype] {
 			gins(a, ncon(uint32(w)-1), &n2)
 		} else {
 			gmove(ncon(0), &n2)
@@ -793,8 +487,8 @@
 
 	gmove(&n2, res)
 
-	regfree(&n1)
-	regfree(&n2)
+	gc.Regfree(&n1)
+	gc.Regfree(&n2)
 }
 
 /*
@@ -803,11 +497,15 @@
  * 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]
 
-	if gc.Issigned[nl.Type.Etype] != 0 {
+	if gc.Issigned[nl.Type.Etype] {
 		t = gc.Types[gc.TINT32]
 	}
 
@@ -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,29 +550,29 @@
 	// 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, i386.REG_AX)
+	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.
-		gc.Nodreg(&ax, t, i386.REG_AH)
+		gc.Nodreg(&ax, t, x86.REG_AH)
 
-		gc.Nodreg(&dx, t, i386.REG_DX)
+		gc.Nodreg(&dx, t, x86.REG_DX)
 		gmove(&ax, &dx)
 	}
 
-	gc.Nodreg(&dx, t, i386.REG_DX)
+	gc.Nodreg(&dx, t, x86.REG_DX)
 	gmove(&dx, res)
 }
 
@@ -892,32 +592,32 @@
 		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
 	}
 
-	if gc.Use_sse != 0 {
+	if gc.Use_sse {
 		cgen_floatsse(n, res)
 	} else {
 		cgen_float387(n, res)
@@ -931,42 +631,40 @@
 
 	nl := n.Left
 	nr := n.Right
-	gc.Nodreg(&f0, nl.Type, i386.REG_F0)
-	gc.Nodreg(&f1, n.Type, i386.REG_F0+1)
+	gc.Nodreg(&f0, nl.Type, x86.REG_F0)
+	gc.Nodreg(&f1, n.Type, x86.REG_F0+1)
 	if nr != nil {
-		goto flt2
+		// binary
+		if nl.Ullman >= nr.Ullman {
+			gc.Cgen(nl, &f0)
+			if nr.Addable != 0 {
+				gins(foptoas(int(n.Op), n.Type, 0), nr, &f0)
+			} else {
+				gc.Cgen(nr, &f0)
+				gins(foptoas(int(n.Op), n.Type, Fpop), &f0, &f1)
+			}
+		} else {
+			gc.Cgen(nr, &f0)
+			if nl.Addable != 0 {
+				gins(foptoas(int(n.Op), n.Type, Frev), nl, &f0)
+			} else {
+				gc.Cgen(nl, &f0)
+				gins(foptoas(int(n.Op), n.Type, Frev|Fpop), &f0, &f1)
+			}
+		}
+
+		gmove(&f0, res)
+		return
 	}
 
 	// 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)
 	}
 	gmove(&f0, res)
 	return
-
-flt2: // binary
-	if nl.Ullman >= nr.Ullman {
-		cgen(nl, &f0)
-		if nr.Addable != 0 {
-			gins(foptoas(int(n.Op), n.Type, 0), nr, &f0)
-		} else {
-			cgen(nr, &f0)
-			gins(foptoas(int(n.Op), n.Type, Fpop), &f0, &f1)
-		}
-	} else {
-		cgen(nr, &f0)
-		if nl.Addable != 0 {
-			gins(foptoas(int(n.Op), n.Type, Frev), nl, &f0)
-		} else {
-			cgen(nl, &f0)
-			gins(foptoas(int(n.Op), n.Type, Frev|Fpop), &f0, &f1)
-		}
-	}
-
-	gmove(&f0, res)
-	return
 }
 
 func cgen_floatsse(n *gc.Node, res *gc.Node) {
@@ -1014,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
@@ -1063,8 +761,48 @@
 	var et int
 	var n2 gc.Node
 	var ax gc.Node
-	if gc.Use_sse != 0 {
-		goto sse
+	if gc.Use_sse {
+		if nl.Addable == 0 {
+			var n1 gc.Node
+			gc.Tempname(&n1, nl.Type)
+			gc.Cgen(nl, &n1)
+			nl = &n1
+		}
+
+		if nr.Addable == 0 {
+			var tmp gc.Node
+			gc.Tempname(&tmp, nr.Type)
+			gc.Cgen(nr, &tmp)
+			nr = &tmp
+		}
+
+		var n2 gc.Node
+		gc.Regalloc(&n2, nr.Type, nil)
+		gmove(nr, &n2)
+		nr = &n2
+
+		if nl.Op != gc.OREGISTER {
+			var n3 gc.Node
+			gc.Regalloc(&n3, nl.Type, nil)
+			gmove(nl, &n3)
+			nl = &n3
+		}
+
+		if a == gc.OGE || a == gc.OGT {
+			// only < and <= work right with NaN; reverse if needed
+			r := nr
+
+			nr = nl
+			nl = r
+			a = gc.Brrev(a)
+		}
+
+		gins(foptoas(gc.OCMP, nr.Type, 0), nl, nr)
+		if nl.Op == gc.OREGISTER {
+			gc.Regfree(nl)
+		}
+		gc.Regfree(nr)
+		goto ret
 	} else {
 		goto x87
 	}
@@ -1080,22 +818,22 @@
 		a = gc.Brrev(a)
 	}
 
-	gc.Nodreg(&tmp, nr.Type, i386.REG_F0)
-	gc.Nodreg(&n2, nr.Type, i386.REG_F0+1)
-	gc.Nodreg(&ax, gc.Types[gc.TUINT16], i386.REG_AX)
+	gc.Nodreg(&tmp, nr.Type, x86.REG_F0)
+	gc.Nodreg(&n2, nr.Type, x86.REG_F0+1)
+	gc.Nodreg(&ax, gc.Types[gc.TUINT16], x86.REG_AX)
 	et = gc.Simsimtype(nr.Type)
 	if et == gc.TFLOAT64 {
 		if nl.Ullman > nr.Ullman {
-			cgen(nl, &tmp)
-			cgen(nr, &tmp)
-			gins(i386.AFXCHD, &tmp, &n2)
+			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(i386.AFUCOMIP, &tmp, &n2)
-		gins(i386.AFMOVDP, &tmp, &tmp) // annoying pop but still better than STSW+SAHF
+		gins(x86.AFUCOMIP, &tmp, &n2)
+		gins(x86.AFMOVDP, &tmp, &tmp) // annoying pop but still better than STSW+SAHF
 	} else {
 		// TODO(rsc): The moves back and forth to memory
 		// here are for truncating the value to 32 bits.
@@ -1108,71 +846,30 @@
 
 		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(i386.AFCOMFP, &t1, &tmp)
-		gins(i386.AFSTSW, nil, &ax)
-		gins(i386.ASAHF, nil, nil)
+		gins(x86.AFCOMFP, &t1, &tmp)
+		gins(x86.AFSTSW, nil, &ax)
+		gins(x86.ASAHF, nil, nil)
 	}
 
 	goto ret
 
-sse:
-	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
-	}
-
-	regalloc(&n2, nr.Type, nil)
-	gmove(nr, &n2)
-	nr = &n2
-
-	if nl.Op != gc.OREGISTER {
-		var n3 gc.Node
-		regalloc(&n3, nl.Type, nil)
-		gmove(nl, &n3)
-		nl = &n3
-	}
-
-	if a == gc.OGE || a == gc.OGT {
-		// only < and <= work right with NaN; reverse if needed
-		r := nr
-
-		nr = nl
-		nl = r
-		a = gc.Brrev(a)
-	}
-
-	gins(foptoas(gc.OCMP, nr.Type, 0), nl, nr)
-	if nl.Op == gc.OREGISTER {
-		regfree(nl)
-	}
-	regfree(nr)
-
 ret:
 	if a == gc.OEQ {
 		// neither NE nor P
-		p1 := gc.Gbranch(i386.AJNE, nil, -likely)
+		p1 := gc.Gbranch(x86.AJNE, nil, -likely)
 
-		p2 := gc.Gbranch(i386.AJPS, 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 if a == gc.ONE {
 		// either NE or P
-		gc.Patch(gc.Gbranch(i386.AJNE, nil, likely), to)
+		gc.Patch(gc.Gbranch(x86.AJNE, nil, likely), to)
 
-		gc.Patch(gc.Gbranch(i386.AJPS, nil, likely), to)
+		gc.Patch(gc.Gbranch(x86.AJPS, nil, likely), to)
 	} else {
 		gc.Patch(gc.Gbranch(optoas(a, nr.Type), nil, likely), to)
 	}
@@ -1208,22 +905,22 @@
 		p2.Lineno = p.Lineno
 		p1.Pc = 9999
 		p2.Pc = 9999
-		p.As = i386.ACMPL
+		p.As = x86.ACMPL
 		p.To.Type = obj.TYPE_CONST
 		p.To.Offset = 0
-		p1.As = i386.AJNE
+		p1.As = x86.AJNE
 		p1.From.Type = obj.TYPE_CONST
 		p1.From.Offset = 1 // likely
 		p1.To.Type = obj.TYPE_BRANCH
-		p1.To.U.Branch = p2.Link
+		p1.To.Val = p2.Link
 
 		// crash by write to memory address 0.
 		// if possible, since we know arg is 0, use 0(arg),
 		// which will be shorter to encode than plain 0.
-		p2.As = i386.AMOVL
+		p2.As = x86.AMOVL
 
 		p2.From.Type = obj.TYPE_REG
-		p2.From.Reg = i386.REG_AX
+		p2.From.Reg = x86.REG_AX
 		if regtyp(&p.From) {
 			p2.To.Type = obj.TYPE_MEM
 			p2.To.Reg = p.From.Reg
@@ -1233,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 841f4dc..7ca4dac 100644
--- a/src/cmd/8g/gsubr.go
+++ b/src/cmd/8g/gsubr.go
@@ -31,11 +31,11 @@
 package main
 
 import (
+	"cmd/internal/gc"
 	"cmd/internal/obj"
-	"cmd/internal/obj/i386"
+	"cmd/internal/obj/x86"
 	"fmt"
 )
-import "cmd/internal/gc"
 
 // TODO(rsc): Can make this bigger if we move
 // the text segment up higher in 8l for all GOOS.
@@ -56,7 +56,7 @@
 		gc.Fatal("optoas: no entry %v-%v", gc.Oconv(int(op), 0), gc.Tconv(t, 0))
 
 	case gc.OADDR<<16 | gc.TPTR32:
-		a = i386.ALEAL
+		a = x86.ALEAL
 
 	case gc.OEQ<<16 | gc.TBOOL,
 		gc.OEQ<<16 | gc.TINT8,
@@ -71,7 +71,7 @@
 		gc.OEQ<<16 | gc.TPTR64,
 		gc.OEQ<<16 | gc.TFLOAT32,
 		gc.OEQ<<16 | gc.TFLOAT64:
-		a = i386.AJEQ
+		a = x86.AJEQ
 
 	case gc.ONE<<16 | gc.TBOOL,
 		gc.ONE<<16 | gc.TINT8,
@@ -86,37 +86,37 @@
 		gc.ONE<<16 | gc.TPTR64,
 		gc.ONE<<16 | gc.TFLOAT32,
 		gc.ONE<<16 | gc.TFLOAT64:
-		a = i386.AJNE
+		a = x86.AJNE
 
 	case gc.OLT<<16 | gc.TINT8,
 		gc.OLT<<16 | gc.TINT16,
 		gc.OLT<<16 | gc.TINT32,
 		gc.OLT<<16 | gc.TINT64:
-		a = i386.AJLT
+		a = x86.AJLT
 
 	case gc.OLT<<16 | gc.TUINT8,
 		gc.OLT<<16 | gc.TUINT16,
 		gc.OLT<<16 | gc.TUINT32,
 		gc.OLT<<16 | gc.TUINT64:
-		a = i386.AJCS
+		a = x86.AJCS
 
 	case gc.OLE<<16 | gc.TINT8,
 		gc.OLE<<16 | gc.TINT16,
 		gc.OLE<<16 | gc.TINT32,
 		gc.OLE<<16 | gc.TINT64:
-		a = i386.AJLE
+		a = x86.AJLE
 
 	case gc.OLE<<16 | gc.TUINT8,
 		gc.OLE<<16 | gc.TUINT16,
 		gc.OLE<<16 | gc.TUINT32,
 		gc.OLE<<16 | gc.TUINT64:
-		a = i386.AJLS
+		a = x86.AJLS
 
 	case gc.OGT<<16 | gc.TINT8,
 		gc.OGT<<16 | gc.TINT16,
 		gc.OGT<<16 | gc.TINT32,
 		gc.OGT<<16 | gc.TINT64:
-		a = i386.AJGT
+		a = x86.AJGT
 
 	case gc.OGT<<16 | gc.TUINT8,
 		gc.OGT<<16 | gc.TUINT16,
@@ -124,13 +124,13 @@
 		gc.OGT<<16 | gc.TUINT64,
 		gc.OLT<<16 | gc.TFLOAT32,
 		gc.OLT<<16 | gc.TFLOAT64:
-		a = i386.AJHI
+		a = x86.AJHI
 
 	case gc.OGE<<16 | gc.TINT8,
 		gc.OGE<<16 | gc.TINT16,
 		gc.OGE<<16 | gc.TINT32,
 		gc.OGE<<16 | gc.TINT64:
-		a = i386.AJGE
+		a = x86.AJGE
 
 	case gc.OGE<<16 | gc.TUINT8,
 		gc.OGE<<16 | gc.TUINT16,
@@ -138,261 +138,261 @@
 		gc.OGE<<16 | gc.TUINT64,
 		gc.OLE<<16 | gc.TFLOAT32,
 		gc.OLE<<16 | gc.TFLOAT64:
-		a = i386.AJCC
+		a = x86.AJCC
 
 	case gc.OCMP<<16 | gc.TBOOL,
 		gc.OCMP<<16 | gc.TINT8,
 		gc.OCMP<<16 | gc.TUINT8:
-		a = i386.ACMPB
+		a = x86.ACMPB
 
 	case gc.OCMP<<16 | gc.TINT16,
 		gc.OCMP<<16 | gc.TUINT16:
-		a = i386.ACMPW
+		a = x86.ACMPW
 
 	case gc.OCMP<<16 | gc.TINT32,
 		gc.OCMP<<16 | gc.TUINT32,
 		gc.OCMP<<16 | gc.TPTR32:
-		a = i386.ACMPL
+		a = x86.ACMPL
 
 	case gc.OAS<<16 | gc.TBOOL,
 		gc.OAS<<16 | gc.TINT8,
 		gc.OAS<<16 | gc.TUINT8:
-		a = i386.AMOVB
+		a = x86.AMOVB
 
 	case gc.OAS<<16 | gc.TINT16,
 		gc.OAS<<16 | gc.TUINT16:
-		a = i386.AMOVW
+		a = x86.AMOVW
 
 	case gc.OAS<<16 | gc.TINT32,
 		gc.OAS<<16 | gc.TUINT32,
 		gc.OAS<<16 | gc.TPTR32:
-		a = i386.AMOVL
+		a = x86.AMOVL
 
 	case gc.OAS<<16 | gc.TFLOAT32:
-		a = i386.AMOVSS
+		a = x86.AMOVSS
 
 	case gc.OAS<<16 | gc.TFLOAT64:
-		a = i386.AMOVSD
+		a = x86.AMOVSD
 
 	case gc.OADD<<16 | gc.TINT8,
 		gc.OADD<<16 | gc.TUINT8:
-		a = i386.AADDB
+		a = x86.AADDB
 
 	case gc.OADD<<16 | gc.TINT16,
 		gc.OADD<<16 | gc.TUINT16:
-		a = i386.AADDW
+		a = x86.AADDW
 
 	case gc.OADD<<16 | gc.TINT32,
 		gc.OADD<<16 | gc.TUINT32,
 		gc.OADD<<16 | gc.TPTR32:
-		a = i386.AADDL
+		a = x86.AADDL
 
 	case gc.OSUB<<16 | gc.TINT8,
 		gc.OSUB<<16 | gc.TUINT8:
-		a = i386.ASUBB
+		a = x86.ASUBB
 
 	case gc.OSUB<<16 | gc.TINT16,
 		gc.OSUB<<16 | gc.TUINT16:
-		a = i386.ASUBW
+		a = x86.ASUBW
 
 	case gc.OSUB<<16 | gc.TINT32,
 		gc.OSUB<<16 | gc.TUINT32,
 		gc.OSUB<<16 | gc.TPTR32:
-		a = i386.ASUBL
+		a = x86.ASUBL
 
 	case gc.OINC<<16 | gc.TINT8,
 		gc.OINC<<16 | gc.TUINT8:
-		a = i386.AINCB
+		a = x86.AINCB
 
 	case gc.OINC<<16 | gc.TINT16,
 		gc.OINC<<16 | gc.TUINT16:
-		a = i386.AINCW
+		a = x86.AINCW
 
 	case gc.OINC<<16 | gc.TINT32,
 		gc.OINC<<16 | gc.TUINT32,
 		gc.OINC<<16 | gc.TPTR32:
-		a = i386.AINCL
+		a = x86.AINCL
 
 	case gc.ODEC<<16 | gc.TINT8,
 		gc.ODEC<<16 | gc.TUINT8:
-		a = i386.ADECB
+		a = x86.ADECB
 
 	case gc.ODEC<<16 | gc.TINT16,
 		gc.ODEC<<16 | gc.TUINT16:
-		a = i386.ADECW
+		a = x86.ADECW
 
 	case gc.ODEC<<16 | gc.TINT32,
 		gc.ODEC<<16 | gc.TUINT32,
 		gc.ODEC<<16 | gc.TPTR32:
-		a = i386.ADECL
+		a = x86.ADECL
 
 	case gc.OCOM<<16 | gc.TINT8,
 		gc.OCOM<<16 | gc.TUINT8:
-		a = i386.ANOTB
+		a = x86.ANOTB
 
 	case gc.OCOM<<16 | gc.TINT16,
 		gc.OCOM<<16 | gc.TUINT16:
-		a = i386.ANOTW
+		a = x86.ANOTW
 
 	case gc.OCOM<<16 | gc.TINT32,
 		gc.OCOM<<16 | gc.TUINT32,
 		gc.OCOM<<16 | gc.TPTR32:
-		a = i386.ANOTL
+		a = x86.ANOTL
 
 	case gc.OMINUS<<16 | gc.TINT8,
 		gc.OMINUS<<16 | gc.TUINT8:
-		a = i386.ANEGB
+		a = x86.ANEGB
 
 	case gc.OMINUS<<16 | gc.TINT16,
 		gc.OMINUS<<16 | gc.TUINT16:
-		a = i386.ANEGW
+		a = x86.ANEGW
 
 	case gc.OMINUS<<16 | gc.TINT32,
 		gc.OMINUS<<16 | gc.TUINT32,
 		gc.OMINUS<<16 | gc.TPTR32:
-		a = i386.ANEGL
+		a = x86.ANEGL
 
 	case gc.OAND<<16 | gc.TINT8,
 		gc.OAND<<16 | gc.TUINT8:
-		a = i386.AANDB
+		a = x86.AANDB
 
 	case gc.OAND<<16 | gc.TINT16,
 		gc.OAND<<16 | gc.TUINT16:
-		a = i386.AANDW
+		a = x86.AANDW
 
 	case gc.OAND<<16 | gc.TINT32,
 		gc.OAND<<16 | gc.TUINT32,
 		gc.OAND<<16 | gc.TPTR32:
-		a = i386.AANDL
+		a = x86.AANDL
 
 	case gc.OOR<<16 | gc.TINT8,
 		gc.OOR<<16 | gc.TUINT8:
-		a = i386.AORB
+		a = x86.AORB
 
 	case gc.OOR<<16 | gc.TINT16,
 		gc.OOR<<16 | gc.TUINT16:
-		a = i386.AORW
+		a = x86.AORW
 
 	case gc.OOR<<16 | gc.TINT32,
 		gc.OOR<<16 | gc.TUINT32,
 		gc.OOR<<16 | gc.TPTR32:
-		a = i386.AORL
+		a = x86.AORL
 
 	case gc.OXOR<<16 | gc.TINT8,
 		gc.OXOR<<16 | gc.TUINT8:
-		a = i386.AXORB
+		a = x86.AXORB
 
 	case gc.OXOR<<16 | gc.TINT16,
 		gc.OXOR<<16 | gc.TUINT16:
-		a = i386.AXORW
+		a = x86.AXORW
 
 	case gc.OXOR<<16 | gc.TINT32,
 		gc.OXOR<<16 | gc.TUINT32,
 		gc.OXOR<<16 | gc.TPTR32:
-		a = i386.AXORL
+		a = x86.AXORL
 
 	case gc.OLROT<<16 | gc.TINT8,
 		gc.OLROT<<16 | gc.TUINT8:
-		a = i386.AROLB
+		a = x86.AROLB
 
 	case gc.OLROT<<16 | gc.TINT16,
 		gc.OLROT<<16 | gc.TUINT16:
-		a = i386.AROLW
+		a = x86.AROLW
 
 	case gc.OLROT<<16 | gc.TINT32,
 		gc.OLROT<<16 | gc.TUINT32,
 		gc.OLROT<<16 | gc.TPTR32:
-		a = i386.AROLL
+		a = x86.AROLL
 
 	case gc.OLSH<<16 | gc.TINT8,
 		gc.OLSH<<16 | gc.TUINT8:
-		a = i386.ASHLB
+		a = x86.ASHLB
 
 	case gc.OLSH<<16 | gc.TINT16,
 		gc.OLSH<<16 | gc.TUINT16:
-		a = i386.ASHLW
+		a = x86.ASHLW
 
 	case gc.OLSH<<16 | gc.TINT32,
 		gc.OLSH<<16 | gc.TUINT32,
 		gc.OLSH<<16 | gc.TPTR32:
-		a = i386.ASHLL
+		a = x86.ASHLL
 
 	case gc.ORSH<<16 | gc.TUINT8:
-		a = i386.ASHRB
+		a = x86.ASHRB
 
 	case gc.ORSH<<16 | gc.TUINT16:
-		a = i386.ASHRW
+		a = x86.ASHRW
 
 	case gc.ORSH<<16 | gc.TUINT32,
 		gc.ORSH<<16 | gc.TPTR32:
-		a = i386.ASHRL
+		a = x86.ASHRL
 
 	case gc.ORSH<<16 | gc.TINT8:
-		a = i386.ASARB
+		a = x86.ASARB
 
 	case gc.ORSH<<16 | gc.TINT16:
-		a = i386.ASARW
+		a = x86.ASARW
 
 	case gc.ORSH<<16 | gc.TINT32:
-		a = i386.ASARL
+		a = x86.ASARL
 
 	case gc.OHMUL<<16 | gc.TINT8,
 		gc.OMUL<<16 | gc.TINT8,
 		gc.OMUL<<16 | gc.TUINT8:
-		a = i386.AIMULB
+		a = x86.AIMULB
 
 	case gc.OHMUL<<16 | gc.TINT16,
 		gc.OMUL<<16 | gc.TINT16,
 		gc.OMUL<<16 | gc.TUINT16:
-		a = i386.AIMULW
+		a = x86.AIMULW
 
 	case gc.OHMUL<<16 | gc.TINT32,
 		gc.OMUL<<16 | gc.TINT32,
 		gc.OMUL<<16 | gc.TUINT32,
 		gc.OMUL<<16 | gc.TPTR32:
-		a = i386.AIMULL
+		a = x86.AIMULL
 
 	case gc.OHMUL<<16 | gc.TUINT8:
-		a = i386.AMULB
+		a = x86.AMULB
 
 	case gc.OHMUL<<16 | gc.TUINT16:
-		a = i386.AMULW
+		a = x86.AMULW
 
 	case gc.OHMUL<<16 | gc.TUINT32,
 		gc.OHMUL<<16 | gc.TPTR32:
-		a = i386.AMULL
+		a = x86.AMULL
 
 	case gc.ODIV<<16 | gc.TINT8,
 		gc.OMOD<<16 | gc.TINT8:
-		a = i386.AIDIVB
+		a = x86.AIDIVB
 
 	case gc.ODIV<<16 | gc.TUINT8,
 		gc.OMOD<<16 | gc.TUINT8:
-		a = i386.ADIVB
+		a = x86.ADIVB
 
 	case gc.ODIV<<16 | gc.TINT16,
 		gc.OMOD<<16 | gc.TINT16:
-		a = i386.AIDIVW
+		a = x86.AIDIVW
 
 	case gc.ODIV<<16 | gc.TUINT16,
 		gc.OMOD<<16 | gc.TUINT16:
-		a = i386.ADIVW
+		a = x86.ADIVW
 
 	case gc.ODIV<<16 | gc.TINT32,
 		gc.OMOD<<16 | gc.TINT32:
-		a = i386.AIDIVL
+		a = x86.AIDIVL
 
 	case gc.ODIV<<16 | gc.TUINT32,
 		gc.ODIV<<16 | gc.TPTR32,
 		gc.OMOD<<16 | gc.TUINT32,
 		gc.OMOD<<16 | gc.TPTR32:
-		a = i386.ADIVL
+		a = x86.ADIVL
 
 	case gc.OEXTEND<<16 | gc.TINT16:
-		a = i386.ACWD
+		a = x86.ACWD
 
 	case gc.OEXTEND<<16 | gc.TINT32:
-		a = i386.ACDQ
+		a = x86.ACDQ
 	}
 
 	return a
@@ -402,8 +402,49 @@
 	a := obj.AXXX
 	et := int(gc.Simtype[t.Etype])
 
-	if gc.Use_sse != 0 {
-		goto sse
+	if gc.Use_sse {
+		switch uint32(op)<<16 | uint32(et) {
+		default:
+			gc.Fatal("foptoas-sse: no entry %v-%v", gc.Oconv(int(op), 0), gc.Tconv(t, 0))
+
+		case gc.OCMP<<16 | gc.TFLOAT32:
+			a = x86.AUCOMISS
+
+		case gc.OCMP<<16 | gc.TFLOAT64:
+			a = x86.AUCOMISD
+
+		case gc.OAS<<16 | gc.TFLOAT32:
+			a = x86.AMOVSS
+
+		case gc.OAS<<16 | gc.TFLOAT64:
+			a = x86.AMOVSD
+
+		case gc.OADD<<16 | gc.TFLOAT32:
+			a = x86.AADDSS
+
+		case gc.OADD<<16 | gc.TFLOAT64:
+			a = x86.AADDSD
+
+		case gc.OSUB<<16 | gc.TFLOAT32:
+			a = x86.ASUBSS
+
+		case gc.OSUB<<16 | gc.TFLOAT64:
+			a = x86.ASUBSD
+
+		case gc.OMUL<<16 | gc.TFLOAT32:
+			a = x86.AMULSS
+
+		case gc.OMUL<<16 | gc.TFLOAT64:
+			a = x86.AMULSD
+
+		case gc.ODIV<<16 | gc.TFLOAT32:
+			a = x86.ADIVSS
+
+		case gc.ODIV<<16 | gc.TFLOAT64:
+			a = x86.ADIVSD
+		}
+
+		return a
 	}
 
 	// If we need Fpop, it means we're working on
@@ -422,315 +463,93 @@
 
 	switch uint32(op)<<16 | (uint32(et)<<8 | uint32(flg)) {
 	case gc.OADD<<16 | (gc.TFLOAT32<<8 | 0):
-		return i386.AFADDF
+		return x86.AFADDF
 
 	case gc.OADD<<16 | (gc.TFLOAT64<<8 | 0):
-		return i386.AFADDD
+		return x86.AFADDD
 
 	case gc.OADD<<16 | (gc.TFLOAT64<<8 | Fpop):
-		return i386.AFADDDP
+		return x86.AFADDDP
 
 	case gc.OSUB<<16 | (gc.TFLOAT32<<8 | 0):
-		return i386.AFSUBF
+		return x86.AFSUBF
 
 	case gc.OSUB<<16 | (gc.TFLOAT32<<8 | Frev):
-		return i386.AFSUBRF
+		return x86.AFSUBRF
 
 	case gc.OSUB<<16 | (gc.TFLOAT64<<8 | 0):
-		return i386.AFSUBD
+		return x86.AFSUBD
 
 	case gc.OSUB<<16 | (gc.TFLOAT64<<8 | Frev):
-		return i386.AFSUBRD
+		return x86.AFSUBRD
 
 	case gc.OSUB<<16 | (gc.TFLOAT64<<8 | Fpop):
-		return i386.AFSUBDP
+		return x86.AFSUBDP
 
 	case gc.OSUB<<16 | (gc.TFLOAT64<<8 | (Fpop | Frev)):
-		return i386.AFSUBRDP
+		return x86.AFSUBRDP
 
 	case gc.OMUL<<16 | (gc.TFLOAT32<<8 | 0):
-		return i386.AFMULF
+		return x86.AFMULF
 
 	case gc.OMUL<<16 | (gc.TFLOAT64<<8 | 0):
-		return i386.AFMULD
+		return x86.AFMULD
 
 	case gc.OMUL<<16 | (gc.TFLOAT64<<8 | Fpop):
-		return i386.AFMULDP
+		return x86.AFMULDP
 
 	case gc.ODIV<<16 | (gc.TFLOAT32<<8 | 0):
-		return i386.AFDIVF
+		return x86.AFDIVF
 
 	case gc.ODIV<<16 | (gc.TFLOAT32<<8 | Frev):
-		return i386.AFDIVRF
+		return x86.AFDIVRF
 
 	case gc.ODIV<<16 | (gc.TFLOAT64<<8 | 0):
-		return i386.AFDIVD
+		return x86.AFDIVD
 
 	case gc.ODIV<<16 | (gc.TFLOAT64<<8 | Frev):
-		return i386.AFDIVRD
+		return x86.AFDIVRD
 
 	case gc.ODIV<<16 | (gc.TFLOAT64<<8 | Fpop):
-		return i386.AFDIVDP
+		return x86.AFDIVDP
 
 	case gc.ODIV<<16 | (gc.TFLOAT64<<8 | (Fpop | Frev)):
-		return i386.AFDIVRDP
+		return x86.AFDIVRDP
 
 	case gc.OCMP<<16 | (gc.TFLOAT32<<8 | 0):
-		return i386.AFCOMF
+		return x86.AFCOMF
 
 	case gc.OCMP<<16 | (gc.TFLOAT32<<8 | Fpop):
-		return i386.AFCOMFP
+		return x86.AFCOMFP
 
 	case gc.OCMP<<16 | (gc.TFLOAT64<<8 | 0):
-		return i386.AFCOMD
+		return x86.AFCOMD
 
 	case gc.OCMP<<16 | (gc.TFLOAT64<<8 | Fpop):
-		return i386.AFCOMDP
+		return x86.AFCOMDP
 
 	case gc.OCMP<<16 | (gc.TFLOAT64<<8 | Fpop2):
-		return i386.AFCOMDPP
+		return x86.AFCOMDPP
 
 	case gc.OMINUS<<16 | (gc.TFLOAT32<<8 | 0):
-		return i386.AFCHS
+		return x86.AFCHS
 
 	case gc.OMINUS<<16 | (gc.TFLOAT64<<8 | 0):
-		return i386.AFCHS
+		return x86.AFCHS
 	}
 
 	gc.Fatal("foptoas %v %v %#x", gc.Oconv(int(op), 0), gc.Tconv(t, 0), flg)
 	return 0
-
-sse:
-	switch uint32(op)<<16 | uint32(et) {
-	default:
-		gc.Fatal("foptoas-sse: no entry %v-%v", gc.Oconv(int(op), 0), gc.Tconv(t, 0))
-
-	case gc.OCMP<<16 | gc.TFLOAT32:
-		a = i386.AUCOMISS
-
-	case gc.OCMP<<16 | gc.TFLOAT64:
-		a = i386.AUCOMISD
-
-	case gc.OAS<<16 | gc.TFLOAT32:
-		a = i386.AMOVSS
-
-	case gc.OAS<<16 | gc.TFLOAT64:
-		a = i386.AMOVSD
-
-	case gc.OADD<<16 | gc.TFLOAT32:
-		a = i386.AADDSS
-
-	case gc.OADD<<16 | gc.TFLOAT64:
-		a = i386.AADDSD
-
-	case gc.OSUB<<16 | gc.TFLOAT32:
-		a = i386.ASUBSS
-
-	case gc.OSUB<<16 | gc.TFLOAT64:
-		a = i386.ASUBSD
-
-	case gc.OMUL<<16 | gc.TFLOAT32:
-		a = i386.AMULSS
-
-	case gc.OMUL<<16 | gc.TFLOAT64:
-		a = i386.AMULSD
-
-	case gc.ODIV<<16 | gc.TFLOAT32:
-		a = i386.ADIVSS
-
-	case gc.ODIV<<16 | gc.TFLOAT64:
-		a = i386.ADIVSD
-	}
-
-	return a
 }
 
 var resvd = []int{
 	//	REG_DI,	// for movstring
 	//	REG_SI,	// for movstring
 
-	i386.REG_AX, // for divide
-	i386.REG_CX, // for shift
-	i386.REG_DX, // for divide
-	i386.REG_SP, // for stack
-
-	i386.REG_BL, // because REG_BX can be allocated
-	i386.REG_BH,
-}
-
-func ginit() {
-	for i := 0; i < len(reg); i++ {
-		reg[i] = 1
-	}
-	for i := i386.REG_AX; i <= i386.REG_DI; i++ {
-		reg[i] = 0
-	}
-	for i := i386.REG_X0; i <= i386.REG_X7; i++ {
-		reg[i] = 0
-	}
-	for i := 0; i < len(resvd); i++ {
-		reg[resvd[i]]++
-	}
-}
-
-var regpc [i386.MAXREG]uint32
-
-func gclean() {
-	for i := 0; i < len(resvd); i++ {
-		reg[resvd[i]]--
-	}
-
-	for i := i386.REG_AX; i <= i386.REG_DI; i++ {
-		if reg[i] != 0 {
-			gc.Yyerror("reg %v left allocated at %x", obj.Rconv(i), regpc[i])
-		}
-	}
-	for i := i386.REG_X0; i <= i386.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 := i386.REG_AX; i <= i386.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 := i386.REG_X0; i <= i386.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 >= i386.REG_AX && i <= i386.REG_DI {
-				goto out
-			}
-		}
-
-		for i = i386.REG_AX; i <= i386.REG_DI; i++ {
-			if reg[i] == 0 {
-				goto out
-			}
-		}
-
-		fmt.Printf("registers allocated at\n")
-		for i := i386.REG_AX; i <= i386.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 = i386.REG_F0
-			goto out
-		}
-
-		if o != nil && o.Op == gc.OREGISTER {
-			i = int(o.Val.U.Reg)
-			if i >= i386.REG_X0 && i <= i386.REG_X7 {
-				goto out
-			}
-		}
-
-		for i = i386.REG_X0; i <= i386.REG_X7; i++ {
-			if reg[i] == 0 {
-				goto out
-			}
-		}
-		fmt.Printf("registers allocated at\n")
-		for i := i386.REG_X0; i <= i386.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 == i386.REG_SP {
-		fmt.Printf("alloc SP\n")
-	}
-	if reg[i] == 0 {
-		regpc[i] = uint32(obj.Getcallerpc(&n))
-		if i == i386.REG_AX || i == i386.REG_CX || i == i386.REG_DX || i == i386.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 == i386.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 == i386.REG_AX || i == i386.REG_CX || i == i386.REG_DX || i == i386.REG_SP) {
-		gc.Fatal("regfree %v", obj.Rconv(i))
-	}
+	x86.REG_AX, // for divide
+	x86.REG_CX, // for shift
+	x86.REG_DX, // for divide
+	x86.REG_SP, // for stack
 }
 
 /*
@@ -747,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) {
@@ -793,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
 			}
 
@@ -802,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
 			}
@@ -842,7 +671,7 @@
 	}
 	nsclean--
 	if sclean[nsclean].Op != gc.OEMPTY {
-		regfree(&sclean[nsclean])
+		gc.Regfree(&sclean[nsclean])
 	}
 }
 
@@ -893,12 +722,12 @@
 	tt := gc.Simsimtype(t.Type)
 	cvt := t.Type
 
-	if gc.Iscomplex[ft] != 0 || gc.Iscomplex[tt] != 0 {
+	if gc.Iscomplex[ft] || gc.Iscomplex[tt] {
 		gc.Complexmove(f, t)
 		return
 	}
 
-	if gc.Isfloat[ft] != 0 || gc.Isfloat[tt] != 0 {
+	if gc.Isfloat[ft] || gc.Isfloat[tt] {
 		floatmove(f, t)
 		return
 	}
@@ -907,7 +736,7 @@
 	// except 64-bit, which always copies via registers anyway.
 	var r1 gc.Node
 	var a int
-	if gc.Isint[ft] != 0 && gc.Isint[tt] != 0 && !gc.Is64(f.Type) && !gc.Is64(t.Type) && gc.Ismem(f) && gc.Ismem(t) {
+	if gc.Isint[ft] && gc.Isint[tt] && !gc.Is64(f.Type) && !gc.Is64(t.Type) && gc.Ismem(f) && gc.Ismem(t) {
 		goto hard
 	}
 
@@ -928,7 +757,9 @@
 
 	switch uint32(ft)<<16 | uint32(tt) {
 	default:
-		goto fatal
+		// should not happen
+		gc.Fatal("gmove %v -> %v", gc.Nconv(f, 0), gc.Nconv(t, 0))
+		return
 
 		/*
 		 * integer copy and truncate
@@ -937,7 +768,7 @@
 		gc.TINT8<<16 | gc.TUINT8,
 		gc.TUINT8<<16 | gc.TINT8,
 		gc.TUINT8<<16 | gc.TUINT8:
-		a = i386.AMOVB
+		a = x86.AMOVB
 
 	case gc.TINT16<<16 | gc.TINT8, // truncate
 		gc.TUINT16<<16 | gc.TINT8,
@@ -947,7 +778,7 @@
 		gc.TUINT16<<16 | gc.TUINT8,
 		gc.TINT32<<16 | gc.TUINT8,
 		gc.TUINT32<<16 | gc.TUINT8:
-		a = i386.AMOVB
+		a = x86.AMOVB
 
 		goto rsrc
 
@@ -960,9 +791,9 @@
 		split64(f, &flo, &fhi)
 
 		var r1 gc.Node
-		gc.Nodreg(&r1, t.Type, i386.REG_AX)
+		gc.Nodreg(&r1, t.Type, x86.REG_AX)
 		gmove(&flo, &r1)
-		gins(i386.AMOVB, &r1, t)
+		gins(x86.AMOVB, &r1, t)
 		splitclean()
 		return
 
@@ -970,13 +801,13 @@
 		gc.TINT16<<16 | gc.TUINT16,
 		gc.TUINT16<<16 | gc.TINT16,
 		gc.TUINT16<<16 | gc.TUINT16:
-		a = i386.AMOVW
+		a = x86.AMOVW
 
 	case gc.TINT32<<16 | gc.TINT16, // truncate
 		gc.TUINT32<<16 | gc.TINT16,
 		gc.TINT32<<16 | gc.TUINT16,
 		gc.TUINT32<<16 | gc.TUINT16:
-		a = i386.AMOVW
+		a = x86.AMOVW
 
 		goto rsrc
 
@@ -989,9 +820,9 @@
 		split64(f, &flo, &fhi)
 
 		var r1 gc.Node
-		gc.Nodreg(&r1, t.Type, i386.REG_AX)
+		gc.Nodreg(&r1, t.Type, x86.REG_AX)
 		gmove(&flo, &r1)
-		gins(i386.AMOVW, &r1, t)
+		gins(x86.AMOVW, &r1, t)
 		splitclean()
 		return
 
@@ -999,7 +830,7 @@
 		gc.TINT32<<16 | gc.TUINT32,
 		gc.TUINT32<<16 | gc.TINT32,
 		gc.TUINT32<<16 | gc.TUINT32:
-		a = i386.AMOVL
+		a = x86.AMOVL
 
 	case gc.TINT64<<16 | gc.TINT32, // truncate
 		gc.TUINT64<<16 | gc.TINT32,
@@ -1010,9 +841,9 @@
 		split64(f, &flo, &fhi)
 
 		var r1 gc.Node
-		gc.Nodreg(&r1, t.Type, i386.REG_AX)
+		gc.Nodreg(&r1, t.Type, x86.REG_AX)
 		gmove(&flo, &r1)
-		gins(i386.AMOVL, &r1, t)
+		gins(x86.AMOVL, &r1, t)
 		splitclean()
 		return
 
@@ -1028,17 +859,17 @@
 		var thi gc.Node
 		split64(t, &tlo, &thi)
 		if f.Op == gc.OLITERAL {
-			gins(i386.AMOVL, &flo, &tlo)
-			gins(i386.AMOVL, &fhi, &thi)
+			gins(x86.AMOVL, &flo, &tlo)
+			gins(x86.AMOVL, &fhi, &thi)
 		} else {
 			var r1 gc.Node
-			gc.Nodreg(&r1, gc.Types[gc.TUINT32], i386.REG_AX)
+			gc.Nodreg(&r1, gc.Types[gc.TUINT32], x86.REG_AX)
 			var r2 gc.Node
-			gc.Nodreg(&r2, gc.Types[gc.TUINT32], i386.REG_DX)
-			gins(i386.AMOVL, &flo, &r1)
-			gins(i386.AMOVL, &fhi, &r2)
-			gins(i386.AMOVL, &r1, &tlo)
-			gins(i386.AMOVL, &r2, &thi)
+			gc.Nodreg(&r2, gc.Types[gc.TUINT32], x86.REG_DX)
+			gins(x86.AMOVL, &flo, &r1)
+			gins(x86.AMOVL, &fhi, &r2)
+			gins(x86.AMOVL, &r1, &tlo)
+			gins(x86.AMOVL, &r2, &thi)
 		}
 
 		splitclean()
@@ -1050,13 +881,13 @@
 		 */
 	case gc.TINT8<<16 | gc.TINT16, // sign extend int8
 		gc.TINT8<<16 | gc.TUINT16:
-		a = i386.AMOVBWSX
+		a = x86.AMOVBWSX
 
 		goto rdst
 
 	case gc.TINT8<<16 | gc.TINT32,
 		gc.TINT8<<16 | gc.TUINT32:
-		a = i386.AMOVBLSX
+		a = x86.AMOVBLSX
 		goto rdst
 
 	case gc.TINT8<<16 | gc.TINT64, // convert via int32
@@ -1067,13 +898,13 @@
 
 	case gc.TUINT8<<16 | gc.TINT16, // zero extend uint8
 		gc.TUINT8<<16 | gc.TUINT16:
-		a = i386.AMOVBWZX
+		a = x86.AMOVBWZX
 
 		goto rdst
 
 	case gc.TUINT8<<16 | gc.TINT32,
 		gc.TUINT8<<16 | gc.TUINT32:
-		a = i386.AMOVBLZX
+		a = x86.AMOVBLZX
 		goto rdst
 
 	case gc.TUINT8<<16 | gc.TINT64, // convert via uint32
@@ -1084,7 +915,7 @@
 
 	case gc.TINT16<<16 | gc.TINT32, // sign extend int16
 		gc.TINT16<<16 | gc.TUINT32:
-		a = i386.AMOVWLSX
+		a = x86.AMOVWLSX
 
 		goto rdst
 
@@ -1096,7 +927,7 @@
 
 	case gc.TUINT16<<16 | gc.TINT32, // zero extend uint16
 		gc.TUINT16<<16 | gc.TUINT32:
-		a = i386.AMOVWLZX
+		a = x86.AMOVWLZX
 
 		goto rdst
 
@@ -1113,13 +944,13 @@
 		split64(t, &tlo, &thi)
 
 		var flo gc.Node
-		gc.Nodreg(&flo, tlo.Type, i386.REG_AX)
+		gc.Nodreg(&flo, tlo.Type, x86.REG_AX)
 		var fhi gc.Node
-		gc.Nodreg(&fhi, thi.Type, i386.REG_DX)
+		gc.Nodreg(&fhi, thi.Type, x86.REG_DX)
 		gmove(f, &flo)
-		gins(i386.ACDQ, nil, nil)
-		gins(i386.AMOVL, &flo, &tlo)
-		gins(i386.AMOVL, &fhi, &thi)
+		gins(x86.ACDQ, nil, nil)
+		gins(x86.AMOVL, &flo, &tlo)
+		gins(x86.AMOVL, &fhi, &thi)
 		splitclean()
 		return
 
@@ -1130,7 +961,7 @@
 		split64(t, &tlo, &thi)
 
 		gmove(f, &tlo)
-		gins(i386.AMOVL, ncon(0), &thi)
+		gins(x86.AMOVL, ncon(0), &thi)
 		splitclean()
 		return
 	}
@@ -1140,34 +971,32 @@
 
 	// 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)
-	return
+		gins(a, f, &r1)
+		gmove(&r1, t)
+		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
-
-	// should not happen
-fatal:
-	gc.Fatal("gmove %v -> %v", gc.Nconv(f, 0), gc.Nconv(t, 0))
 }
 
 func floatmove(f *gc.Node, t *gc.Node) {
@@ -1178,7 +1007,7 @@
 	cvt := t.Type
 
 	// cannot have two floating point memory operands.
-	if gc.Isfloat[ft] != 0 && gc.Isfloat[tt] != 0 && gc.Ismem(f) && gc.Ismem(t) {
+	if gc.Isfloat[ft] && gc.Isfloat[tt] && gc.Ismem(f) && gc.Ismem(t) {
 		goto hard
 	}
 
@@ -1192,7 +1021,7 @@
 		// some constants can't move directly to memory.
 		if gc.Ismem(t) {
 			// float constants come from memory.
-			if gc.Isfloat[tt] != 0 {
+			if gc.Isfloat[tt] {
 				goto hard
 			}
 		}
@@ -1207,7 +1036,7 @@
 
 	switch uint32(ft)<<16 | uint32(tt) {
 	default:
-		if gc.Use_sse != 0 {
+		if gc.Use_sse {
 			floatmove_sse(f, t)
 		} else {
 			floatmove_387(f, t)
@@ -1223,11 +1052,11 @@
 		}
 
 		var r1 gc.Node
-		gc.Nodreg(&r1, gc.Types[ft], i386.REG_F0)
+		gc.Nodreg(&r1, gc.Types[ft], x86.REG_F0)
 		if ft == gc.TFLOAT32 {
-			gins(i386.AFMOVF, f, &r1)
+			gins(x86.AFMOVF, f, &r1)
 		} else {
-			gins(i386.AFMOVD, f, &r1)
+			gins(x86.AFMOVD, f, &r1)
 		}
 
 		// set round to zero mode during conversion
@@ -1236,17 +1065,17 @@
 
 		var t2 gc.Node
 		memname(&t2, gc.Types[gc.TUINT16])
-		gins(i386.AFSTCW, nil, &t1)
-		gins(i386.AMOVW, ncon(0xf7f), &t2)
-		gins(i386.AFLDCW, &t2, nil)
+		gins(x86.AFSTCW, nil, &t1)
+		gins(x86.AMOVW, ncon(0xf7f), &t2)
+		gins(x86.AFLDCW, &t2, nil)
 		if tt == gc.TINT16 {
-			gins(i386.AFMOVWP, &r1, t)
+			gins(x86.AFMOVWP, &r1, t)
 		} else if tt == gc.TINT32 {
-			gins(i386.AFMOVLP, &r1, t)
+			gins(x86.AFMOVLP, &r1, t)
 		} else {
-			gins(i386.AFMOVVP, &r1, t)
+			gins(x86.AFMOVVP, &r1, t)
 		}
-		gins(i386.AFLDCW, &t1, nil)
+		gins(x86.AFLDCW, &t1, nil)
 		return
 
 	case gc.TFLOAT32<<16 | gc.TUINT64,
@@ -1258,36 +1087,36 @@
 
 		bignodes()
 		var f0 gc.Node
-		gc.Nodreg(&f0, gc.Types[ft], i386.REG_F0)
+		gc.Nodreg(&f0, gc.Types[ft], x86.REG_F0)
 		var f1 gc.Node
-		gc.Nodreg(&f1, gc.Types[ft], i386.REG_F0+1)
+		gc.Nodreg(&f1, gc.Types[ft], x86.REG_F0+1)
 		var ax gc.Node
-		gc.Nodreg(&ax, gc.Types[gc.TUINT16], i386.REG_AX)
+		gc.Nodreg(&ax, gc.Types[gc.TUINT16], x86.REG_AX)
 
 		if ft == gc.TFLOAT32 {
-			gins(i386.AFMOVF, f, &f0)
+			gins(x86.AFMOVF, f, &f0)
 		} else {
-			gins(i386.AFMOVD, f, &f0)
+			gins(x86.AFMOVD, f, &f0)
 		}
 
 		// if 0 > v { answer = 0 }
-		gins(i386.AFMOVD, &zerof, &f0)
+		gins(x86.AFMOVD, &zerof, &f0)
 
-		gins(i386.AFUCOMIP, &f0, &f1)
+		gins(x86.AFUCOMIP, &f0, &f1)
 		p1 := gc.Gbranch(optoas(gc.OGT, gc.Types[tt]), nil, 0)
 
 		// if 1<<64 <= v { answer = 0 too }
-		gins(i386.AFMOVD, &two64f, &f0)
+		gins(x86.AFMOVD, &two64f, &f0)
 
-		gins(i386.AFUCOMIP, &f0, &f1)
+		gins(x86.AFUCOMIP, &f0, &f1)
 		p2 := gc.Gbranch(optoas(gc.OGT, gc.Types[tt]), nil, 0)
 		gc.Patch(p1, gc.Pc)
-		gins(i386.AFMOVVP, &f0, t) // don't care about t, but will pop the stack
+		gins(x86.AFMOVVP, &f0, t) // don't care about t, but will pop the stack
 		var thi gc.Node
 		var tlo gc.Node
 		split64(t, &tlo, &thi)
-		gins(i386.AMOVL, ncon(0), &tlo)
-		gins(i386.AMOVL, ncon(0), &thi)
+		gins(x86.AMOVL, ncon(0), &tlo)
+		gins(x86.AMOVL, ncon(0), &thi)
 		splitclean()
 		p1 = gc.Gbranch(obj.AJMP, nil, 0)
 		gc.Patch(p2, gc.Pc)
@@ -1302,28 +1131,28 @@
 
 		var t2 gc.Node
 		memname(&t2, gc.Types[gc.TUINT16])
-		gins(i386.AFSTCW, nil, &t1)
-		gins(i386.AMOVW, ncon(0xf7f), &t2)
-		gins(i386.AFLDCW, &t2, nil)
+		gins(x86.AFSTCW, nil, &t1)
+		gins(x86.AMOVW, ncon(0xf7f), &t2)
+		gins(x86.AFLDCW, &t2, nil)
 
 		// actual work
-		gins(i386.AFMOVD, &two63f, &f0)
+		gins(x86.AFMOVD, &two63f, &f0)
 
-		gins(i386.AFUCOMIP, &f0, &f1)
+		gins(x86.AFUCOMIP, &f0, &f1)
 		p2 = gc.Gbranch(optoas(gc.OLE, gc.Types[tt]), nil, 0)
-		gins(i386.AFMOVVP, &f0, t)
+		gins(x86.AFMOVVP, &f0, t)
 		p3 := gc.Gbranch(obj.AJMP, nil, 0)
 		gc.Patch(p2, gc.Pc)
-		gins(i386.AFMOVD, &two63f, &f0)
-		gins(i386.AFSUBDP, &f0, &f1)
-		gins(i386.AFMOVVP, &f0, t)
+		gins(x86.AFMOVD, &two63f, &f0)
+		gins(x86.AFSUBDP, &f0, &f1)
+		gins(x86.AFMOVVP, &f0, t)
 		split64(t, &tlo, &thi)
-		gins(i386.AXORL, ncon(0x80000000), &thi) // + 2^63
+		gins(x86.AXORL, ncon(0x80000000), &thi) // + 2^63
 		gc.Patch(p3, gc.Pc)
 		splitclean()
 
 		// restore rounding mode
-		gins(i386.AFLDCW, &t1, nil)
+		gins(x86.AFLDCW, &t1, nil)
 
 		gc.Patch(p1, gc.Pc)
 		return
@@ -1337,12 +1166,12 @@
 			goto hardmem
 		}
 		var f0 gc.Node
-		gc.Nodreg(&f0, t.Type, i386.REG_F0)
-		gins(i386.AFMOVV, f, &f0)
+		gc.Nodreg(&f0, t.Type, x86.REG_F0)
+		gins(x86.AFMOVV, f, &f0)
 		if tt == gc.TFLOAT32 {
-			gins(i386.AFMOVFP, &f0, t)
+			gins(x86.AFMOVFP, &f0, t)
 		} else {
-			gins(i386.AFMOVDP, &f0, t)
+			gins(x86.AFMOVDP, &f0, t)
 		}
 		return
 
@@ -1352,30 +1181,30 @@
 	case gc.TUINT64<<16 | gc.TFLOAT32,
 		gc.TUINT64<<16 | gc.TFLOAT64:
 		var ax gc.Node
-		gc.Nodreg(&ax, gc.Types[gc.TUINT32], i386.REG_AX)
+		gc.Nodreg(&ax, gc.Types[gc.TUINT32], x86.REG_AX)
 
 		var dx gc.Node
-		gc.Nodreg(&dx, gc.Types[gc.TUINT32], i386.REG_DX)
+		gc.Nodreg(&dx, gc.Types[gc.TUINT32], x86.REG_DX)
 		var cx gc.Node
-		gc.Nodreg(&cx, gc.Types[gc.TUINT32], i386.REG_CX)
+		gc.Nodreg(&cx, gc.Types[gc.TUINT32], x86.REG_CX)
 		var t1 gc.Node
 		gc.Tempname(&t1, f.Type)
 		var tlo gc.Node
 		var thi gc.Node
 		split64(&t1, &tlo, &thi)
 		gmove(f, &t1)
-		gins(i386.ACMPL, &thi, ncon(0))
-		p1 := gc.Gbranch(i386.AJLT, nil, 0)
+		gins(x86.ACMPL, &thi, ncon(0))
+		p1 := gc.Gbranch(x86.AJLT, nil, 0)
 
 		// native
 		var r1 gc.Node
-		gc.Nodreg(&r1, gc.Types[tt], i386.REG_F0)
+		gc.Nodreg(&r1, gc.Types[tt], x86.REG_F0)
 
-		gins(i386.AFMOVV, &t1, &r1)
+		gins(x86.AFMOVV, &t1, &r1)
 		if tt == gc.TFLOAT32 {
-			gins(i386.AFMOVFP, &r1, t)
+			gins(x86.AFMOVFP, &r1, t)
 		} else {
-			gins(i386.AFMOVDP, &r1, t)
+			gins(x86.AFMOVDP, &r1, t)
 		}
 		p2 := gc.Gbranch(obj.AJMP, nil, 0)
 
@@ -1384,25 +1213,25 @@
 
 		gmove(&tlo, &ax)
 		gmove(&thi, &dx)
-		p1 = gins(i386.ASHRL, ncon(1), &ax)
-		p1.From.Index = i386.REG_DX // double-width shift DX -> AX
+		p1 = gins(x86.ASHRL, ncon(1), &ax)
+		p1.From.Index = x86.REG_DX // double-width shift DX -> AX
 		p1.From.Scale = 0
-		gins(i386.AMOVL, ncon(0), &cx)
-		gins(i386.ASETCC, nil, &cx)
-		gins(i386.AORL, &cx, &ax)
-		gins(i386.ASHRL, ncon(1), &dx)
+		gins(x86.AMOVL, ncon(0), &cx)
+		gins(x86.ASETCC, nil, &cx)
+		gins(x86.AORL, &cx, &ax)
+		gins(x86.ASHRL, ncon(1), &dx)
 		gmove(&dx, &thi)
 		gmove(&ax, &tlo)
-		gc.Nodreg(&r1, gc.Types[tt], i386.REG_F0)
+		gc.Nodreg(&r1, gc.Types[tt], x86.REG_F0)
 		var r2 gc.Node
-		gc.Nodreg(&r2, gc.Types[tt], i386.REG_F0+1)
-		gins(i386.AFMOVV, &t1, &r1)
-		gins(i386.AFMOVD, &r1, &r1)
-		gins(i386.AFADDDP, &r1, &r2)
+		gc.Nodreg(&r2, gc.Types[tt], x86.REG_F0+1)
+		gins(x86.AFMOVV, &t1, &r1)
+		gins(x86.AFMOVD, &r1, &r1)
+		gins(x86.AFADDDP, &r1, &r2)
 		if tt == gc.TFLOAT32 {
-			gins(i386.AFMOVFP, &r1, t)
+			gins(x86.AFMOVFP, &r1, t)
 		} else {
-			gins(i386.AFMOVDP, &r1, t)
+			gins(x86.AFMOVDP, &r1, t)
 		}
 		gc.Patch(p2, gc.Pc)
 		splitclean()
@@ -1411,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
@@ -1452,12 +1281,12 @@
 			goto hardmem
 		}
 		var r1 gc.Node
-		gc.Nodreg(&r1, gc.Types[ft], i386.REG_F0)
+		gc.Nodreg(&r1, gc.Types[ft], x86.REG_F0)
 		if f.Op != gc.OREGISTER {
 			if ft == gc.TFLOAT32 {
-				gins(i386.AFMOVF, f, &r1)
+				gins(x86.AFMOVF, f, &r1)
 			} else {
-				gins(i386.AFMOVD, f, &r1)
+				gins(x86.AFMOVD, f, &r1)
 			}
 		}
 
@@ -1467,17 +1296,17 @@
 
 		var t2 gc.Node
 		memname(&t2, gc.Types[gc.TUINT16])
-		gins(i386.AFSTCW, nil, &t1)
-		gins(i386.AMOVW, ncon(0xf7f), &t2)
-		gins(i386.AFLDCW, &t2, nil)
+		gins(x86.AFSTCW, nil, &t1)
+		gins(x86.AMOVW, ncon(0xf7f), &t2)
+		gins(x86.AFLDCW, &t2, nil)
 		if tt == gc.TINT16 {
-			gins(i386.AFMOVWP, &r1, t)
+			gins(x86.AFMOVWP, &r1, t)
 		} else if tt == gc.TINT32 {
-			gins(i386.AFMOVLP, &r1, t)
+			gins(x86.AFMOVLP, &r1, t)
 		} else {
-			gins(i386.AFMOVVP, &r1, t)
+			gins(x86.AFMOVVP, &r1, t)
 		}
-		gins(i386.AFLDCW, &t1, nil)
+		gins(x86.AFLDCW, &t1, nil)
 		return
 
 		// convert via int32.
@@ -1496,9 +1325,9 @@
 			gc.Fatal("gmove %v", gc.Nconv(t, 0))
 
 		case gc.TINT8:
-			gins(i386.ACMPL, &t1, ncon(-0x80&(1<<32-1)))
+			gins(x86.ACMPL, &t1, ncon(-0x80&(1<<32-1)))
 			p1 := gc.Gbranch(optoas(gc.OLT, gc.Types[gc.TINT32]), nil, -1)
-			gins(i386.ACMPL, &t1, ncon(0x7f))
+			gins(x86.ACMPL, &t1, ncon(0x7f))
 			p2 := gc.Gbranch(optoas(gc.OGT, gc.Types[gc.TINT32]), nil, -1)
 			p3 := gc.Gbranch(obj.AJMP, nil, 0)
 			gc.Patch(p1, gc.Pc)
@@ -1508,16 +1337,16 @@
 			gmove(&t1, t)
 
 		case gc.TUINT8:
-			gins(i386.ATESTL, ncon(0xffffff00), &t1)
-			p1 := gc.Gbranch(i386.AJEQ, nil, +1)
-			gins(i386.AMOVL, ncon(0), &t1)
+			gins(x86.ATESTL, ncon(0xffffff00), &t1)
+			p1 := gc.Gbranch(x86.AJEQ, nil, +1)
+			gins(x86.AMOVL, ncon(0), &t1)
 			gc.Patch(p1, gc.Pc)
 			gmove(&t1, t)
 
 		case gc.TUINT16:
-			gins(i386.ATESTL, ncon(0xffff0000), &t1)
-			p1 := gc.Gbranch(i386.AJEQ, nil, +1)
-			gins(i386.AMOVL, ncon(0), &t1)
+			gins(x86.ATESTL, ncon(0xffff0000), &t1)
+			p1 := gc.Gbranch(x86.AJEQ, nil, +1)
+			gins(x86.AMOVL, ncon(0), &t1)
 			gc.Patch(p1, gc.Pc)
 			gmove(&t1, t)
 		}
@@ -1550,13 +1379,13 @@
 
 		switch ft {
 		case gc.TINT16:
-			a = i386.AFMOVW
+			a = x86.AFMOVW
 
 		case gc.TINT32:
-			a = i386.AFMOVL
+			a = x86.AFMOVL
 
 		default:
-			a = i386.AFMOVV
+			a = x86.AFMOVV
 		}
 
 		// convert via int32 memory
@@ -1592,23 +1421,23 @@
 			goto hard
 		}
 		if f.Op == gc.OREGISTER && t.Op == gc.OREGISTER {
-			if f.Val.U.Reg != i386.REG_F0 || t.Val.U.Reg != i386.REG_F0 {
+			if f.Val.U.Reg != x86.REG_F0 || t.Val.U.Reg != x86.REG_F0 {
 				goto fatal
 			}
 			return
 		}
 
-		a = i386.AFMOVF
+		a = x86.AFMOVF
 		if ft == gc.TFLOAT64 {
-			a = i386.AFMOVD
+			a = x86.AFMOVD
 		}
 		if gc.Ismem(t) {
-			if f.Op != gc.OREGISTER || f.Val.U.Reg != i386.REG_F0 {
+			if f.Op != gc.OREGISTER || f.Val.U.Reg != x86.REG_F0 {
 				gc.Fatal("gmove %v", gc.Nconv(f, 0))
 			}
-			a = i386.AFMOVFP
+			a = x86.AFMOVFP
 			if ft == gc.TFLOAT64 {
-				a = i386.AFMOVDP
+				a = x86.AFMOVDP
 			}
 		}
 
@@ -1617,16 +1446,16 @@
 			goto hard
 		}
 		if f.Op == gc.OREGISTER && t.Op == gc.OREGISTER {
-			if f.Val.U.Reg != i386.REG_F0 || t.Val.U.Reg != i386.REG_F0 {
+			if f.Val.U.Reg != x86.REG_F0 || t.Val.U.Reg != x86.REG_F0 {
 				goto fatal
 			}
 			return
 		}
 
 		if f.Op == gc.OREGISTER {
-			gins(i386.AFMOVDP, f, t)
+			gins(x86.AFMOVDP, f, t)
 		} else {
-			gins(i386.AFMOVF, f, t)
+			gins(x86.AFMOVF, f, t)
 		}
 		return
 
@@ -1637,15 +1466,15 @@
 		if f.Op == gc.OREGISTER && t.Op == gc.OREGISTER {
 			var r1 gc.Node
 			gc.Tempname(&r1, gc.Types[gc.TFLOAT32])
-			gins(i386.AFMOVFP, f, &r1)
-			gins(i386.AFMOVF, &r1, t)
+			gins(x86.AFMOVFP, f, &r1)
+			gins(x86.AFMOVF, &r1, t)
 			return
 		}
 
 		if f.Op == gc.OREGISTER {
-			gins(i386.AFMOVFP, f, t)
+			gins(x86.AFMOVFP, f, t)
 		} else {
-			gins(i386.AFMOVD, f, t)
+			gins(x86.AFMOVD, f, t)
 		}
 		return
 	}
@@ -1655,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
@@ -1716,11 +1545,11 @@
 		goto hardmem
 
 	case gc.TFLOAT32<<16 | gc.TINT32:
-		a = i386.ACVTTSS2SL
+		a = x86.ACVTTSS2SL
 		goto rdst
 
 	case gc.TFLOAT64<<16 | gc.TINT32:
-		a = i386.ACVTTSD2SL
+		a = x86.ACVTTSD2SL
 		goto rdst
 
 		// convert via int32 memory
@@ -1747,28 +1576,28 @@
 		goto hardmem
 
 	case gc.TINT32<<16 | gc.TFLOAT32:
-		a = i386.ACVTSL2SS
+		a = x86.ACVTSL2SS
 		goto rdst
 
 	case gc.TINT32<<16 | gc.TFLOAT64:
-		a = i386.ACVTSL2SD
+		a = x86.ACVTSL2SD
 		goto rdst
 
 		/*
 		 * float to float
 		 */
 	case gc.TFLOAT32<<16 | gc.TFLOAT32:
-		a = i386.AMOVSS
+		a = x86.AMOVSS
 
 	case gc.TFLOAT64<<16 | gc.TFLOAT64:
-		a = i386.AMOVSD
+		a = x86.AMOVSD
 
 	case gc.TFLOAT32<<16 | gc.TFLOAT64:
-		a = i386.ACVTSS2SD
+		a = x86.ACVTSS2SD
 		goto rdst
 
 	case gc.TFLOAT64<<16 | gc.TFLOAT32:
-		a = i386.ACVTSD2SS
+		a = x86.ACVTSD2SS
 		goto rdst
 	}
 
@@ -1777,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
@@ -1794,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
 }
 
@@ -1823,65 +1652,63 @@
  *	as f, t
  */
 func gins(as int, f *gc.Node, t *gc.Node) *obj.Prog {
-	if as == i386.AFMOVF && f != nil && f.Op == gc.OREGISTER && t != nil && t.Op == gc.OREGISTER {
+	if as == x86.AFMOVF && f != nil && f.Op == gc.OREGISTER && t != nil && t.Op == gc.OREGISTER {
 		gc.Fatal("gins MOVF reg, reg")
 	}
-	if as == i386.ACVTSD2SS && f != nil && f.Op == gc.OLITERAL {
+	if as == x86.ACVTSD2SS && f != nil && f.Op == gc.OLITERAL {
 		gc.Fatal("gins CVTSD2SS const")
 	}
-	if as == i386.AMOVSD && t != nil && t.Op == gc.OREGISTER && t.Val.U.Reg == i386.REG_F0 {
+	if as == x86.AMOVSD && t != nil && t.Op == gc.OREGISTER && t.Val.U.Reg == x86.REG_F0 {
 		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 i386.AMOVB,
-		i386.AMOVW,
-		i386.AMOVL:
+	case x86.AMOVB,
+		x86.AMOVW,
+		x86.AMOVL:
 		if f != nil && t != nil && samaddr(f, t) {
 			return nil
 		}
 
-	case i386.ALEAL:
+	case x86.ALEAL:
 		if f != nil && gc.Isconst(f, gc.CTNIL) {
 			gc.Fatal("gins LEAL nil %v", gc.Tconv(f.Type, 0))
 		}
 	}
 
-	af := obj.Addr{}
-	at := obj.Addr{}
-	if f != nil {
-		gc.Naddr(f, &af, 1)
-	}
-	if t != nil {
-		gc.Naddr(t, &at, 1)
-	}
 	p := gc.Prog(as)
-	if f != nil {
-		p.From = af
-	}
-	if t != nil {
-		p.To = at
-	}
+	gc.Naddr(&p.From, f)
+	gc.Naddr(&p.To, t)
+
 	if gc.Debug['g'] != 0 {
 		fmt.Printf("%v\n", p)
 	}
 
 	w := 0
 	switch as {
-	case i386.AMOVB:
+	case x86.AMOVB:
 		w = 1
 
-	case i386.AMOVW:
+	case x86.AMOVW:
 		w = 2
 
-	case i386.AMOVL:
+	case x86.AMOVL:
 		w = 4
 	}
 
-	if true && w != 0 && f != nil && (af.Width > int64(w) || at.Width > int64(w)) {
+	if true && w != 0 && f != nil && (p.From.Width > int64(w) || p.To.Width > int64(w)) {
 		gc.Dump("bad width from:", f)
 		gc.Dump("bad width to:", t)
-		gc.Fatal("bad width: %v (%d, %d)\n", p, af.Width, at.Width)
+		gc.Fatal("bad width: %v (%d, %d)\n", p, p.From.Width, p.To.Width)
 	}
 
 	if p.To.Type == obj.TYPE_ADDR && w > 0 {
@@ -1891,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 8aa6e94..e309aea7 100644
--- a/src/cmd/8g/peep.go
+++ b/src/cmd/8g/peep.go
@@ -31,29 +31,26 @@
 package main
 
 import (
+	"cmd/internal/gc"
 	"cmd/internal/obj"
-	"cmd/internal/obj/i386"
+	"cmd/internal/obj/x86"
 	"fmt"
 )
-import "cmd/internal/gc"
 
 const (
 	REGEXT      = 0
-	exregoffset = i386.REG_DI
+	exregoffset = x86.REG_DI
 )
 
 var gactive uint32
 
 // do we need the carry bit
 func needc(p *obj.Prog) bool {
-	var info gc.ProgInfo
-
 	for p != nil {
-		proginfo(&info, p)
-		if info.Flags&gc.UseCarry != 0 {
+		if p.Info.Flags&gc.UseCarry != 0 {
 			return true
 		}
-		if info.Flags&(gc.SetCarry|gc.KillCarry) != 0 {
+		if p.Info.Flags&(gc.SetCarry|gc.KillCarry) != 0 {
 			return false
 		}
 		p = p.Link
@@ -100,20 +97,20 @@
 	for r := g.Start; r != nil; r = r.Link {
 		p = r.Prog
 		switch p.As {
-		case i386.ALEAL:
+		case x86.ALEAL:
 			if regtyp(&p.To) {
 				if p.From.Sym != nil {
-					if p.From.Index == i386.REG_NONE {
+					if p.From.Index == x86.REG_NONE {
 						conprop(r)
 					}
 				}
 			}
 
-		case i386.AMOVB,
-			i386.AMOVW,
-			i386.AMOVL,
-			i386.AMOVSS,
-			i386.AMOVSD:
+		case x86.AMOVB,
+			x86.AMOVW,
+			x86.AMOVL,
+			x86.AMOVSS,
+			x86.AMOVSD:
 			if regtyp(&p.To) {
 				if p.From.Type == obj.TYPE_CONST || p.From.Type == obj.TYPE_FCONST {
 					conprop(r)
@@ -135,9 +132,9 @@
 	for r = g.Start; r != nil; r = r.Link {
 		p = r.Prog
 		switch p.As {
-		case i386.AMOVL,
-			i386.AMOVSS,
-			i386.AMOVSD:
+		case x86.AMOVL,
+			x86.AMOVSS,
+			x86.AMOVSD:
 			if regtyp(&p.To) {
 				if regtyp(&p.From) {
 					if copyprop(g, r) {
@@ -150,66 +147,66 @@
 				}
 			}
 
-		case i386.AMOVBLZX,
-			i386.AMOVWLZX,
-			i386.AMOVBLSX,
-			i386.AMOVWLSX:
+		case x86.AMOVBLZX,
+			x86.AMOVWLZX,
+			x86.AMOVBLSX,
+			x86.AMOVWLSX:
 			if regtyp(&p.To) {
 				r1 = rnops(gc.Uniqs(r))
 				if r1 != nil {
 					p1 = r1.Prog
 					if p.As == p1.As && p.To.Type == p1.From.Type && p.To.Reg == p1.From.Reg {
-						p1.As = i386.AMOVL
+						p1.As = x86.AMOVL
 						t++
 					}
 				}
 			}
 
-		case i386.AADDL,
-			i386.AADDW:
+		case x86.AADDL,
+			x86.AADDW:
 			if p.From.Type != obj.TYPE_CONST || needc(p.Link) {
 				break
 			}
 			if p.From.Offset == -1 {
-				if p.As == i386.AADDL {
-					p.As = i386.ADECL
+				if p.As == x86.AADDL {
+					p.As = x86.ADECL
 				} else {
-					p.As = i386.ADECW
+					p.As = x86.ADECW
 				}
 				p.From = obj.Addr{}
 				break
 			}
 
 			if p.From.Offset == 1 {
-				if p.As == i386.AADDL {
-					p.As = i386.AINCL
+				if p.As == x86.AADDL {
+					p.As = x86.AINCL
 				} else {
-					p.As = i386.AINCW
+					p.As = x86.AINCW
 				}
 				p.From = obj.Addr{}
 				break
 			}
 
-		case i386.ASUBL,
-			i386.ASUBW:
+		case x86.ASUBL,
+			x86.ASUBW:
 			if p.From.Type != obj.TYPE_CONST || needc(p.Link) {
 				break
 			}
 			if p.From.Offset == -1 {
-				if p.As == i386.ASUBL {
-					p.As = i386.AINCL
+				if p.As == x86.ASUBL {
+					p.As = x86.AINCL
 				} else {
-					p.As = i386.AINCW
+					p.As = x86.AINCW
 				}
 				p.From = obj.Addr{}
 				break
 			}
 
 			if p.From.Offset == 1 {
-				if p.As == i386.ASUBL {
-					p.As = i386.ADECL
+				if p.As == x86.ASUBL {
+					p.As = x86.ADECL
 				} else {
-					p.As = i386.ADECW
+					p.As = x86.ADECW
 				}
 				p.From = obj.Addr{}
 				break
@@ -228,10 +225,10 @@
 	// the processor can do better if we do moves using both.
 	for r := g.Start; r != nil; r = r.Link {
 		p = r.Prog
-		if p.As == i386.AMOVSD {
+		if p.As == x86.AMOVSD {
 			if regtyp(&p.From) {
 				if regtyp(&p.To) {
-					p.As = i386.AMOVAPD
+					p.As = x86.AMOVAPD
 				}
 			}
 		}
@@ -252,7 +249,7 @@
 }
 
 func regtyp(a *obj.Addr) bool {
-	return a.Type == obj.TYPE_REG && (i386.REG_AX <= a.Reg && a.Reg <= i386.REG_DI || i386.REG_X0 <= a.Reg && a.Reg <= i386.REG_X7)
+	return a.Type == obj.TYPE_REG && (x86.REG_AX <= a.Reg && a.Reg <= x86.REG_DI || x86.REG_X0 <= a.Reg && a.Reg <= x86.REG_X7)
 }
 
 // movb elimination.
@@ -269,21 +266,21 @@
 		p = r.Prog
 		if regtyp(&p.To) {
 			switch p.As {
-			case i386.AINCB,
-				i386.AINCW:
-				p.As = i386.AINCL
+			case x86.AINCB,
+				x86.AINCW:
+				p.As = x86.AINCL
 
-			case i386.ADECB,
-				i386.ADECW:
-				p.As = i386.ADECL
+			case x86.ADECB,
+				x86.ADECW:
+				p.As = x86.ADECL
 
-			case i386.ANEGB,
-				i386.ANEGW:
-				p.As = i386.ANEGL
+			case x86.ANEGB,
+				x86.ANEGW:
+				p.As = x86.ANEGL
 
-			case i386.ANOTB,
-				i386.ANOTW:
-				p.As = i386.ANOTL
+			case x86.ANOTB,
+				x86.ANOTW:
+				p.As = x86.ANOTL
 			}
 
 			if regtyp(&p.From) || p.From.Type == obj.TYPE_CONST {
@@ -292,54 +289,54 @@
 				// we don't switch to 32-bit arithmetic if it can
 				// change how the carry bit is set (and the carry bit is needed).
 				switch p.As {
-				case i386.AMOVB,
-					i386.AMOVW:
-					p.As = i386.AMOVL
+				case x86.AMOVB,
+					x86.AMOVW:
+					p.As = x86.AMOVL
 
-				case i386.AADDB,
-					i386.AADDW:
+				case x86.AADDB,
+					x86.AADDW:
 					if !needc(p.Link) {
-						p.As = i386.AADDL
+						p.As = x86.AADDL
 					}
 
-				case i386.ASUBB,
-					i386.ASUBW:
+				case x86.ASUBB,
+					x86.ASUBW:
 					if !needc(p.Link) {
-						p.As = i386.ASUBL
+						p.As = x86.ASUBL
 					}
 
-				case i386.AMULB,
-					i386.AMULW:
-					p.As = i386.AMULL
+				case x86.AMULB,
+					x86.AMULW:
+					p.As = x86.AMULL
 
-				case i386.AIMULB,
-					i386.AIMULW:
-					p.As = i386.AIMULL
+				case x86.AIMULB,
+					x86.AIMULW:
+					p.As = x86.AIMULL
 
-				case i386.AANDB,
-					i386.AANDW:
-					p.As = i386.AANDL
+				case x86.AANDB,
+					x86.AANDW:
+					p.As = x86.AANDL
 
-				case i386.AORB,
-					i386.AORW:
-					p.As = i386.AORL
+				case x86.AORB,
+					x86.AORW:
+					p.As = x86.AORL
 
-				case i386.AXORB,
-					i386.AXORW:
-					p.As = i386.AXORL
+				case x86.AXORB,
+					x86.AXORW:
+					p.As = x86.AXORL
 
-				case i386.ASHLB,
-					i386.ASHLW:
-					p.As = i386.ASHLL
+				case x86.ASHLB,
+					x86.ASHLW:
+					p.As = x86.ASHLL
 				}
 			} else {
 				// explicit zero extension
 				switch p.As {
-				case i386.AMOVB:
-					p.As = i386.AMOVBLZX
+				case x86.AMOVB:
+					p.As = x86.AMOVBLZX
 
-				case i386.AMOVW:
-					p.As = i386.AMOVWLZX
+				case x86.AMOVW:
+					p.As = x86.AMOVWLZX
 				}
 			}
 		}
@@ -370,9 +367,7 @@
 	if !regtyp(v2) {
 		return false
 	}
-	var info gc.ProgInfo
-	var r *gc.Flow
-	for r = gc.Uniqp(r0); r != nil; r = gc.Uniqp(r) {
+	for r := gc.Uniqp(r0); r != nil; r = gc.Uniqp(r) {
 		if gc.Debug['P'] != 0 && gc.Debug['v'] != 0 {
 			fmt.Printf("\t? %v\n", r.Prog)
 		}
@@ -383,17 +378,40 @@
 		if p.As == obj.AVARDEF || p.As == obj.AVARKILL {
 			continue
 		}
-		proginfo(&info, p)
-		if info.Flags&gc.Call != 0 {
+		if p.Info.Flags&gc.Call != 0 {
 			return false
 		}
 
-		if info.Reguse|info.Regset != 0 {
+		if p.Info.Reguse|p.Info.Regset != 0 {
 			return false
 		}
 
-		if (info.Flags&gc.Move != 0) && (info.Flags&(gc.SizeL|gc.SizeQ|gc.SizeF|gc.SizeD) != 0) && p.To.Type == v1.Type && p.To.Reg == v1.Reg {
-			goto gotit
+		if (p.Info.Flags&gc.Move != 0) && (p.Info.Flags&(gc.SizeL|gc.SizeQ|gc.SizeF|gc.SizeD) != 0) && p.To.Type == v1.Type && p.To.Reg == v1.Reg {
+			copysub(&p.To, v1, v2, 1)
+			if gc.Debug['P'] != 0 {
+				fmt.Printf("gotit: %v->%v\n%v", gc.Ctxt.Dconv(v1), gc.Ctxt.Dconv(v2), r.Prog)
+				if p.From.Type == v2.Type && p.From.Reg == v2.Reg {
+					fmt.Printf(" excise")
+				}
+				fmt.Printf("\n")
+			}
+
+			for r = gc.Uniqs(r); r != r0; r = gc.Uniqs(r) {
+				p = r.Prog
+				copysub(&p.From, v1, v2, 1)
+				copysub(&p.To, v1, v2, 1)
+				if gc.Debug['P'] != 0 {
+					fmt.Printf("%v\n", r.Prog)
+				}
+			}
+
+			t := int(v1.Reg)
+			v1.Reg = v2.Reg
+			v2.Reg = int16(t)
+			if gc.Debug['P'] != 0 {
+				fmt.Printf("%v last\n", r.Prog)
+			}
+			return true
 		}
 
 		if copyau(&p.From, v2) || copyau(&p.To, v2) {
@@ -405,33 +423,6 @@
 	}
 
 	return false
-
-gotit:
-	copysub(&p.To, v1, v2, 1)
-	if gc.Debug['P'] != 0 {
-		fmt.Printf("gotit: %v->%v\n%v", gc.Ctxt.Dconv(v1), gc.Ctxt.Dconv(v2), r.Prog)
-		if p.From.Type == v2.Type && p.From.Reg == v2.Reg {
-			fmt.Printf(" excise")
-		}
-		fmt.Printf("\n")
-	}
-
-	for r = gc.Uniqs(r); r != r0; r = gc.Uniqs(r) {
-		p = r.Prog
-		copysub(&p.From, v1, v2, 1)
-		copysub(&p.To, v1, v2, 1)
-		if gc.Debug['P'] != 0 {
-			fmt.Printf("%v\n", r.Prog)
-		}
-	}
-
-	t := int(v1.Reg)
-	v1.Reg = v2.Reg
-	v2.Reg = int16(t)
-	if gc.Debug['P'] != 0 {
-		fmt.Printf("%v last\n", r.Prog)
-	}
-	return true
 }
 
 /*
@@ -585,7 +576,7 @@
 		if REGEXT != 0 /*TypeKind(100016)*/ && v.Type == obj.TYPE_REG && v.Reg <= REGEXT && v.Reg > exregoffset {
 			return 2
 		}
-		if i386.REGARG >= 0 && v.Type == obj.TYPE_REG && v.Reg == i386.REGARG {
+		if x86.REGARG >= 0 && v.Type == obj.TYPE_REG && v.Reg == x86.REGARG {
 			return 2
 		}
 		if v.Type == p.From.Type && v.Reg == p.From.Reg {
@@ -605,7 +596,7 @@
 		return 3
 
 	case obj.ATEXT:
-		if i386.REGARG >= 0 && v.Type == obj.TYPE_REG && v.Reg == i386.REGARG {
+		if x86.REGARG >= 0 && v.Type == obj.TYPE_REG && v.Reg == x86.REGARG {
 			return 3
 		}
 		return 0
@@ -614,26 +605,24 @@
 	if p.As == obj.AVARDEF || p.As == obj.AVARKILL {
 		return 0
 	}
-	var info gc.ProgInfo
-	proginfo(&info, p)
 
-	if (info.Reguse|info.Regset)&RtoB(int(v.Reg)) != 0 {
+	if (p.Info.Reguse|p.Info.Regset)&RtoB(int(v.Reg)) != 0 {
 		return 2
 	}
 
-	if info.Flags&gc.LeftAddr != 0 {
+	if p.Info.Flags&gc.LeftAddr != 0 {
 		if copyas(&p.From, v) {
 			return 2
 		}
 	}
 
-	if info.Flags&(gc.RightRead|gc.RightWrite) == gc.RightRead|gc.RightWrite {
+	if p.Info.Flags&(gc.RightRead|gc.RightWrite) == gc.RightRead|gc.RightWrite {
 		if copyas(&p.To, v) {
 			return 2
 		}
 	}
 
-	if info.Flags&gc.RightWrite != 0 {
+	if p.Info.Flags&gc.RightWrite != 0 {
 		if copyas(&p.To, v) {
 			if s != nil {
 				return copysub(&p.From, v, s, 1)
@@ -645,7 +634,7 @@
 		}
 	}
 
-	if info.Flags&(gc.LeftAddr|gc.LeftRead|gc.LeftWrite|gc.RightAddr|gc.RightRead|gc.RightWrite) != 0 {
+	if p.Info.Flags&(gc.LeftAddr|gc.LeftRead|gc.LeftWrite|gc.RightAddr|gc.RightRead|gc.RightWrite) != 0 {
 		if s != nil {
 			if copysub(&p.From, v, s, 1) != 0 {
 				return 1
@@ -670,10 +659,10 @@
  * semantics
  */
 func copyas(a *obj.Addr, v *obj.Addr) bool {
-	if i386.REG_AL <= a.Reg && a.Reg <= i386.REG_BL {
+	if x86.REG_AL <= a.Reg && a.Reg <= x86.REG_BL {
 		gc.Fatal("use of byte register")
 	}
-	if i386.REG_AL <= v.Reg && v.Reg <= i386.REG_BL {
+	if x86.REG_AL <= v.Reg && v.Reg <= x86.REG_BL {
 		gc.Fatal("use of byte register")
 	}
 
@@ -683,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
 		}
@@ -698,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
 		}
@@ -714,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 +721,7 @@
 func copysub(a *obj.Addr, v *obj.Addr, s *obj.Addr, f int) int {
 	if copyas(a, v) {
 		reg := int(s.Reg)
-		if reg >= i386.REG_AX && reg <= i386.REG_DI || reg >= i386.REG_X0 && reg <= i386.REG_X7 {
+		if reg >= x86.REG_AX && reg <= x86.REG_DI || reg >= x86.REG_X0 && reg <= x86.REG_X7 {
 			if f != 0 {
 				a.Reg = int16(reg)
 			}
@@ -743,8 +732,8 @@
 
 	if regtyp(v) {
 		reg := int(v.Reg)
-		if a.Type == obj.TYPE_MEM && int(a.Reg) == reg {
-			if (s.Reg == i386.REG_BP) && a.Index != obj.TYPE_NONE {
+		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 */
 			}
 			if f != 0 {
@@ -801,7 +790,7 @@
 					if p.From.Node == p0.From.Node {
 						if p.From.Offset == p0.From.Offset {
 							if p.From.Scale == p0.From.Scale {
-								if p.From.Type == obj.TYPE_FCONST && p.From.U.Dval == p0.From.U.Dval {
+								if p.From.Type == obj.TYPE_FCONST && p.From.Val.(float64) == p0.From.Val.(float64) {
 									if p.From.Index == p0.From.Index {
 										excise(r)
 										goto loop
@@ -817,9 +806,9 @@
 }
 
 func smallindir(a *obj.Addr, reg *obj.Addr) bool {
-	return regtyp(reg) && a.Type == obj.TYPE_MEM && a.Reg == reg.Reg && a.Index == i386.REG_NONE && 0 <= a.Offset && a.Offset < 4096
+	return regtyp(reg) && a.Type == obj.TYPE_MEM && a.Reg == reg.Reg && a.Index == x86.REG_NONE && 0 <= a.Offset && a.Offset < 4096
 }
 
 func stackaddr(a *obj.Addr) bool {
-	return a.Type == obj.TYPE_REG && a.Reg == i386.REG_SP
+	return a.Type == obj.TYPE_REG && a.Reg == x86.REG_SP
 }
diff --git a/src/cmd/8g/prog.go b/src/cmd/8g/prog.go
index d8e46e5..1346c20 100644
--- a/src/cmd/8g/prog.go
+++ b/src/cmd/8g/prog.go
@@ -5,18 +5,18 @@
 package main
 
 import (
+	"cmd/internal/gc"
 	"cmd/internal/obj"
-	"cmd/internal/obj/i386"
+	"cmd/internal/obj/x86"
 )
-import "cmd/internal/gc"
 
 var (
-	AX               = RtoB(i386.REG_AX)
-	BX               = RtoB(i386.REG_BX)
-	CX               = RtoB(i386.REG_CX)
-	DX               = RtoB(i386.REG_DX)
-	DI               = RtoB(i386.REG_DI)
-	SI               = RtoB(i386.REG_SI)
+	AX               = RtoB(x86.REG_AX)
+	BX               = RtoB(x86.REG_BX)
+	CX               = RtoB(x86.REG_CX)
+	DX               = RtoB(x86.REG_DX)
+	DI               = RtoB(x86.REG_DI)
+	SI               = RtoB(x86.REG_SI)
 	LeftRdwr  uint32 = gc.LeftRead | gc.LeftWrite
 	RightRdwr uint32 = gc.RightRead | gc.RightWrite
 )
@@ -30,233 +30,234 @@
 // size variants of an operation even if we just use a subset.
 //
 // The table is formatted for 8-space tabs.
-var progtable = [i386.ALAST]gc.ProgInfo{
-	obj.ATYPE:     gc.ProgInfo{gc.Pseudo | gc.Skip, 0, 0, 0},
-	obj.ATEXT:     gc.ProgInfo{gc.Pseudo, 0, 0, 0},
-	obj.AFUNCDATA: gc.ProgInfo{gc.Pseudo, 0, 0, 0},
-	obj.APCDATA:   gc.ProgInfo{gc.Pseudo, 0, 0, 0},
-	obj.AUNDEF:    gc.ProgInfo{gc.Break, 0, 0, 0},
-	obj.AUSEFIELD: gc.ProgInfo{gc.OK, 0, 0, 0},
-	obj.ACHECKNIL: gc.ProgInfo{gc.LeftRead, 0, 0, 0},
-	obj.AVARDEF:   gc.ProgInfo{gc.Pseudo | gc.RightWrite, 0, 0, 0},
-	obj.AVARKILL:  gc.ProgInfo{gc.Pseudo | gc.RightWrite, 0, 0, 0},
+var progtable = [x86.ALAST]obj.ProgInfo{
+	obj.ATYPE:     {gc.Pseudo | gc.Skip, 0, 0, 0},
+	obj.ATEXT:     {gc.Pseudo, 0, 0, 0},
+	obj.AFUNCDATA: {gc.Pseudo, 0, 0, 0},
+	obj.APCDATA:   {gc.Pseudo, 0, 0, 0},
+	obj.AUNDEF:    {gc.Break, 0, 0, 0},
+	obj.AUSEFIELD: {gc.OK, 0, 0, 0},
+	obj.ACHECKNIL: {gc.LeftRead, 0, 0, 0},
+	obj.AVARDEF:   {gc.Pseudo | gc.RightWrite, 0, 0, 0},
+	obj.AVARKILL:  {gc.Pseudo | gc.RightWrite, 0, 0, 0},
 
 	// NOP is an internal no-op that also stands
 	// for USED and SET annotations, not the Intel opcode.
-	obj.ANOP:        gc.ProgInfo{gc.LeftRead | gc.RightWrite, 0, 0, 0},
-	i386.AADCL:      gc.ProgInfo{gc.SizeL | gc.LeftRead | RightRdwr | gc.SetCarry | gc.UseCarry, 0, 0, 0},
-	i386.AADCW:      gc.ProgInfo{gc.SizeW | gc.LeftRead | RightRdwr | gc.SetCarry | gc.UseCarry, 0, 0, 0},
-	i386.AADDB:      gc.ProgInfo{gc.SizeB | gc.LeftRead | RightRdwr | gc.SetCarry, 0, 0, 0},
-	i386.AADDL:      gc.ProgInfo{gc.SizeL | gc.LeftRead | RightRdwr | gc.SetCarry, 0, 0, 0},
-	i386.AADDW:      gc.ProgInfo{gc.SizeW | gc.LeftRead | RightRdwr | gc.SetCarry, 0, 0, 0},
-	i386.AADDSD:     gc.ProgInfo{gc.SizeD | gc.LeftRead | RightRdwr, 0, 0, 0},
-	i386.AADDSS:     gc.ProgInfo{gc.SizeF | gc.LeftRead | RightRdwr, 0, 0, 0},
-	i386.AANDB:      gc.ProgInfo{gc.SizeB | gc.LeftRead | RightRdwr | gc.SetCarry, 0, 0, 0},
-	i386.AANDL:      gc.ProgInfo{gc.SizeL | gc.LeftRead | RightRdwr | gc.SetCarry, 0, 0, 0},
-	i386.AANDW:      gc.ProgInfo{gc.SizeW | gc.LeftRead | RightRdwr | gc.SetCarry, 0, 0, 0},
-	obj.ACALL:       gc.ProgInfo{gc.RightAddr | gc.Call | gc.KillCarry, 0, 0, 0},
-	i386.ACDQ:       gc.ProgInfo{gc.OK, AX, AX | DX, 0},
-	i386.ACWD:       gc.ProgInfo{gc.OK, AX, AX | DX, 0},
-	i386.ACLD:       gc.ProgInfo{gc.OK, 0, 0, 0},
-	i386.ASTD:       gc.ProgInfo{gc.OK, 0, 0, 0},
-	i386.ACMPB:      gc.ProgInfo{gc.SizeB | gc.LeftRead | gc.RightRead | gc.SetCarry, 0, 0, 0},
-	i386.ACMPL:      gc.ProgInfo{gc.SizeL | gc.LeftRead | gc.RightRead | gc.SetCarry, 0, 0, 0},
-	i386.ACMPW:      gc.ProgInfo{gc.SizeW | gc.LeftRead | gc.RightRead | gc.SetCarry, 0, 0, 0},
-	i386.ACOMISD:    gc.ProgInfo{gc.SizeD | gc.LeftRead | gc.RightRead | gc.SetCarry, 0, 0, 0},
-	i386.ACOMISS:    gc.ProgInfo{gc.SizeF | gc.LeftRead | gc.RightRead | gc.SetCarry, 0, 0, 0},
-	i386.ACVTSD2SL:  gc.ProgInfo{gc.SizeL | gc.LeftRead | gc.RightWrite | gc.Conv, 0, 0, 0},
-	i386.ACVTSD2SS:  gc.ProgInfo{gc.SizeF | gc.LeftRead | gc.RightWrite | gc.Conv, 0, 0, 0},
-	i386.ACVTSL2SD:  gc.ProgInfo{gc.SizeD | gc.LeftRead | gc.RightWrite | gc.Conv, 0, 0, 0},
-	i386.ACVTSL2SS:  gc.ProgInfo{gc.SizeF | gc.LeftRead | gc.RightWrite | gc.Conv, 0, 0, 0},
-	i386.ACVTSS2SD:  gc.ProgInfo{gc.SizeD | gc.LeftRead | gc.RightWrite | gc.Conv, 0, 0, 0},
-	i386.ACVTSS2SL:  gc.ProgInfo{gc.SizeL | gc.LeftRead | gc.RightWrite | gc.Conv, 0, 0, 0},
-	i386.ACVTTSD2SL: gc.ProgInfo{gc.SizeL | gc.LeftRead | gc.RightWrite | gc.Conv, 0, 0, 0},
-	i386.ACVTTSS2SL: gc.ProgInfo{gc.SizeL | gc.LeftRead | gc.RightWrite | gc.Conv, 0, 0, 0},
-	i386.ADECB:      gc.ProgInfo{gc.SizeB | RightRdwr, 0, 0, 0},
-	i386.ADECL:      gc.ProgInfo{gc.SizeL | RightRdwr, 0, 0, 0},
-	i386.ADECW:      gc.ProgInfo{gc.SizeW | RightRdwr, 0, 0, 0},
-	i386.ADIVB:      gc.ProgInfo{gc.SizeB | gc.LeftRead | gc.SetCarry, AX, AX, 0},
-	i386.ADIVL:      gc.ProgInfo{gc.SizeL | gc.LeftRead | gc.SetCarry, AX | DX, AX | DX, 0},
-	i386.ADIVW:      gc.ProgInfo{gc.SizeW | gc.LeftRead | gc.SetCarry, AX | DX, AX | DX, 0},
-	i386.ADIVSD:     gc.ProgInfo{gc.SizeD | gc.LeftRead | RightRdwr, 0, 0, 0},
-	i386.ADIVSS:     gc.ProgInfo{gc.SizeF | gc.LeftRead | RightRdwr, 0, 0, 0},
-	i386.AFLDCW:     gc.ProgInfo{gc.SizeW | gc.LeftAddr, 0, 0, 0},
-	i386.AFSTCW:     gc.ProgInfo{gc.SizeW | gc.RightAddr, 0, 0, 0},
-	i386.AFSTSW:     gc.ProgInfo{gc.SizeW | gc.RightAddr | gc.RightWrite, 0, 0, 0},
-	i386.AFADDD:     gc.ProgInfo{gc.SizeD | gc.LeftAddr | RightRdwr, 0, 0, 0},
-	i386.AFADDDP:    gc.ProgInfo{gc.SizeD | gc.LeftAddr | RightRdwr, 0, 0, 0},
-	i386.AFADDF:     gc.ProgInfo{gc.SizeF | gc.LeftAddr | RightRdwr, 0, 0, 0},
-	i386.AFCOMD:     gc.ProgInfo{gc.SizeD | gc.LeftAddr | gc.RightRead, 0, 0, 0},
-	i386.AFCOMDP:    gc.ProgInfo{gc.SizeD | gc.LeftAddr | gc.RightRead, 0, 0, 0},
-	i386.AFCOMDPP:   gc.ProgInfo{gc.SizeD | gc.LeftAddr | gc.RightRead, 0, 0, 0},
-	i386.AFCOMF:     gc.ProgInfo{gc.SizeF | gc.LeftAddr | gc.RightRead, 0, 0, 0},
-	i386.AFCOMFP:    gc.ProgInfo{gc.SizeF | gc.LeftAddr | gc.RightRead, 0, 0, 0},
-	i386.AFUCOMIP:   gc.ProgInfo{gc.SizeF | gc.LeftAddr | gc.RightRead, 0, 0, 0},
-	i386.AFCHS:      gc.ProgInfo{gc.SizeD | RightRdwr, 0, 0, 0}, // also SizeF
+	obj.ANOP:       {gc.LeftRead | gc.RightWrite, 0, 0, 0},
+	x86.AADCL:      {gc.SizeL | gc.LeftRead | RightRdwr | gc.SetCarry | gc.UseCarry, 0, 0, 0},
+	x86.AADCW:      {gc.SizeW | gc.LeftRead | RightRdwr | gc.SetCarry | gc.UseCarry, 0, 0, 0},
+	x86.AADDB:      {gc.SizeB | gc.LeftRead | RightRdwr | gc.SetCarry, 0, 0, 0},
+	x86.AADDL:      {gc.SizeL | gc.LeftRead | RightRdwr | gc.SetCarry, 0, 0, 0},
+	x86.AADDW:      {gc.SizeW | gc.LeftRead | RightRdwr | gc.SetCarry, 0, 0, 0},
+	x86.AADDSD:     {gc.SizeD | gc.LeftRead | RightRdwr, 0, 0, 0},
+	x86.AADDSS:     {gc.SizeF | gc.LeftRead | RightRdwr, 0, 0, 0},
+	x86.AANDB:      {gc.SizeB | gc.LeftRead | RightRdwr | gc.SetCarry, 0, 0, 0},
+	x86.AANDL:      {gc.SizeL | gc.LeftRead | RightRdwr | gc.SetCarry, 0, 0, 0},
+	x86.AANDW:      {gc.SizeW | gc.LeftRead | RightRdwr | gc.SetCarry, 0, 0, 0},
+	obj.ACALL:      {gc.RightAddr | gc.Call | gc.KillCarry, 0, 0, 0},
+	x86.ACDQ:       {gc.OK, AX, AX | DX, 0},
+	x86.ACWD:       {gc.OK, AX, AX | DX, 0},
+	x86.ACLD:       {gc.OK, 0, 0, 0},
+	x86.ASTD:       {gc.OK, 0, 0, 0},
+	x86.ACMPB:      {gc.SizeB | gc.LeftRead | gc.RightRead | gc.SetCarry, 0, 0, 0},
+	x86.ACMPL:      {gc.SizeL | gc.LeftRead | gc.RightRead | gc.SetCarry, 0, 0, 0},
+	x86.ACMPW:      {gc.SizeW | gc.LeftRead | gc.RightRead | gc.SetCarry, 0, 0, 0},
+	x86.ACOMISD:    {gc.SizeD | gc.LeftRead | gc.RightRead | gc.SetCarry, 0, 0, 0},
+	x86.ACOMISS:    {gc.SizeF | gc.LeftRead | gc.RightRead | gc.SetCarry, 0, 0, 0},
+	x86.ACVTSD2SL:  {gc.SizeL | gc.LeftRead | gc.RightWrite | gc.Conv, 0, 0, 0},
+	x86.ACVTSD2SS:  {gc.SizeF | gc.LeftRead | gc.RightWrite | gc.Conv, 0, 0, 0},
+	x86.ACVTSL2SD:  {gc.SizeD | gc.LeftRead | gc.RightWrite | gc.Conv, 0, 0, 0},
+	x86.ACVTSL2SS:  {gc.SizeF | gc.LeftRead | gc.RightWrite | gc.Conv, 0, 0, 0},
+	x86.ACVTSS2SD:  {gc.SizeD | gc.LeftRead | gc.RightWrite | gc.Conv, 0, 0, 0},
+	x86.ACVTSS2SL:  {gc.SizeL | gc.LeftRead | gc.RightWrite | gc.Conv, 0, 0, 0},
+	x86.ACVTTSD2SL: {gc.SizeL | gc.LeftRead | gc.RightWrite | gc.Conv, 0, 0, 0},
+	x86.ACVTTSS2SL: {gc.SizeL | gc.LeftRead | gc.RightWrite | gc.Conv, 0, 0, 0},
+	x86.ADECB:      {gc.SizeB | RightRdwr, 0, 0, 0},
+	x86.ADECL:      {gc.SizeL | RightRdwr, 0, 0, 0},
+	x86.ADECW:      {gc.SizeW | RightRdwr, 0, 0, 0},
+	x86.ADIVB:      {gc.SizeB | gc.LeftRead | gc.SetCarry, AX, AX, 0},
+	x86.ADIVL:      {gc.SizeL | gc.LeftRead | gc.SetCarry, AX | DX, AX | DX, 0},
+	x86.ADIVW:      {gc.SizeW | gc.LeftRead | gc.SetCarry, AX | DX, AX | DX, 0},
+	x86.ADIVSD:     {gc.SizeD | gc.LeftRead | RightRdwr, 0, 0, 0},
+	x86.ADIVSS:     {gc.SizeF | gc.LeftRead | RightRdwr, 0, 0, 0},
+	x86.AFLDCW:     {gc.SizeW | gc.LeftAddr, 0, 0, 0},
+	x86.AFSTCW:     {gc.SizeW | gc.RightAddr, 0, 0, 0},
+	x86.AFSTSW:     {gc.SizeW | gc.RightAddr | gc.RightWrite, 0, 0, 0},
+	x86.AFADDD:     {gc.SizeD | gc.LeftAddr | RightRdwr, 0, 0, 0},
+	x86.AFADDDP:    {gc.SizeD | gc.LeftAddr | RightRdwr, 0, 0, 0},
+	x86.AFADDF:     {gc.SizeF | gc.LeftAddr | RightRdwr, 0, 0, 0},
+	x86.AFCOMD:     {gc.SizeD | gc.LeftAddr | gc.RightRead, 0, 0, 0},
+	x86.AFCOMDP:    {gc.SizeD | gc.LeftAddr | gc.RightRead, 0, 0, 0},
+	x86.AFCOMDPP:   {gc.SizeD | gc.LeftAddr | gc.RightRead, 0, 0, 0},
+	x86.AFCOMF:     {gc.SizeF | gc.LeftAddr | gc.RightRead, 0, 0, 0},
+	x86.AFCOMFP:    {gc.SizeF | gc.LeftAddr | gc.RightRead, 0, 0, 0},
+	x86.AFUCOMIP:   {gc.SizeF | gc.LeftAddr | gc.RightRead, 0, 0, 0},
+	x86.AFCHS:      {gc.SizeD | RightRdwr, 0, 0, 0}, // also SizeF
 
-	i386.AFDIVDP:  gc.ProgInfo{gc.SizeD | gc.LeftAddr | RightRdwr, 0, 0, 0},
-	i386.AFDIVF:   gc.ProgInfo{gc.SizeF | gc.LeftAddr | RightRdwr, 0, 0, 0},
-	i386.AFDIVD:   gc.ProgInfo{gc.SizeD | gc.LeftAddr | RightRdwr, 0, 0, 0},
-	i386.AFDIVRDP: gc.ProgInfo{gc.SizeD | gc.LeftAddr | RightRdwr, 0, 0, 0},
-	i386.AFDIVRF:  gc.ProgInfo{gc.SizeF | gc.LeftAddr | RightRdwr, 0, 0, 0},
-	i386.AFDIVRD:  gc.ProgInfo{gc.SizeD | gc.LeftAddr | RightRdwr, 0, 0, 0},
-	i386.AFXCHD:   gc.ProgInfo{gc.SizeD | LeftRdwr | RightRdwr, 0, 0, 0},
-	i386.AFSUBD:   gc.ProgInfo{gc.SizeD | gc.LeftAddr | RightRdwr, 0, 0, 0},
-	i386.AFSUBDP:  gc.ProgInfo{gc.SizeD | gc.LeftAddr | RightRdwr, 0, 0, 0},
-	i386.AFSUBF:   gc.ProgInfo{gc.SizeF | gc.LeftAddr | RightRdwr, 0, 0, 0},
-	i386.AFSUBRD:  gc.ProgInfo{gc.SizeD | gc.LeftAddr | RightRdwr, 0, 0, 0},
-	i386.AFSUBRDP: gc.ProgInfo{gc.SizeD | gc.LeftAddr | RightRdwr, 0, 0, 0},
-	i386.AFSUBRF:  gc.ProgInfo{gc.SizeF | gc.LeftAddr | RightRdwr, 0, 0, 0},
-	i386.AFMOVD:   gc.ProgInfo{gc.SizeD | gc.LeftAddr | gc.RightWrite, 0, 0, 0},
-	i386.AFMOVF:   gc.ProgInfo{gc.SizeF | gc.LeftAddr | gc.RightWrite, 0, 0, 0},
-	i386.AFMOVL:   gc.ProgInfo{gc.SizeL | gc.LeftAddr | gc.RightWrite, 0, 0, 0},
-	i386.AFMOVW:   gc.ProgInfo{gc.SizeW | gc.LeftAddr | gc.RightWrite, 0, 0, 0},
-	i386.AFMOVV:   gc.ProgInfo{gc.SizeQ | gc.LeftAddr | gc.RightWrite, 0, 0, 0},
+	x86.AFDIVDP:  {gc.SizeD | gc.LeftAddr | RightRdwr, 0, 0, 0},
+	x86.AFDIVF:   {gc.SizeF | gc.LeftAddr | RightRdwr, 0, 0, 0},
+	x86.AFDIVD:   {gc.SizeD | gc.LeftAddr | RightRdwr, 0, 0, 0},
+	x86.AFDIVRDP: {gc.SizeD | gc.LeftAddr | RightRdwr, 0, 0, 0},
+	x86.AFDIVRF:  {gc.SizeF | gc.LeftAddr | RightRdwr, 0, 0, 0},
+	x86.AFDIVRD:  {gc.SizeD | gc.LeftAddr | RightRdwr, 0, 0, 0},
+	x86.AFXCHD:   {gc.SizeD | LeftRdwr | RightRdwr, 0, 0, 0},
+	x86.AFSUBD:   {gc.SizeD | gc.LeftAddr | RightRdwr, 0, 0, 0},
+	x86.AFSUBDP:  {gc.SizeD | gc.LeftAddr | RightRdwr, 0, 0, 0},
+	x86.AFSUBF:   {gc.SizeF | gc.LeftAddr | RightRdwr, 0, 0, 0},
+	x86.AFSUBRD:  {gc.SizeD | gc.LeftAddr | RightRdwr, 0, 0, 0},
+	x86.AFSUBRDP: {gc.SizeD | gc.LeftAddr | RightRdwr, 0, 0, 0},
+	x86.AFSUBRF:  {gc.SizeF | gc.LeftAddr | RightRdwr, 0, 0, 0},
+	x86.AFMOVD:   {gc.SizeD | gc.LeftAddr | gc.RightWrite, 0, 0, 0},
+	x86.AFMOVF:   {gc.SizeF | gc.LeftAddr | gc.RightWrite, 0, 0, 0},
+	x86.AFMOVL:   {gc.SizeL | gc.LeftAddr | gc.RightWrite, 0, 0, 0},
+	x86.AFMOVW:   {gc.SizeW | gc.LeftAddr | gc.RightWrite, 0, 0, 0},
+	x86.AFMOVV:   {gc.SizeQ | gc.LeftAddr | gc.RightWrite, 0, 0, 0},
 
 	// These instructions are marked as RightAddr
 	// so that the register optimizer does not try to replace the
 	// memory references with integer register references.
 	// But they do not use the previous value at the address, so
 	// we also mark them RightWrite.
-	i386.AFMOVDP:  gc.ProgInfo{gc.SizeD | gc.LeftRead | gc.RightWrite | gc.RightAddr, 0, 0, 0},
-	i386.AFMOVFP:  gc.ProgInfo{gc.SizeF | gc.LeftRead | gc.RightWrite | gc.RightAddr, 0, 0, 0},
-	i386.AFMOVLP:  gc.ProgInfo{gc.SizeL | gc.LeftRead | gc.RightWrite | gc.RightAddr, 0, 0, 0},
-	i386.AFMOVWP:  gc.ProgInfo{gc.SizeW | gc.LeftRead | gc.RightWrite | gc.RightAddr, 0, 0, 0},
-	i386.AFMOVVP:  gc.ProgInfo{gc.SizeQ | gc.LeftRead | gc.RightWrite | gc.RightAddr, 0, 0, 0},
-	i386.AFMULD:   gc.ProgInfo{gc.SizeD | gc.LeftAddr | RightRdwr, 0, 0, 0},
-	i386.AFMULDP:  gc.ProgInfo{gc.SizeD | gc.LeftAddr | RightRdwr, 0, 0, 0},
-	i386.AFMULF:   gc.ProgInfo{gc.SizeF | gc.LeftAddr | RightRdwr, 0, 0, 0},
-	i386.AIDIVB:   gc.ProgInfo{gc.SizeB | gc.LeftRead | gc.SetCarry, AX, AX, 0},
-	i386.AIDIVL:   gc.ProgInfo{gc.SizeL | gc.LeftRead | gc.SetCarry, AX | DX, AX | DX, 0},
-	i386.AIDIVW:   gc.ProgInfo{gc.SizeW | gc.LeftRead | gc.SetCarry, AX | DX, AX | DX, 0},
-	i386.AIMULB:   gc.ProgInfo{gc.SizeB | gc.LeftRead | gc.SetCarry, AX, AX, 0},
-	i386.AIMULL:   gc.ProgInfo{gc.SizeL | gc.LeftRead | gc.ImulAXDX | gc.SetCarry, 0, 0, 0},
-	i386.AIMULW:   gc.ProgInfo{gc.SizeW | gc.LeftRead | gc.ImulAXDX | gc.SetCarry, 0, 0, 0},
-	i386.AINCB:    gc.ProgInfo{gc.SizeB | RightRdwr, 0, 0, 0},
-	i386.AINCL:    gc.ProgInfo{gc.SizeL | RightRdwr, 0, 0, 0},
-	i386.AINCW:    gc.ProgInfo{gc.SizeW | RightRdwr, 0, 0, 0},
-	i386.AJCC:     gc.ProgInfo{gc.Cjmp | gc.UseCarry, 0, 0, 0},
-	i386.AJCS:     gc.ProgInfo{gc.Cjmp | gc.UseCarry, 0, 0, 0},
-	i386.AJEQ:     gc.ProgInfo{gc.Cjmp | gc.UseCarry, 0, 0, 0},
-	i386.AJGE:     gc.ProgInfo{gc.Cjmp | gc.UseCarry, 0, 0, 0},
-	i386.AJGT:     gc.ProgInfo{gc.Cjmp | gc.UseCarry, 0, 0, 0},
-	i386.AJHI:     gc.ProgInfo{gc.Cjmp | gc.UseCarry, 0, 0, 0},
-	i386.AJLE:     gc.ProgInfo{gc.Cjmp | gc.UseCarry, 0, 0, 0},
-	i386.AJLS:     gc.ProgInfo{gc.Cjmp | gc.UseCarry, 0, 0, 0},
-	i386.AJLT:     gc.ProgInfo{gc.Cjmp | gc.UseCarry, 0, 0, 0},
-	i386.AJMI:     gc.ProgInfo{gc.Cjmp | gc.UseCarry, 0, 0, 0},
-	i386.AJNE:     gc.ProgInfo{gc.Cjmp | gc.UseCarry, 0, 0, 0},
-	i386.AJOC:     gc.ProgInfo{gc.Cjmp | gc.UseCarry, 0, 0, 0},
-	i386.AJOS:     gc.ProgInfo{gc.Cjmp | gc.UseCarry, 0, 0, 0},
-	i386.AJPC:     gc.ProgInfo{gc.Cjmp | gc.UseCarry, 0, 0, 0},
-	i386.AJPL:     gc.ProgInfo{gc.Cjmp | gc.UseCarry, 0, 0, 0},
-	i386.AJPS:     gc.ProgInfo{gc.Cjmp | gc.UseCarry, 0, 0, 0},
-	obj.AJMP:      gc.ProgInfo{gc.Jump | gc.Break | gc.KillCarry, 0, 0, 0},
-	i386.ALEAL:    gc.ProgInfo{gc.LeftAddr | gc.RightWrite, 0, 0, 0},
-	i386.AMOVBLSX: gc.ProgInfo{gc.SizeL | gc.LeftRead | gc.RightWrite | gc.Conv, 0, 0, 0},
-	i386.AMOVBLZX: gc.ProgInfo{gc.SizeL | gc.LeftRead | gc.RightWrite | gc.Conv, 0, 0, 0},
-	i386.AMOVBWSX: gc.ProgInfo{gc.SizeW | gc.LeftRead | gc.RightWrite | gc.Conv, 0, 0, 0},
-	i386.AMOVBWZX: gc.ProgInfo{gc.SizeW | gc.LeftRead | gc.RightWrite | gc.Conv, 0, 0, 0},
-	i386.AMOVWLSX: gc.ProgInfo{gc.SizeL | gc.LeftRead | gc.RightWrite | gc.Conv, 0, 0, 0},
-	i386.AMOVWLZX: gc.ProgInfo{gc.SizeL | gc.LeftRead | gc.RightWrite | gc.Conv, 0, 0, 0},
-	i386.AMOVB:    gc.ProgInfo{gc.SizeB | gc.LeftRead | gc.RightWrite | gc.Move, 0, 0, 0},
-	i386.AMOVL:    gc.ProgInfo{gc.SizeL | gc.LeftRead | gc.RightWrite | gc.Move, 0, 0, 0},
-	i386.AMOVW:    gc.ProgInfo{gc.SizeW | gc.LeftRead | gc.RightWrite | gc.Move, 0, 0, 0},
-	i386.AMOVSB:   gc.ProgInfo{gc.OK, DI | SI, DI | SI, 0},
-	i386.AMOVSL:   gc.ProgInfo{gc.OK, DI | SI, DI | SI, 0},
-	i386.AMOVSW:   gc.ProgInfo{gc.OK, DI | SI, DI | SI, 0},
-	obj.ADUFFCOPY: gc.ProgInfo{gc.OK, DI | SI, DI | SI | CX, 0},
-	i386.AMOVSD:   gc.ProgInfo{gc.SizeD | gc.LeftRead | gc.RightWrite | gc.Move, 0, 0, 0},
-	i386.AMOVSS:   gc.ProgInfo{gc.SizeF | gc.LeftRead | gc.RightWrite | gc.Move, 0, 0, 0},
+	x86.AFMOVDP:   {gc.SizeD | gc.LeftRead | gc.RightWrite | gc.RightAddr, 0, 0, 0},
+	x86.AFMOVFP:   {gc.SizeF | gc.LeftRead | gc.RightWrite | gc.RightAddr, 0, 0, 0},
+	x86.AFMOVLP:   {gc.SizeL | gc.LeftRead | gc.RightWrite | gc.RightAddr, 0, 0, 0},
+	x86.AFMOVWP:   {gc.SizeW | gc.LeftRead | gc.RightWrite | gc.RightAddr, 0, 0, 0},
+	x86.AFMOVVP:   {gc.SizeQ | gc.LeftRead | gc.RightWrite | gc.RightAddr, 0, 0, 0},
+	x86.AFMULD:    {gc.SizeD | gc.LeftAddr | RightRdwr, 0, 0, 0},
+	x86.AFMULDP:   {gc.SizeD | gc.LeftAddr | RightRdwr, 0, 0, 0},
+	x86.AFMULF:    {gc.SizeF | gc.LeftAddr | RightRdwr, 0, 0, 0},
+	x86.AIDIVB:    {gc.SizeB | gc.LeftRead | gc.SetCarry, AX, AX, 0},
+	x86.AIDIVL:    {gc.SizeL | gc.LeftRead | gc.SetCarry, AX | DX, AX | DX, 0},
+	x86.AIDIVW:    {gc.SizeW | gc.LeftRead | gc.SetCarry, AX | DX, AX | DX, 0},
+	x86.AIMULB:    {gc.SizeB | gc.LeftRead | gc.SetCarry, AX, AX, 0},
+	x86.AIMULL:    {gc.SizeL | gc.LeftRead | gc.ImulAXDX | gc.SetCarry, 0, 0, 0},
+	x86.AIMULW:    {gc.SizeW | gc.LeftRead | gc.ImulAXDX | gc.SetCarry, 0, 0, 0},
+	x86.AINCB:     {gc.SizeB | RightRdwr, 0, 0, 0},
+	x86.AINCL:     {gc.SizeL | RightRdwr, 0, 0, 0},
+	x86.AINCW:     {gc.SizeW | RightRdwr, 0, 0, 0},
+	x86.AJCC:      {gc.Cjmp | gc.UseCarry, 0, 0, 0},
+	x86.AJCS:      {gc.Cjmp | gc.UseCarry, 0, 0, 0},
+	x86.AJEQ:      {gc.Cjmp | gc.UseCarry, 0, 0, 0},
+	x86.AJGE:      {gc.Cjmp | gc.UseCarry, 0, 0, 0},
+	x86.AJGT:      {gc.Cjmp | gc.UseCarry, 0, 0, 0},
+	x86.AJHI:      {gc.Cjmp | gc.UseCarry, 0, 0, 0},
+	x86.AJLE:      {gc.Cjmp | gc.UseCarry, 0, 0, 0},
+	x86.AJLS:      {gc.Cjmp | gc.UseCarry, 0, 0, 0},
+	x86.AJLT:      {gc.Cjmp | gc.UseCarry, 0, 0, 0},
+	x86.AJMI:      {gc.Cjmp | gc.UseCarry, 0, 0, 0},
+	x86.AJNE:      {gc.Cjmp | gc.UseCarry, 0, 0, 0},
+	x86.AJOC:      {gc.Cjmp | gc.UseCarry, 0, 0, 0},
+	x86.AJOS:      {gc.Cjmp | gc.UseCarry, 0, 0, 0},
+	x86.AJPC:      {gc.Cjmp | gc.UseCarry, 0, 0, 0},
+	x86.AJPL:      {gc.Cjmp | gc.UseCarry, 0, 0, 0},
+	x86.AJPS:      {gc.Cjmp | gc.UseCarry, 0, 0, 0},
+	obj.AJMP:      {gc.Jump | gc.Break | gc.KillCarry, 0, 0, 0},
+	x86.ALEAL:     {gc.LeftAddr | gc.RightWrite, 0, 0, 0},
+	x86.AMOVBLSX:  {gc.SizeL | gc.LeftRead | gc.RightWrite | gc.Conv, 0, 0, 0},
+	x86.AMOVBLZX:  {gc.SizeL | gc.LeftRead | gc.RightWrite | gc.Conv, 0, 0, 0},
+	x86.AMOVBWSX:  {gc.SizeW | gc.LeftRead | gc.RightWrite | gc.Conv, 0, 0, 0},
+	x86.AMOVBWZX:  {gc.SizeW | gc.LeftRead | gc.RightWrite | gc.Conv, 0, 0, 0},
+	x86.AMOVWLSX:  {gc.SizeL | gc.LeftRead | gc.RightWrite | gc.Conv, 0, 0, 0},
+	x86.AMOVWLZX:  {gc.SizeL | gc.LeftRead | gc.RightWrite | gc.Conv, 0, 0, 0},
+	x86.AMOVB:     {gc.SizeB | gc.LeftRead | gc.RightWrite | gc.Move, 0, 0, 0},
+	x86.AMOVL:     {gc.SizeL | gc.LeftRead | gc.RightWrite | gc.Move, 0, 0, 0},
+	x86.AMOVW:     {gc.SizeW | gc.LeftRead | gc.RightWrite | gc.Move, 0, 0, 0},
+	x86.AMOVSB:    {gc.OK, DI | SI, DI | SI, 0},
+	x86.AMOVSL:    {gc.OK, DI | SI, DI | SI, 0},
+	x86.AMOVSW:    {gc.OK, DI | SI, DI | SI, 0},
+	obj.ADUFFCOPY: {gc.OK, DI | SI, DI | SI | CX, 0},
+	x86.AMOVSD:    {gc.SizeD | gc.LeftRead | gc.RightWrite | gc.Move, 0, 0, 0},
+	x86.AMOVSS:    {gc.SizeF | gc.LeftRead | gc.RightWrite | gc.Move, 0, 0, 0},
 
 	// We use MOVAPD as a faster synonym for MOVSD.
-	i386.AMOVAPD:  gc.ProgInfo{gc.SizeD | gc.LeftRead | gc.RightWrite | gc.Move, 0, 0, 0},
-	i386.AMULB:    gc.ProgInfo{gc.SizeB | gc.LeftRead | gc.SetCarry, AX, AX, 0},
-	i386.AMULL:    gc.ProgInfo{gc.SizeL | gc.LeftRead | gc.SetCarry, AX, AX | DX, 0},
-	i386.AMULW:    gc.ProgInfo{gc.SizeW | gc.LeftRead | gc.SetCarry, AX, AX | DX, 0},
-	i386.AMULSD:   gc.ProgInfo{gc.SizeD | gc.LeftRead | RightRdwr, 0, 0, 0},
-	i386.AMULSS:   gc.ProgInfo{gc.SizeF | gc.LeftRead | RightRdwr, 0, 0, 0},
-	i386.ANEGB:    gc.ProgInfo{gc.SizeB | RightRdwr | gc.SetCarry, 0, 0, 0},
-	i386.ANEGL:    gc.ProgInfo{gc.SizeL | RightRdwr | gc.SetCarry, 0, 0, 0},
-	i386.ANEGW:    gc.ProgInfo{gc.SizeW | RightRdwr | gc.SetCarry, 0, 0, 0},
-	i386.ANOTB:    gc.ProgInfo{gc.SizeB | RightRdwr, 0, 0, 0},
-	i386.ANOTL:    gc.ProgInfo{gc.SizeL | RightRdwr, 0, 0, 0},
-	i386.ANOTW:    gc.ProgInfo{gc.SizeW | RightRdwr, 0, 0, 0},
-	i386.AORB:     gc.ProgInfo{gc.SizeB | gc.LeftRead | RightRdwr | gc.SetCarry, 0, 0, 0},
-	i386.AORL:     gc.ProgInfo{gc.SizeL | gc.LeftRead | RightRdwr | gc.SetCarry, 0, 0, 0},
-	i386.AORW:     gc.ProgInfo{gc.SizeW | gc.LeftRead | RightRdwr | gc.SetCarry, 0, 0, 0},
-	i386.APOPL:    gc.ProgInfo{gc.SizeL | gc.RightWrite, 0, 0, 0},
-	i386.APUSHL:   gc.ProgInfo{gc.SizeL | gc.LeftRead, 0, 0, 0},
-	i386.ARCLB:    gc.ProgInfo{gc.SizeB | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry | gc.UseCarry, 0, 0, 0},
-	i386.ARCLL:    gc.ProgInfo{gc.SizeL | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry | gc.UseCarry, 0, 0, 0},
-	i386.ARCLW:    gc.ProgInfo{gc.SizeW | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry | gc.UseCarry, 0, 0, 0},
-	i386.ARCRB:    gc.ProgInfo{gc.SizeB | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry | gc.UseCarry, 0, 0, 0},
-	i386.ARCRL:    gc.ProgInfo{gc.SizeL | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry | gc.UseCarry, 0, 0, 0},
-	i386.ARCRW:    gc.ProgInfo{gc.SizeW | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry | gc.UseCarry, 0, 0, 0},
-	i386.AREP:     gc.ProgInfo{gc.OK, CX, CX, 0},
-	i386.AREPN:    gc.ProgInfo{gc.OK, CX, CX, 0},
-	obj.ARET:      gc.ProgInfo{gc.Break | gc.KillCarry, 0, 0, 0},
-	i386.AROLB:    gc.ProgInfo{gc.SizeB | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry, 0, 0, 0},
-	i386.AROLL:    gc.ProgInfo{gc.SizeL | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry, 0, 0, 0},
-	i386.AROLW:    gc.ProgInfo{gc.SizeW | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry, 0, 0, 0},
-	i386.ARORB:    gc.ProgInfo{gc.SizeB | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry, 0, 0, 0},
-	i386.ARORL:    gc.ProgInfo{gc.SizeL | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry, 0, 0, 0},
-	i386.ARORW:    gc.ProgInfo{gc.SizeW | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry, 0, 0, 0},
-	i386.ASAHF:    gc.ProgInfo{gc.OK, AX, AX, 0},
-	i386.ASALB:    gc.ProgInfo{gc.SizeB | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry, 0, 0, 0},
-	i386.ASALL:    gc.ProgInfo{gc.SizeL | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry, 0, 0, 0},
-	i386.ASALW:    gc.ProgInfo{gc.SizeW | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry, 0, 0, 0},
-	i386.ASARB:    gc.ProgInfo{gc.SizeB | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry, 0, 0, 0},
-	i386.ASARL:    gc.ProgInfo{gc.SizeL | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry, 0, 0, 0},
-	i386.ASARW:    gc.ProgInfo{gc.SizeW | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry, 0, 0, 0},
-	i386.ASBBB:    gc.ProgInfo{gc.SizeB | gc.LeftRead | RightRdwr | gc.SetCarry | gc.UseCarry, 0, 0, 0},
-	i386.ASBBL:    gc.ProgInfo{gc.SizeL | gc.LeftRead | RightRdwr | gc.SetCarry | gc.UseCarry, 0, 0, 0},
-	i386.ASBBW:    gc.ProgInfo{gc.SizeW | gc.LeftRead | RightRdwr | gc.SetCarry | gc.UseCarry, 0, 0, 0},
-	i386.ASETCC:   gc.ProgInfo{gc.SizeB | RightRdwr | gc.UseCarry, 0, 0, 0},
-	i386.ASETCS:   gc.ProgInfo{gc.SizeB | RightRdwr | gc.UseCarry, 0, 0, 0},
-	i386.ASETEQ:   gc.ProgInfo{gc.SizeB | RightRdwr | gc.UseCarry, 0, 0, 0},
-	i386.ASETGE:   gc.ProgInfo{gc.SizeB | RightRdwr | gc.UseCarry, 0, 0, 0},
-	i386.ASETGT:   gc.ProgInfo{gc.SizeB | RightRdwr | gc.UseCarry, 0, 0, 0},
-	i386.ASETHI:   gc.ProgInfo{gc.SizeB | RightRdwr | gc.UseCarry, 0, 0, 0},
-	i386.ASETLE:   gc.ProgInfo{gc.SizeB | RightRdwr | gc.UseCarry, 0, 0, 0},
-	i386.ASETLS:   gc.ProgInfo{gc.SizeB | RightRdwr | gc.UseCarry, 0, 0, 0},
-	i386.ASETLT:   gc.ProgInfo{gc.SizeB | RightRdwr | gc.UseCarry, 0, 0, 0},
-	i386.ASETMI:   gc.ProgInfo{gc.SizeB | RightRdwr | gc.UseCarry, 0, 0, 0},
-	i386.ASETNE:   gc.ProgInfo{gc.SizeB | RightRdwr | gc.UseCarry, 0, 0, 0},
-	i386.ASETOC:   gc.ProgInfo{gc.SizeB | RightRdwr | gc.UseCarry, 0, 0, 0},
-	i386.ASETOS:   gc.ProgInfo{gc.SizeB | RightRdwr | gc.UseCarry, 0, 0, 0},
-	i386.ASETPC:   gc.ProgInfo{gc.SizeB | RightRdwr | gc.UseCarry, 0, 0, 0},
-	i386.ASETPL:   gc.ProgInfo{gc.SizeB | RightRdwr | gc.UseCarry, 0, 0, 0},
-	i386.ASETPS:   gc.ProgInfo{gc.SizeB | RightRdwr | gc.UseCarry, 0, 0, 0},
-	i386.ASHLB:    gc.ProgInfo{gc.SizeB | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry, 0, 0, 0},
-	i386.ASHLL:    gc.ProgInfo{gc.SizeL | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry, 0, 0, 0},
-	i386.ASHLW:    gc.ProgInfo{gc.SizeW | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry, 0, 0, 0},
-	i386.ASHRB:    gc.ProgInfo{gc.SizeB | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry, 0, 0, 0},
-	i386.ASHRL:    gc.ProgInfo{gc.SizeL | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry, 0, 0, 0},
-	i386.ASHRW:    gc.ProgInfo{gc.SizeW | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry, 0, 0, 0},
-	i386.ASTOSB:   gc.ProgInfo{gc.OK, AX | DI, DI, 0},
-	i386.ASTOSL:   gc.ProgInfo{gc.OK, AX | DI, DI, 0},
-	i386.ASTOSW:   gc.ProgInfo{gc.OK, AX | DI, DI, 0},
-	obj.ADUFFZERO: gc.ProgInfo{gc.OK, AX | DI, DI, 0},
-	i386.ASUBB:    gc.ProgInfo{gc.SizeB | gc.LeftRead | RightRdwr | gc.SetCarry, 0, 0, 0},
-	i386.ASUBL:    gc.ProgInfo{gc.SizeL | gc.LeftRead | RightRdwr | gc.SetCarry, 0, 0, 0},
-	i386.ASUBW:    gc.ProgInfo{gc.SizeW | gc.LeftRead | RightRdwr | gc.SetCarry, 0, 0, 0},
-	i386.ASUBSD:   gc.ProgInfo{gc.SizeD | gc.LeftRead | RightRdwr, 0, 0, 0},
-	i386.ASUBSS:   gc.ProgInfo{gc.SizeF | gc.LeftRead | RightRdwr, 0, 0, 0},
-	i386.ATESTB:   gc.ProgInfo{gc.SizeB | gc.LeftRead | gc.RightRead | gc.SetCarry, 0, 0, 0},
-	i386.ATESTL:   gc.ProgInfo{gc.SizeL | gc.LeftRead | gc.RightRead | gc.SetCarry, 0, 0, 0},
-	i386.ATESTW:   gc.ProgInfo{gc.SizeW | gc.LeftRead | gc.RightRead | gc.SetCarry, 0, 0, 0},
-	i386.AUCOMISD: gc.ProgInfo{gc.SizeD | gc.LeftRead | gc.RightRead, 0, 0, 0},
-	i386.AUCOMISS: gc.ProgInfo{gc.SizeF | gc.LeftRead | gc.RightRead, 0, 0, 0},
-	i386.AXCHGB:   gc.ProgInfo{gc.SizeB | LeftRdwr | RightRdwr, 0, 0, 0},
-	i386.AXCHGL:   gc.ProgInfo{gc.SizeL | LeftRdwr | RightRdwr, 0, 0, 0},
-	i386.AXCHGW:   gc.ProgInfo{gc.SizeW | LeftRdwr | RightRdwr, 0, 0, 0},
-	i386.AXORB:    gc.ProgInfo{gc.SizeB | gc.LeftRead | RightRdwr | gc.SetCarry, 0, 0, 0},
-	i386.AXORL:    gc.ProgInfo{gc.SizeL | gc.LeftRead | RightRdwr | gc.SetCarry, 0, 0, 0},
-	i386.AXORW:    gc.ProgInfo{gc.SizeW | gc.LeftRead | RightRdwr | gc.SetCarry, 0, 0, 0},
+	x86.AMOVAPD:   {gc.SizeD | gc.LeftRead | gc.RightWrite | gc.Move, 0, 0, 0},
+	x86.AMULB:     {gc.SizeB | gc.LeftRead | gc.SetCarry, AX, AX, 0},
+	x86.AMULL:     {gc.SizeL | gc.LeftRead | gc.SetCarry, AX, AX | DX, 0},
+	x86.AMULW:     {gc.SizeW | gc.LeftRead | gc.SetCarry, AX, AX | DX, 0},
+	x86.AMULSD:    {gc.SizeD | gc.LeftRead | RightRdwr, 0, 0, 0},
+	x86.AMULSS:    {gc.SizeF | gc.LeftRead | RightRdwr, 0, 0, 0},
+	x86.ANEGB:     {gc.SizeB | RightRdwr | gc.SetCarry, 0, 0, 0},
+	x86.ANEGL:     {gc.SizeL | RightRdwr | gc.SetCarry, 0, 0, 0},
+	x86.ANEGW:     {gc.SizeW | RightRdwr | gc.SetCarry, 0, 0, 0},
+	x86.ANOTB:     {gc.SizeB | RightRdwr, 0, 0, 0},
+	x86.ANOTL:     {gc.SizeL | RightRdwr, 0, 0, 0},
+	x86.ANOTW:     {gc.SizeW | RightRdwr, 0, 0, 0},
+	x86.AORB:      {gc.SizeB | gc.LeftRead | RightRdwr | gc.SetCarry, 0, 0, 0},
+	x86.AORL:      {gc.SizeL | gc.LeftRead | RightRdwr | gc.SetCarry, 0, 0, 0},
+	x86.AORW:      {gc.SizeW | gc.LeftRead | RightRdwr | gc.SetCarry, 0, 0, 0},
+	x86.APOPL:     {gc.SizeL | gc.RightWrite, 0, 0, 0},
+	x86.APUSHL:    {gc.SizeL | gc.LeftRead, 0, 0, 0},
+	x86.ARCLB:     {gc.SizeB | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry | gc.UseCarry, 0, 0, 0},
+	x86.ARCLL:     {gc.SizeL | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry | gc.UseCarry, 0, 0, 0},
+	x86.ARCLW:     {gc.SizeW | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry | gc.UseCarry, 0, 0, 0},
+	x86.ARCRB:     {gc.SizeB | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry | gc.UseCarry, 0, 0, 0},
+	x86.ARCRL:     {gc.SizeL | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry | gc.UseCarry, 0, 0, 0},
+	x86.ARCRW:     {gc.SizeW | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry | gc.UseCarry, 0, 0, 0},
+	x86.AREP:      {gc.OK, CX, CX, 0},
+	x86.AREPN:     {gc.OK, CX, CX, 0},
+	obj.ARET:      {gc.Break | gc.KillCarry, 0, 0, 0},
+	x86.AROLB:     {gc.SizeB | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry, 0, 0, 0},
+	x86.AROLL:     {gc.SizeL | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry, 0, 0, 0},
+	x86.AROLW:     {gc.SizeW | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry, 0, 0, 0},
+	x86.ARORB:     {gc.SizeB | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry, 0, 0, 0},
+	x86.ARORL:     {gc.SizeL | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry, 0, 0, 0},
+	x86.ARORW:     {gc.SizeW | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry, 0, 0, 0},
+	x86.ASAHF:     {gc.OK, AX, AX, 0},
+	x86.ASALB:     {gc.SizeB | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry, 0, 0, 0},
+	x86.ASALL:     {gc.SizeL | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry, 0, 0, 0},
+	x86.ASALW:     {gc.SizeW | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry, 0, 0, 0},
+	x86.ASARB:     {gc.SizeB | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry, 0, 0, 0},
+	x86.ASARL:     {gc.SizeL | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry, 0, 0, 0},
+	x86.ASARW:     {gc.SizeW | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry, 0, 0, 0},
+	x86.ASBBB:     {gc.SizeB | gc.LeftRead | RightRdwr | gc.SetCarry | gc.UseCarry, 0, 0, 0},
+	x86.ASBBL:     {gc.SizeL | gc.LeftRead | RightRdwr | gc.SetCarry | gc.UseCarry, 0, 0, 0},
+	x86.ASBBW:     {gc.SizeW | gc.LeftRead | RightRdwr | gc.SetCarry | gc.UseCarry, 0, 0, 0},
+	x86.ASETCC:    {gc.SizeB | RightRdwr | gc.UseCarry, 0, 0, 0},
+	x86.ASETCS:    {gc.SizeB | RightRdwr | gc.UseCarry, 0, 0, 0},
+	x86.ASETEQ:    {gc.SizeB | RightRdwr | gc.UseCarry, 0, 0, 0},
+	x86.ASETGE:    {gc.SizeB | RightRdwr | gc.UseCarry, 0, 0, 0},
+	x86.ASETGT:    {gc.SizeB | RightRdwr | gc.UseCarry, 0, 0, 0},
+	x86.ASETHI:    {gc.SizeB | RightRdwr | gc.UseCarry, 0, 0, 0},
+	x86.ASETLE:    {gc.SizeB | RightRdwr | gc.UseCarry, 0, 0, 0},
+	x86.ASETLS:    {gc.SizeB | RightRdwr | gc.UseCarry, 0, 0, 0},
+	x86.ASETLT:    {gc.SizeB | RightRdwr | gc.UseCarry, 0, 0, 0},
+	x86.ASETMI:    {gc.SizeB | RightRdwr | gc.UseCarry, 0, 0, 0},
+	x86.ASETNE:    {gc.SizeB | RightRdwr | gc.UseCarry, 0, 0, 0},
+	x86.ASETOC:    {gc.SizeB | RightRdwr | gc.UseCarry, 0, 0, 0},
+	x86.ASETOS:    {gc.SizeB | RightRdwr | gc.UseCarry, 0, 0, 0},
+	x86.ASETPC:    {gc.SizeB | RightRdwr | gc.UseCarry, 0, 0, 0},
+	x86.ASETPL:    {gc.SizeB | RightRdwr | gc.UseCarry, 0, 0, 0},
+	x86.ASETPS:    {gc.SizeB | RightRdwr | gc.UseCarry, 0, 0, 0},
+	x86.ASHLB:     {gc.SizeB | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry, 0, 0, 0},
+	x86.ASHLL:     {gc.SizeL | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry, 0, 0, 0},
+	x86.ASHLW:     {gc.SizeW | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry, 0, 0, 0},
+	x86.ASHRB:     {gc.SizeB | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry, 0, 0, 0},
+	x86.ASHRL:     {gc.SizeL | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry, 0, 0, 0},
+	x86.ASHRW:     {gc.SizeW | gc.LeftRead | RightRdwr | gc.ShiftCX | gc.SetCarry, 0, 0, 0},
+	x86.ASTOSB:    {gc.OK, AX | DI, DI, 0},
+	x86.ASTOSL:    {gc.OK, AX | DI, DI, 0},
+	x86.ASTOSW:    {gc.OK, AX | DI, DI, 0},
+	obj.ADUFFZERO: {gc.OK, AX | DI, DI, 0},
+	x86.ASUBB:     {gc.SizeB | gc.LeftRead | RightRdwr | gc.SetCarry, 0, 0, 0},
+	x86.ASUBL:     {gc.SizeL | gc.LeftRead | RightRdwr | gc.SetCarry, 0, 0, 0},
+	x86.ASUBW:     {gc.SizeW | gc.LeftRead | RightRdwr | gc.SetCarry, 0, 0, 0},
+	x86.ASUBSD:    {gc.SizeD | gc.LeftRead | RightRdwr, 0, 0, 0},
+	x86.ASUBSS:    {gc.SizeF | gc.LeftRead | RightRdwr, 0, 0, 0},
+	x86.ATESTB:    {gc.SizeB | gc.LeftRead | gc.RightRead | gc.SetCarry, 0, 0, 0},
+	x86.ATESTL:    {gc.SizeL | gc.LeftRead | gc.RightRead | gc.SetCarry, 0, 0, 0},
+	x86.ATESTW:    {gc.SizeW | gc.LeftRead | gc.RightRead | gc.SetCarry, 0, 0, 0},
+	x86.AUCOMISD:  {gc.SizeD | gc.LeftRead | gc.RightRead, 0, 0, 0},
+	x86.AUCOMISS:  {gc.SizeF | gc.LeftRead | gc.RightRead, 0, 0, 0},
+	x86.AXCHGB:    {gc.SizeB | LeftRdwr | RightRdwr, 0, 0, 0},
+	x86.AXCHGL:    {gc.SizeL | LeftRdwr | RightRdwr, 0, 0, 0},
+	x86.AXCHGW:    {gc.SizeW | LeftRdwr | RightRdwr, 0, 0, 0},
+	x86.AXORB:     {gc.SizeB | gc.LeftRead | RightRdwr | gc.SetCarry, 0, 0, 0},
+	x86.AXORL:     {gc.SizeL | gc.LeftRead | RightRdwr | gc.SetCarry, 0, 0, 0},
+	x86.AXORW:     {gc.SizeW | gc.LeftRead | RightRdwr | gc.SetCarry, 0, 0, 0},
 }
 
-func proginfo(info *gc.ProgInfo, p *obj.Prog) {
+func proginfo(p *obj.Prog) {
+	info := &p.Info
 	*info = progtable[p.As]
 	if info.Flags == 0 {
 		gc.Fatal("unknown instruction %v", p)
@@ -279,13 +280,13 @@
 	if p.From.Type == obj.TYPE_MEM && p.From.Name == obj.NAME_NONE {
 		info.Regindex |= RtoB(int(p.From.Reg))
 	}
-	if p.From.Index != i386.REG_NONE {
+	if p.From.Index != x86.REG_NONE {
 		info.Regindex |= RtoB(int(p.From.Index))
 	}
 	if p.To.Type == obj.TYPE_MEM && p.To.Name == obj.NAME_NONE {
 		info.Regindex |= RtoB(int(p.To.Reg))
 	}
-	if p.To.Index != i386.REG_NONE {
+	if p.To.Index != x86.REG_NONE {
 		info.Regindex |= RtoB(int(p.To.Index))
 	}
 }
diff --git a/src/cmd/8g/reg.go b/src/cmd/8g/reg.go
index 4d4d9a5..9f2cb60 100644
--- a/src/cmd/8g/reg.go
+++ b/src/cmd/8g/reg.go
@@ -30,11 +30,11 @@
 
 package main
 
-import "cmd/internal/obj/i386"
+import "cmd/internal/obj/x86"
 import "cmd/internal/gc"
 
 const (
-	NREGVAR = 16
+	NREGVAR = 16 /* 8 integer + 8 floating */
 )
 
 var regname = []string{
@@ -62,28 +62,28 @@
 }
 
 func excludedregs() uint64 {
-	return RtoB(i386.REG_SP)
+	return RtoB(x86.REG_SP)
 }
 
 func doregbits(r int) uint64 {
 	b := uint64(0)
-	if r >= i386.REG_AX && r <= i386.REG_DI {
+	if r >= x86.REG_AX && r <= x86.REG_DI {
 		b |= RtoB(r)
-	} else if r >= i386.REG_AL && r <= i386.REG_BL {
-		b |= RtoB(r - i386.REG_AL + i386.REG_AX)
-	} else if r >= i386.REG_AH && r <= i386.REG_BH {
-		b |= RtoB(r - i386.REG_AH + i386.REG_AX)
-	} else if r >= i386.REG_X0 && r <= i386.REG_X0+7 {
+	} else if r >= x86.REG_AL && r <= x86.REG_BL {
+		b |= RtoB(r - x86.REG_AL + x86.REG_AX)
+	} else if r >= x86.REG_AH && r <= x86.REG_BH {
+		b |= RtoB(r - x86.REG_AH + x86.REG_AX)
+	} else if r >= x86.REG_X0 && r <= x86.REG_X0+7 {
 		b |= FtoB(r)
 	}
 	return b
 }
 
 func RtoB(r int) uint64 {
-	if r < i386.REG_AX || r > i386.REG_DI {
+	if r < x86.REG_AX || r > x86.REG_DI {
 		return 0
 	}
-	return 1 << uint(r-i386.REG_AX)
+	return 1 << uint(r-x86.REG_AX)
 }
 
 func BtoR(b uint64) int {
@@ -91,14 +91,14 @@
 	if b == 0 {
 		return 0
 	}
-	return gc.Bitno(b) + i386.REG_AX
+	return gc.Bitno(b) + x86.REG_AX
 }
 
 func FtoB(f int) uint64 {
-	if f < i386.REG_X0 || f > i386.REG_X7 {
+	if f < x86.REG_X0 || f > x86.REG_X7 {
 		return 0
 	}
-	return 1 << uint(f-i386.REG_X0+8)
+	return 1 << uint(f-x86.REG_X0+8)
 }
 
 func BtoF(b uint64) int {
@@ -106,5 +106,5 @@
 	if b == 0 {
 		return 0
 	}
-	return gc.Bitno(b) - 8 + i386.REG_X0
+	return gc.Bitno(b) - 8 + x86.REG_X0
 }
diff --git a/src/cmd/8l/asm.go b/src/cmd/8l/asm.go
index 295c62e..49ff080 100644
--- a/src/cmd/8l/asm.go
+++ b/src/cmd/8l/asm.go
@@ -31,24 +31,21 @@
 package main
 
 import (
+	"cmd/internal/ld"
 	"cmd/internal/obj"
 	"fmt"
 	"log"
 )
-import "cmd/internal/ld"
 
 func needlib(name string) int {
-	var p string
-	var s *ld.LSym
-
 	if name[0] == '\x00' {
 		return 0
 	}
 
 	/* reuse hash code in symbol table */
-	p = fmt.Sprintf(".dynlib.%s", name)
+	p := fmt.Sprintf(".dynlib.%s", name)
 
-	s = ld.Linklookup(ld.Ctxt, p, 0)
+	s := ld.Linklookup(ld.Ctxt, p, 0)
 
 	if s.Type == 0 {
 		s.Type = 100 // avoid SDATA, etc.
@@ -66,11 +63,7 @@
 }
 
 func adddynrel(s *ld.LSym, r *ld.Reloc) {
-	var targ *ld.LSym
-	var rel *ld.LSym
-	var got *ld.LSym
-
-	targ = r.Sym
+	targ := r.Sym
 	ld.Ctxt.Cursym = s
 
 	switch r.Type {
@@ -210,7 +203,7 @@
 		}
 		if ld.Iself {
 			adddynsym(ld.Ctxt, targ)
-			rel = ld.Linklookup(ld.Ctxt, ".rel", 0)
+			rel := ld.Linklookup(ld.Ctxt, ".rel", 0)
 			ld.Addaddrplus(ld.Ctxt, rel, s, int64(r.Off))
 			ld.Adduint32(ld.Ctxt, rel, ld.ELF32_R_INFO(uint32(targ.Dynid), ld.R_386_32))
 			r.Type = ld.R_CONST // write r->add during relocsym
@@ -231,7 +224,7 @@
 			// but we only need to support cgo and that's all it needs.
 			adddynsym(ld.Ctxt, targ)
 
-			got = ld.Linklookup(ld.Ctxt, ".got", 0)
+			got := ld.Linklookup(ld.Ctxt, ".got", 0)
 			s.Type = got.Type | ld.SSUB
 			s.Outer = got
 			s.Sub = got.Sub
@@ -242,6 +235,11 @@
 			r.Type = 256 // ignore during relocsym
 			return
 		}
+
+		if ld.HEADTYPE == ld.Hwindows && s.Size == PtrSize {
+			// nothing to do, the relocation will be laid out in pereloc1
+			return
+		}
 	}
 
 	ld.Ctxt.Cursym = s
@@ -249,11 +247,9 @@
 }
 
 func elfreloc1(r *ld.Reloc, sectoff int64) int {
-	var elfsym int32
-
 	ld.Thearch.Lput(uint32(sectoff))
 
-	elfsym = r.Xsym.Elfsym
+	elfsym := r.Xsym.Elfsym
 	switch r.Type {
 	default:
 		return -1
@@ -287,9 +283,8 @@
 
 func machoreloc1(r *ld.Reloc, sectoff int64) int {
 	var v uint32
-	var rs *ld.LSym
 
-	rs = r.Xsym
+	rs := r.Xsym
 
 	if rs.Type == ld.SHOSTOBJ {
 		if rs.Dynid < 0 {
@@ -342,6 +337,36 @@
 	return 0
 }
 
+func pereloc1(r *ld.Reloc, sectoff int64) bool {
+	var v uint32
+
+	rs := r.Xsym
+
+	if rs.Dynid < 0 {
+		ld.Diag("reloc %d to non-coff symbol %s type=%d", r.Type, rs.Name, rs.Type)
+		return false
+	}
+
+	ld.Thearch.Lput(uint32(sectoff))
+	ld.Thearch.Lput(uint32(rs.Dynid))
+
+	switch r.Type {
+	default:
+		return false
+
+	case ld.R_ADDR:
+		v = ld.IMAGE_REL_I386_DIR32
+
+	case ld.R_CALL,
+		ld.R_PCREL:
+		v = ld.IMAGE_REL_I386_REL32
+	}
+
+	ld.Thearch.Wput(uint16(v))
+
+	return true
+}
+
 func archreloc(r *ld.Reloc, s *ld.LSym, val *int64) int {
 	if ld.Linkmode == ld.LinkExternal {
 		return -1
@@ -365,11 +390,8 @@
 }
 
 func elfsetupplt() {
-	var plt *ld.LSym
-	var got *ld.LSym
-
-	plt = ld.Linklookup(ld.Ctxt, ".plt", 0)
-	got = ld.Linklookup(ld.Ctxt, ".got.plt", 0)
+	plt := ld.Linklookup(ld.Ctxt, ".plt", 0)
+	got := ld.Linklookup(ld.Ctxt, ".got.plt", 0)
 	if plt.Size == 0 {
 		// pushl got+4
 		ld.Adduint8(ld.Ctxt, plt, 0xff)
@@ -395,10 +417,6 @@
 }
 
 func addpltsym(ctxt *ld.Link, s *ld.LSym) {
-	var plt *ld.LSym
-	var got *ld.LSym
-	var rel *ld.LSym
-
 	if s.Plt >= 0 {
 		return
 	}
@@ -406,9 +424,9 @@
 	adddynsym(ctxt, s)
 
 	if ld.Iself {
-		plt = ld.Linklookup(ctxt, ".plt", 0)
-		got = ld.Linklookup(ctxt, ".got.plt", 0)
-		rel = ld.Linklookup(ctxt, ".rel.plt", 0)
+		plt := ld.Linklookup(ctxt, ".plt", 0)
+		got := ld.Linklookup(ctxt, ".got.plt", 0)
+		rel := ld.Linklookup(ctxt, ".rel.plt", 0)
 		if plt.Size == 0 {
 			elfsetupplt()
 		}
@@ -441,9 +459,7 @@
 	} else if ld.HEADTYPE == ld.Hdarwin {
 		// Same laziness as in 6l.
 
-		var plt *ld.LSym
-
-		plt = ld.Linklookup(ctxt, ".plt", 0)
+		plt := ld.Linklookup(ctxt, ".plt", 0)
 
 		addgotsym(ctxt, s)
 
@@ -461,20 +477,17 @@
 }
 
 func addgotsym(ctxt *ld.Link, s *ld.LSym) {
-	var got *ld.LSym
-	var rel *ld.LSym
-
 	if s.Got >= 0 {
 		return
 	}
 
 	adddynsym(ctxt, s)
-	got = ld.Linklookup(ctxt, ".got", 0)
+	got := ld.Linklookup(ctxt, ".got", 0)
 	s.Got = int32(got.Size)
 	ld.Adduint32(ctxt, got, 0)
 
 	if ld.Iself {
-		rel = ld.Linklookup(ctxt, ".rel", 0)
+		rel := ld.Linklookup(ctxt, ".rel", 0)
 		ld.Addaddrplus(ctxt, rel, got, int64(s.Got))
 		ld.Adduint32(ctxt, rel, ld.ELF32_R_INFO(uint32(s.Dynid), ld.R_386_GLOB_DAT))
 	} else if ld.HEADTYPE == ld.Hdarwin {
@@ -485,10 +498,6 @@
 }
 
 func adddynsym(ctxt *ld.Link, s *ld.LSym) {
-	var d *ld.LSym
-	var t int
-	var name string
-
 	if s.Dynid >= 0 {
 		return
 	}
@@ -497,10 +506,10 @@
 		s.Dynid = int32(ld.Nelfsym)
 		ld.Nelfsym++
 
-		d = ld.Linklookup(ctxt, ".dynsym", 0)
+		d := ld.Linklookup(ctxt, ".dynsym", 0)
 
 		/* name */
-		name = s.Extname
+		name := s.Extname
 
 		ld.Adduint32(ctxt, d, uint32(ld.Addstring(ld.Linklookup(ctxt, ".dynstr", 0), name)))
 
@@ -515,7 +524,7 @@
 		ld.Adduint32(ctxt, d, 0)
 
 		/* type */
-		t = ld.STB_GLOBAL << 4
+		t := ld.STB_GLOBAL << 4
 
 		if s.Cgoexport != 0 && s.Type&ld.SMASK == ld.STEXT {
 			t |= ld.STT_FUNC
@@ -541,14 +550,12 @@
 }
 
 func adddynlib(lib string) {
-	var s *ld.LSym
-
 	if needlib(lib) == 0 {
 		return
 	}
 
 	if ld.Iself {
-		s = ld.Linklookup(ld.Ctxt, ".dynstr", 0)
+		s := ld.Linklookup(ld.Ctxt, ".dynstr", 0)
 		if s.Size == 0 {
 			ld.Addstring(s, "")
 		}
@@ -561,14 +568,6 @@
 }
 
 func asmb() {
-	var magic int32
-	var symo uint32
-	var dwarfoff uint32
-	var machlink uint32
-	var sect *ld.Section
-	var sym *ld.LSym
-	var i int
-
 	if ld.Debug['v'] != 0 {
 		fmt.Fprintf(&ld.Bso, "%5.2f asmb\n", obj.Cputime())
 	}
@@ -578,7 +577,7 @@
 		ld.Asmbelfsetup()
 	}
 
-	sect = ld.Segtext.Sect
+	sect := ld.Segtext.Sect
 	ld.Cseek(int64(sect.Vaddr - ld.Segtext.Vaddr + ld.Segtext.Fileoff))
 	ld.Codeblk(int64(sect.Vaddr), int64(sect.Length))
 	for sect = sect.Next; sect != nil; sect = sect.Next {
@@ -604,13 +603,13 @@
 	ld.Cseek(int64(ld.Segdata.Fileoff))
 	ld.Datblk(int64(ld.Segdata.Vaddr), int64(ld.Segdata.Filelen))
 
-	machlink = 0
+	machlink := uint32(0)
 	if ld.HEADTYPE == ld.Hdarwin {
 		if ld.Debug['v'] != 0 {
 			fmt.Fprintf(&ld.Bso, "%5.2f dwarf\n", obj.Cputime())
 		}
 
-		dwarfoff = uint32(ld.Rnd(int64(uint64(ld.HEADR)+ld.Segtext.Length), int64(ld.INITRND)) + ld.Rnd(int64(ld.Segdata.Filelen), int64(ld.INITRND)))
+		dwarfoff := uint32(ld.Rnd(int64(uint64(ld.HEADR)+ld.Segtext.Length), int64(ld.INITRND)) + ld.Rnd(int64(ld.Segdata.Filelen), int64(ld.INITRND)))
 		ld.Cseek(int64(dwarfoff))
 
 		ld.Segdwarf.Fileoff = uint64(ld.Cpos())
@@ -623,7 +622,7 @@
 	ld.Symsize = 0
 	ld.Spsize = 0
 	ld.Lcsize = 0
-	symo = 0
+	symo := uint32(0)
 	if ld.Debug['s'] == 0 {
 		// TODO: rationalize
 		if ld.Debug['v'] != 0 {
@@ -673,10 +672,10 @@
 			ld.Asmplan9sym()
 			ld.Cflush()
 
-			sym = ld.Linklookup(ld.Ctxt, "pclntab", 0)
+			sym := ld.Linklookup(ld.Ctxt, "pclntab", 0)
 			if sym != nil {
 				ld.Lcsize = int32(len(sym.P))
-				for i = 0; int32(i) < ld.Lcsize; i++ {
+				for i := 0; int32(i) < ld.Lcsize; i++ {
 					ld.Cput(uint8(sym.P[i]))
 				}
 
@@ -704,7 +703,7 @@
 	switch ld.HEADTYPE {
 	default:
 	case ld.Hplan9: /* plan9 */
-		magic = 4*11*11 + 7
+		magic := int32(4*11*11 + 7)
 
 		ld.Lputb(uint32(magic))              /* magic */
 		ld.Lputb(uint32(ld.Segtext.Filelen)) /* sizes */
@@ -722,7 +721,6 @@
 		ld.Hfreebsd,
 		ld.Hnetbsd,
 		ld.Hopenbsd,
-		ld.Hdragonfly,
 		ld.Hnacl:
 		ld.Asmbelf(int64(symo))
 
diff --git a/src/cmd/8l/l.go b/src/cmd/8l/l.go
index fbeee98..6005085 100644
--- a/src/cmd/8l/l.go
+++ b/src/cmd/8l/l.go
@@ -1,37 +1,3 @@
-// Inferno utils/8l/asm.c
-// http://code.google.com/p/inferno-os/source/browse/utils/8l/asm.c
-//
-//	Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
-//	Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
-//	Portions Copyright © 1997-1999 Vita Nuova Limited
-//	Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
-//	Portions Copyright © 2004,2006 Bruce Ellis
-//	Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
-//	Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
-//	Portions Copyright © 2009 The Go Authors.  All rights reserved.
-//
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files (the "Software"), to deal
-// in the Software without restriction, including without limitation the rights
-// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-// copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-// THE SOFTWARE.
-
-package main
-
-// Writing object files.
-
 // Inferno utils/8l/l.h
 // http://code.google.com/p/inferno-os/source/browse/utils/8l/l.h
 //
@@ -62,12 +28,14 @@
 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 // THE SOFTWARE.
 
+package main
+
 const (
 	thechar   = '8'
 	PtrSize   = 4
 	IntSize   = 4
 	RegSize   = 4
-	MaxAlign  = 32
+	MaxAlign  = 32 // max data alignment
 	FuncAlign = 16
 	MINLC     = 1
 )
diff --git a/src/cmd/8l/obj.go b/src/cmd/8l/obj.go
index 5d44721..938a777 100644
--- a/src/cmd/8l/obj.go
+++ b/src/cmd/8l/obj.go
@@ -31,11 +31,11 @@
 package main
 
 import (
+	"cmd/internal/ld"
 	"cmd/internal/obj"
 	"fmt"
 	"log"
 )
-import "cmd/internal/ld"
 
 // Reading object files.
 
@@ -68,6 +68,7 @@
 	ld.Thearch.Elfsetupplt = elfsetupplt
 	ld.Thearch.Gentext = gentext
 	ld.Thearch.Machoreloc1 = machoreloc1
+	ld.Thearch.PEreloc1 = pereloc1
 	ld.Thearch.Lput = ld.Lputl
 	ld.Thearch.Wput = ld.Wputl
 	ld.Thearch.Vput = ld.Vputl
@@ -76,7 +77,6 @@
 	ld.Thearch.Freebsddynld = "/usr/libexec/ld-elf.so.1"
 	ld.Thearch.Openbsddynld = "/usr/libexec/ld.so"
 	ld.Thearch.Netbsddynld = "/usr/libexec/ld.elf_so"
-	ld.Thearch.Dragonflydynld = "/usr/libexec/ld-elf.so.2"
 	ld.Thearch.Solarisdynld = "/lib/ld.so.1"
 }
 
@@ -97,11 +97,11 @@
 		}
 
 	case ld.Hdarwin,
-		ld.Hdragonfly,
 		ld.Hfreebsd,
 		ld.Hlinux,
 		ld.Hnetbsd,
-		ld.Hopenbsd:
+		ld.Hopenbsd,
+		ld.Hwindows:
 		break
 	}
 
@@ -141,8 +141,7 @@
 	case ld.Hlinux, /* elf32 executable */
 		ld.Hfreebsd,
 		ld.Hnetbsd,
-		ld.Hopenbsd,
-		ld.Hdragonfly:
+		ld.Hopenbsd:
 		ld.Elfinit()
 
 		ld.HEADR = ld.ELFRESERVE
diff --git a/src/cmd/9g/cgen.go b/src/cmd/9g/cgen.go
index 74accf2..0f7fc07 100644
--- a/src/cmd/9g/cgen.go
+++ b/src/cmd/9g/cgen.go
@@ -5,1471 +5,12 @@
 package main
 
 import (
+	"cmd/internal/gc"
 	"cmd/internal/obj"
 	"cmd/internal/obj/ppc64"
-	"fmt"
 )
-import "cmd/internal/gc"
 
-/*
- * 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)
-	}
-
-	var a int
-	var nr *gc.Node
-	var nl *gc.Node
-	var n1 gc.Node
-	var n2 gc.Node
-	if n == nil || n.Type == nil {
-		goto ret
-	}
-
-	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)
-		}
-		goto ret
-
-	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)
-		}
-		goto ret
-	}
-
-	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)
-			goto ret
-		}
-	}
-
-	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)
-		goto ret
-	}
-
-	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)
-			goto ret
-		}
-
-		var f int
-		if res.Ullman >= gc.UINF {
-			goto gen
-		}
-
-		if gc.Complexop(n, res) {
-			gc.Complexgen(n, res)
-			goto ret
-		}
-
-		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] == 0 {
-			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()
-				goto ret
-			}
-		}
-
-	gen:
-		var n1 gc.Node
-		igen(res, &n1, nil)
-		cgen(n, &n1)
-		regfree(&n1)
-		goto ret
-	}
-
-	// 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)
-		goto ret
-	}
-
-	// 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)
-		}
-
-		goto ret
-	}
-
-	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)
-			goto ret
-		}
-	}
-
-	if gc.Iscomplex[n.Type.Etype] == 0 {
-		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()
-			goto ret
-		}
-	}
-
-	// 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;
-
-	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)
-		goto ret
-
-	case gc.OPLUS:
-		cgen(nl, res)
-		goto ret
-
-		// 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)
-		goto ret
-
-	case gc.OMINUS:
-		if gc.Isfloat[nl.Type.Etype] != 0 {
-			nr = gc.Nodintconst(-1)
-			gc.Convlit(&nr, n.Type)
-			a = optoas(gc.OMUL, nl.Type)
-			goto sbop
-		}
-
-		a = optoas(int(n.Op), nl.Type)
-		goto uop
-
-		// 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)
-				goto ret
-			}
-		}
-
-		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.S, &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] != 0 {
-			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)
-	}
-
-	goto ret
-
-	/*
-	 * 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
-	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)
-	}
-	goto ret
-
-uop: // unary
-	regalloc(&n1, nl.Type, res)
-
-	cgen(nl, &n1)
-	gins(a, nil, &n1)
-	gmove(&n1, res)
-	regfree(&n1)
-	goto ret
-
-ret:
-}
-
-/*
- * 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.S)))
-			} 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.S, &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
-	}
-
-	var nl *gc.Node
-	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)
-		n3 := gc.Node{}
-		n3.Op = gc.OADDR
-		n3.Left = &n1
-		gins(ppc64.AMOVD, &n3, &n2)
-		gmove(&n2, res)
-		regfree(&n2)
-		goto ret
-	}
-
-	if n.Addable != 0 {
-		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)
-		goto ret
-	}
-
-	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)
-		}
-	}
-
-ret:
-}
-
-/*
- * 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] != 0 && gc.Isfixedarray(n.Left.Left.Type)) {
-			if gc.Isconst(n.Right, gc.CTINT) {
-				// Compute &a.
-				if gc.Isptr[n.Left.Type.Etype] == 0 {
-					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)
-	}
-
-	var et int
-	var nl *gc.Node
-	var nr *gc.Node
-	if n.Type == nil {
-		gc.Convlit(&n, gc.Types[gc.TBOOL])
-		if n.Type == nil {
-			goto ret
-		}
-	}
-
-	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)
-		goto ret
-	}
-
-	nr = nil
-
-	for n.Op == gc.OCONVNOP {
-		n = n.Left
-		if n.Ninit != nil {
-			gc.Genlist(n.Ninit)
-		}
-	}
-
-	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)
-		goto ret
-
-		// 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)
-		}
-		goto ret
-
-	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)
-		}
-
-		goto ret
-
-	case gc.OEQ,
-		gc.ONE,
-		gc.OLT,
-		gc.OGT,
-		gc.OLE,
-		gc.OGE:
-		nr = n.Right
-		if nr == nil || nr.Type == nil {
-			goto ret
-		}
-		fallthrough
-
-	case gc.ONOT: // unary
-		nl = n.Left
-
-		if nl == nil || nl.Type == nil {
-			goto ret
-		}
-	}
-
-	switch n.Op {
-	case gc.ONOT:
-		bgen(nl, !true_, likely, to)
-		goto ret
-
-	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] != 0 {
-				// 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)
-				goto ret
-			}
-
-			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] != 0 {
-			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] != 0 && (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)
-	}
-
-	goto ret
-
-ret:
-}
-
-/*
- * 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] != 0 {
-			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] != 0 {
-			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(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.
@@ -1499,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
@@ -1531,31 +51,31 @@
 	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
-	nend := gc.Node{}
+	var nend gc.Node
 
 	// 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)
 		}
 
@@ -1576,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
@@ -1598,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
@@ -1623,272 +143,7 @@
 		}
 	}
 
-	regfree(&dst)
-	regfree(&src)
-	regfree(&tmp)
-}
-
-func cadable(n *gc.Node) bool {
-	if n.Addable == 0 {
-		// dont know how it happens,
-		// but it does
-		return false
-	}
-
-	switch n.Op {
-	case gc.ONAME:
-		return true
-	}
-
-	return false
-}
-
-/*
- * copy a composite value by moving its individual components.
- * Slices, strings and interfaces are supported.
- * Small structs or arrays with elements of basic type are
- * also supported.
- * nr is N when assigning a zero value.
- * return 1 if can do, 0 if can't.
- */
-func componentgen(nr *gc.Node, nl *gc.Node) bool {
-	var nodl gc.Node
-	var nodr gc.Node
-
-	freel := 0
-	freer := 0
-
-	switch nl.Type.Etype {
-	default:
-		goto no
-
-	case gc.TARRAY:
-		t := nl.Type
-
-		// Slices are ok.
-		if gc.Isslice(t) {
-			break
-		}
-
-		// Small arrays are ok.
-		if t.Bound > 0 && t.Bound <= 3 && !gc.Isfat(t.Type) {
-			break
-		}
-
-		goto no
-
-		// Small structs with non-fat types are ok.
-	// Zero-sized structs are treated separately elsewhere.
-	case gc.TSTRUCT:
-		fldcount := int64(0)
-
-		for t := nl.Type.Type; t != nil; t = t.Down {
-			if gc.Isfat(t.Type) {
-				goto no
-			}
-			if t.Etype != gc.TFIELD {
-				gc.Fatal("componentgen: not a TFIELD: %v", gc.Tconv(t, obj.FmtLong))
-			}
-			fldcount++
-		}
-
-		if fldcount == 0 || fldcount > 4 {
-			goto no
-		}
-
-	case gc.TSTRING,
-		gc.TINTER:
-		break
-	}
-
-	nodl = *nl
-	if !cadable(nl) {
-		if nr != nil && !cadable(nr) {
-			goto no
-		}
-		igen(nl, &nodl, nil)
-		freel = 1
-	}
-
-	if nr != nil {
-		nodr = *nr
-		if !cadable(nr) {
-			igen(nr, &nodr, nil)
-			freer = 1
-		}
-	} else {
-		// When zeroing, prepare a register containing zero.
-		var tmp gc.Node
-		gc.Nodconst(&tmp, nl.Type, 0)
-
-		regalloc(&nodr, gc.Types[gc.TUINT], nil)
-		gmove(&tmp, &nodr)
-		freer = 1
-	}
-
-	// nl and nr are 'cadable' which basically means they are names (variables) now.
-	// If they are the same variable, don't generate any code, because the
-	// VARDEF we generate will mark the old value as dead incorrectly.
-	// (And also the assignments are useless.)
-	if nr != nil && nl.Op == gc.ONAME && nr.Op == gc.ONAME && nl == nr {
-		goto yes
-	}
-
-	switch nl.Type.Etype {
-	// componentgen for arrays.
-	case gc.TARRAY:
-		if nl.Op == gc.ONAME {
-			gc.Gvardef(nl)
-		}
-		t := nl.Type
-		if !gc.Isslice(t) {
-			nodl.Type = t.Type
-			nodr.Type = nodl.Type
-			for fldcount := int64(0); fldcount < t.Bound; fldcount++ {
-				if nr == nil {
-					gc.Clearslim(&nodl)
-				} else {
-					gmove(&nodr, &nodl)
-				}
-				nodl.Xoffset += t.Type.Width
-				nodr.Xoffset += t.Type.Width
-			}
-
-			goto yes
-		}
-
-		// componentgen for slices.
-		nodl.Xoffset += int64(gc.Array_array)
-
-		nodl.Type = gc.Ptrto(nl.Type.Type)
-
-		if nr != nil {
-			nodr.Xoffset += int64(gc.Array_array)
-			nodr.Type = nodl.Type
-		}
-
-		gmove(&nodr, &nodl)
-
-		nodl.Xoffset += int64(gc.Array_nel) - int64(gc.Array_array)
-		nodl.Type = gc.Types[gc.Simtype[gc.TUINT]]
-
-		if nr != nil {
-			nodr.Xoffset += int64(gc.Array_nel) - int64(gc.Array_array)
-			nodr.Type = nodl.Type
-		}
-
-		gmove(&nodr, &nodl)
-
-		nodl.Xoffset += int64(gc.Array_cap) - int64(gc.Array_nel)
-		nodl.Type = gc.Types[gc.Simtype[gc.TUINT]]
-
-		if nr != nil {
-			nodr.Xoffset += int64(gc.Array_cap) - int64(gc.Array_nel)
-			nodr.Type = nodl.Type
-		}
-
-		gmove(&nodr, &nodl)
-
-		goto yes
-
-	case gc.TSTRING:
-		if nl.Op == gc.ONAME {
-			gc.Gvardef(nl)
-		}
-		nodl.Xoffset += int64(gc.Array_array)
-		nodl.Type = gc.Ptrto(gc.Types[gc.TUINT8])
-
-		if nr != nil {
-			nodr.Xoffset += int64(gc.Array_array)
-			nodr.Type = nodl.Type
-		}
-
-		gmove(&nodr, &nodl)
-
-		nodl.Xoffset += int64(gc.Array_nel) - int64(gc.Array_array)
-		nodl.Type = gc.Types[gc.Simtype[gc.TUINT]]
-
-		if nr != nil {
-			nodr.Xoffset += int64(gc.Array_nel) - int64(gc.Array_array)
-			nodr.Type = nodl.Type
-		}
-
-		gmove(&nodr, &nodl)
-
-		goto yes
-
-	case gc.TINTER:
-		if nl.Op == gc.ONAME {
-			gc.Gvardef(nl)
-		}
-		nodl.Xoffset += int64(gc.Array_array)
-		nodl.Type = gc.Ptrto(gc.Types[gc.TUINT8])
-
-		if nr != nil {
-			nodr.Xoffset += int64(gc.Array_array)
-			nodr.Type = nodl.Type
-		}
-
-		gmove(&nodr, &nodl)
-
-		nodl.Xoffset += int64(gc.Array_nel) - int64(gc.Array_array)
-		nodl.Type = gc.Ptrto(gc.Types[gc.TUINT8])
-
-		if nr != nil {
-			nodr.Xoffset += int64(gc.Array_nel) - int64(gc.Array_array)
-			nodr.Type = nodl.Type
-		}
-
-		gmove(&nodr, &nodl)
-
-		goto yes
-
-	case gc.TSTRUCT:
-		if nl.Op == gc.ONAME {
-			gc.Gvardef(nl)
-		}
-		loffset := nodl.Xoffset
-		roffset := nodr.Xoffset
-
-		// funarg structs may not begin at offset zero.
-		if nl.Type.Etype == gc.TSTRUCT && nl.Type.Funarg != 0 && nl.Type.Type != nil {
-			loffset -= nl.Type.Type.Width
-		}
-		if nr != nil && nr.Type.Etype == gc.TSTRUCT && nr.Type.Funarg != 0 && nr.Type.Type != nil {
-			roffset -= nr.Type.Type.Width
-		}
-
-		for t := nl.Type.Type; t != nil; t = t.Down {
-			nodl.Xoffset = loffset + t.Width
-			nodl.Type = t.Type
-
-			if nr == nil {
-				gc.Clearslim(&nodl)
-			} else {
-				nodr.Xoffset = roffset + t.Width
-				nodr.Type = nodl.Type
-				gmove(&nodr, &nodl)
-			}
-		}
-
-		goto yes
-	}
-
-no:
-	if freer != 0 {
-		regfree(&nodr)
-	}
-	if freel != 0 {
-		regfree(&nodl)
-	}
-	return false
-
-yes:
-	if freer != 0 {
-		regfree(&nodr)
-	}
-	if freel != 0 {
-		regfree(&nodl)
-	}
-	return true
+	gc.Regfree(&dst)
+	gc.Regfree(&src)
+	gc.Regfree(&tmp)
 }
diff --git a/src/cmd/9g/galign.go b/src/cmd/9g/galign.go
index 99425c3..b9e6c32 100644
--- a/src/cmd/9g/galign.go
+++ b/src/cmd/9g/galign.go
@@ -5,10 +5,10 @@
 package main
 
 import (
+	"cmd/internal/gc"
 	"cmd/internal/obj"
 	"cmd/internal/obj/ppc64"
 )
-import "cmd/internal/gc"
 
 var thechar int = '9'
 
@@ -53,32 +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.Igen = igen
+	gc.Thearch.Ginscon = ginscon
+	gc.Thearch.Ginsnop = ginsnop
+	gc.Thearch.Gmove = gmove
 	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/ggen.go b/src/cmd/9g/ggen.go
index 2a3dbcb..a009186 100644
--- a/src/cmd/9g/ggen.go
+++ b/src/cmd/9g/ggen.go
@@ -5,11 +5,11 @@
 package main
 
 import (
+	"cmd/internal/gc"
 	"cmd/internal/obj"
 	"cmd/internal/obj/ppc64"
 	"fmt"
 )
-import "cmd/internal/gc"
 
 func defframe(ptxt *obj.Prog) {
 	var n *gc.Node
@@ -17,7 +17,7 @@
 	// fill in argument size, stack size
 	ptxt.To.Type = obj.TYPE_TEXTSIZE
 
-	ptxt.To.U.Argsize = int32(gc.Rnd(gc.Curfn.Type.Argwid, int64(gc.Widthptr)))
+	ptxt.To.Val = int32(gc.Rnd(gc.Curfn.Type.Argwid, int64(gc.Widthptr)))
 	frame := uint32(gc.Rnd(gc.Stksize+gc.Maxarg, int64(gc.Widthreg)))
 	ptxt.To.Offset = int64(frame)
 
@@ -30,9 +30,9 @@
 	lo := hi
 
 	// iterate through declarations - they are sorted in decreasing xoffset order.
-	for l := gc.Curfn.Dcl; l != nil; l = l.Next {
+	for l := gc.Curfn.Func.Dcl; l != nil; l = l.Next {
 		n = l.N
-		if n.Needzero == 0 {
+		if !n.Needzero {
 			continue
 		}
 		if n.Class != gc.PAUTO {
@@ -76,7 +76,7 @@
 		p.Reg = ppc64.REGSP
 		p = appendpp(p, obj.ADUFFZERO, obj.TYPE_NONE, 0, 0, obj.TYPE_MEM, 0, 0)
 		f := gc.Sysfunc("duffzero")
-		gc.Naddr(f, &p.To, 1)
+		gc.Naddr(&p.To, f)
 		gc.Afunclit(&p.To, f)
 		p.To.Offset = 4 * (128 - cnt/int64(gc.Widthptr))
 	} else {
@@ -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.REG_R0
-			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")
-	}
-
-	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] != 0 {
-		t = t.Type
-	}
-
-	var flist gc.Iter
-	fp := gc.Structfirst(&flist, gc.Getoutarg(t))
-	if fp == nil {
-		gc.Fatal("cgen_aret: nil")
-	}
-
-	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.
@@ -459,7 +139,7 @@
 
 	t0 := t
 	check := 0
-	if gc.Issigned[t.Etype] != 0 {
+	if gc.Issigned[t.Etype] {
 		check = 1
 		if gc.Isconst(nl, gc.CTINT) && gc.Mpgetfix(nl.Val.U.Xval) != -(1<<uint64(t.Width*8-1)) {
 			check = 0
@@ -469,7 +149,7 @@
 	}
 
 	if t.Width < 8 {
-		if gc.Issigned[t.Etype] != 0 {
+		if gc.Issigned[t.Etype] {
 			t = gc.Types[gc.TINT64]
 		} else {
 			t = gc.Types[gc.TUINT64]
@@ -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,36 +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)
-	goto longdiv
-
-	// division and mod using (slow) hardware instruction
-longdiv:
-	dodiv(op, nl, nr, res)
-
-	return
-}
-
-/*
  * generate high multiply:
  *   res = (nl*nr) >> width
  */
@@ -596,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,
@@ -618,7 +281,7 @@
 
 	case gc.TINT64,
 		gc.TUINT64:
-		if gc.Issigned[t.Etype] != 0 {
+		if gc.Issigned[t.Etype] {
 			gins(ppc64.AMULHD, &n2, &n1)
 		} else {
 			gins(ppc64.AMULHDU, &n2, &n1)
@@ -628,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)
 }
 
 /*
@@ -639,17 +302,12 @@
  *	res = nl >> nr
  */
 func cgen_shift(op int, bounded bool, nl *gc.Node, nr *gc.Node, res *gc.Node) {
-	var n1 gc.Node
-	var n2 gc.Node
-	var n3 gc.Node
-	var tcount *gc.Type
-
 	a := int(optoas(op, nl.Type))
 
 	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
@@ -662,56 +320,59 @@
 			gins(a, nr, &n1)
 		}
 		gmove(&n1, res)
-		regfree(&n1)
-		goto ret
+		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
 	}
 
 	// Allow either uint32 or uint64 as shift type,
 	// to avoid unnecessary conversion from uint32 to uint64
 	// just to do the comparison.
-	tcount = gc.Types[gc.Simtype[nr.Type.Etype]]
+	tcount := gc.Types[gc.Simtype[nr.Type.Etype]]
 
 	if tcount.Etype < gc.TUINT32 {
 		tcount = gc.Types[gc.TUINT32]
 	}
 
-	regalloc(&n1, nr.Type, nil) // to hold the shift type in CX
-	regalloc(&n3, tcount, &n1)  // to clear high bits of CX
+	var n1 gc.Node
+	gc.Regalloc(&n1, nr.Type, nil) // to hold the shift type in CX
+	var n3 gc.Node
+	gc.Regalloc(&n3, tcount, &n1) // to clear high bits of CX
 
-	regalloc(&n2, nl.Type, res)
+	var n2 gc.Node
+	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 {
 		gc.Nodconst(&n3, tcount, nl.Type.Width*8)
 		gins(optoas(gc.OCMP, tcount), &n1, &n3)
 		p1 := (*obj.Prog)(gc.Gbranch(optoas(gc.OLT, tcount), nil, +1))
-		if op == gc.ORSH && gc.Issigned[nl.Type.Etype] != 0 {
+		if op == gc.ORSH && gc.Issigned[nl.Type.Etype] {
 			gc.Nodconst(&n3, gc.Types[gc.TUINT32], nl.Type.Width*8-1)
 			gins(a, &n3, &n2)
 		} else {
@@ -726,10 +387,8 @@
 
 	gmove(&n2, res)
 
-	regfree(&n1)
-	regfree(&n2)
-
-ret:
+	gc.Regfree(&n1)
+	gc.Regfree(&n2)
 }
 
 func clearfat(nl *gc.Node) {
@@ -741,32 +400,32 @@
 	w := uint64(uint64(nl.Type.Width))
 
 	// Avoid taking the address for simple enough types.
-	//if(componentgen(N, nl))
-	//	return;
+	if gc.Componentgen(nil, nl) {
+		return
+	}
 
 	c := uint64(w % 8) // bytes
 	q := uint64(w / 8) // dwords
 
-	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.REG_R0) // r0 is always zero
+	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
-	var p *obj.Prog
 	if q > 128 {
-		p = gins(ppc64.ASUB, nil, &dst)
+		p := gins(ppc64.ASUB, nil, &dst)
 		p.From.Type = obj.TYPE_CONST
 		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)
@@ -779,12 +438,12 @@
 		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
 	} else if q >= 4 {
-		p = gins(ppc64.ASUB, nil, &dst)
+		p := gins(ppc64.ASUB, nil, &dst)
 		p.From.Type = obj.TYPE_CONST
 		p.From.Offset = 8
 		f := (*gc.Node)(gc.Sysfunc("duffzero"))
@@ -797,6 +456,7 @@
 		// duffzero leaves R3 on the last zeroed dword
 		boff = 8
 	} else {
+		var p *obj.Prog
 		for t := uint64(0); t < q; t++ {
 			p = gins(ppc64.AMOVD, &r0, &dst)
 			p.To.Type = obj.TYPE_MEM
@@ -806,13 +466,14 @@
 		boff = 8 * q
 	}
 
+	var p *obj.Prog
 	for t := uint64(0); t < c; t++ {
 		p = gins(ppc64.AMOVB, &r0, &dst)
 		p.To.Type = obj.TYPE_MEM
 		p.To.Offset = int64(t + boff)
 	}
 
-	reg[ppc64.REGRT1-ppc64.REG_R0]--
+	gc.Regfree(&dst)
 }
 
 // Called after regopt and peep have run.
@@ -847,7 +508,7 @@
 			p->from.type = TYPE_CONST;
 			p->from.offset = 4;
 			p->from.reg = 0;
-			p->reg = REG_R0;
+			p->reg = REGZERO;
 			p->to.type = TYPE_REG;
 			p->to.reg = reg;
 		*/
@@ -876,15 +537,15 @@
 		//p1->from.offset = 1; // likely
 		p1.To.Type = obj.TYPE_BRANCH
 
-		p1.To.U.Branch = p2.Link
+		p1.To.Val = p2.Link
 
 		// crash by write to memory address 0.
 		p2.As = ppc64.AMOVD
 
 		p2.From.Type = obj.TYPE_REG
-		p2.From.Reg = ppc64.REG_R0
+		p2.From.Reg = ppc64.REGZERO
 		p2.To.Type = obj.TYPE_MEM
-		p2.To.Reg = ppc64.REG_R0
+		p2.To.Reg = ppc64.REGZERO
 		p2.To.Offset = 0
 	}
 }
diff --git a/src/cmd/9g/gsubr.go b/src/cmd/9g/gsubr.go
index 74a312a..5a6fd29 100644
--- a/src/cmd/9g/gsubr.go
+++ b/src/cmd/9g/gsubr.go
@@ -31,11 +31,11 @@
 package main
 
 import (
+	"cmd/internal/gc"
 	"cmd/internal/obj"
 	"cmd/internal/obj/ppc64"
 	"fmt"
 )
-import "cmd/internal/gc"
 
 // TODO(rsc): Can make this bigger if we move
 // the text segment up higher in 6l for all GOOS.
@@ -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)
 }
 
 /*
@@ -325,7 +160,7 @@
 	tt := int(gc.Simsimtype(t.Type))
 	cvt := (*gc.Type)(t.Type)
 
-	if gc.Iscomplex[ft] != 0 || gc.Iscomplex[tt] != 0 {
+	if gc.Iscomplex[ft] || gc.Iscomplex[tt] {
 		gc.Complexmove(f, t)
 		return
 	}
@@ -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
 
 		/*
@@ -669,47 +504,104 @@
 
 	// requires register destination
 rdst:
-	regalloc(&r1, t.Type, t)
+	{
+		gc.Regalloc(&r1, t.Type, t)
 
-	gins(a, f, &r1)
-	gmove(&r1, t)
-	regfree(&r1)
-	return
+		gins(a, f, &r1)
+		gmove(&r1, t)
+		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)
 
-	af := obj.Addr(obj.Addr{})
+	p := gc.Prog(as)
+	gc.Naddr(&p.From, f)
+	gc.Naddr(&p.To, t)
 
-	at := obj.Addr(obj.Addr{})
-	if f != nil {
-		gc.Naddr(f, &af, 1)
+	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 t != nil {
-		gc.Naddr(t, &at, 1)
-	}
-	p := (*obj.Prog)(gc.Prog(as))
-	if f != nil {
-		p.From = af
-	}
-	if t != nil {
-		p.To = at
-	}
+
 	if gc.Debug['g'] != 0 {
 		fmt.Printf("%v\n", p)
 	}
@@ -736,16 +628,16 @@
 
 	case ppc64.AMOVD,
 		ppc64.AMOVDU:
-		if af.Type == obj.TYPE_CONST || af.Type == obj.TYPE_ADDR {
+		if p.From.Type == obj.TYPE_CONST || p.From.Type == obj.TYPE_ADDR {
 			break
 		}
 		w = 8
 	}
 
-	if w != 0 && ((f != nil && af.Width < int64(w)) || (t != nil && at.Type != obj.TYPE_REG && at.Width > int64(w))) {
+	if w != 0 && ((f != nil && p.From.Width < int64(w)) || (t != nil && p.To.Type != obj.TYPE_REG && p.To.Width > int64(w))) {
 		gc.Dump("f", f)
 		gc.Dump("t", t)
-		gc.Fatal("bad width: %v (%d, %d)\n", p, af.Width, at.Width)
+		gc.Fatal("bad width: %v (%d, %d)\n", p, p.From.Width, p.To.Width)
 	}
 
 	return p
@@ -841,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,
@@ -866,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/9g/opt.go b/src/cmd/9g/opt.go
index a029420..4a134f1 100644
--- a/src/cmd/9g/opt.go
+++ b/src/cmd/9g/opt.go
@@ -1,42 +1,12 @@
-// Derived from Inferno utils/6c/peep.c
-// http://code.google.com/p/inferno-os/source/browse/utils/6c/peep.c
-//
-//	Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
-//	Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
-//	Portions Copyright © 1997-1999 Vita Nuova Limited
-//	Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
-//	Portions Copyright © 2004,2006 Bruce Ellis
-//	Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
-//	Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
-//	Portions Copyright © 2009 The Go Authors.  All rights reserved.
-//
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files (the "Software"), to deal
-// in the Software without restriction, including without limitation the rights
-// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-// copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-// THE SOFTWARE.
-
-package main
-
 // 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.
 
+package main
+
 // Many Power ISA arithmetic and logical instructions come in four
 // standard variants.  These bits let us map between variants.
 const (
-	V_CC = 1 << 0
-	V_V  = 1 << 1
+	V_CC = 1 << 0 // xCC (affect CR field 0 flags)
+	V_V  = 1 << 1 // xV (affect SO and OV flags)
 )
diff --git a/src/cmd/9g/peep.go b/src/cmd/9g/peep.go
index f7c0a95..6992968 100644
--- a/src/cmd/9g/peep.go
+++ b/src/cmd/9g/peep.go
@@ -31,11 +31,11 @@
 package main
 
 import (
+	"cmd/internal/gc"
 	"cmd/internal/obj"
 	"cmd/internal/obj/ppc64"
 	"fmt"
 )
-import "cmd/internal/gc"
 
 var gactive uint32
 
@@ -407,9 +407,7 @@
 	if !regtyp(v2) {
 		return false
 	}
-	var r *gc.Flow
-	var info gc.ProgInfo
-	for r = gc.Uniqp(r0); r != nil; r = gc.Uniqp(r) {
+	for r := gc.Uniqp(r0); r != nil; r = gc.Uniqp(r) {
 		if gc.Uniqs(r) == nil {
 			break
 		}
@@ -417,15 +415,39 @@
 		if p.As == obj.AVARDEF || p.As == obj.AVARKILL {
 			continue
 		}
-		proginfo(&info, p)
-		if info.Flags&gc.Call != 0 {
+		if p.Info.Flags&gc.Call != 0 {
 			return false
 		}
 
-		if info.Flags&(gc.RightRead|gc.RightWrite) == gc.RightWrite {
+		if p.Info.Flags&(gc.RightRead|gc.RightWrite) == gc.RightWrite {
 			if p.To.Type == v1.Type {
 				if p.To.Reg == v1.Reg {
-					goto gotit
+					copysub(&p.To, v1, v2, 1)
+					if gc.Debug['P'] != 0 {
+						fmt.Printf("gotit: %v->%v\n%v", gc.Ctxt.Dconv(v1), gc.Ctxt.Dconv(v2), r.Prog)
+						if p.From.Type == v2.Type {
+							fmt.Printf(" excise")
+						}
+						fmt.Printf("\n")
+					}
+
+					for r = gc.Uniqs(r); r != r0; r = gc.Uniqs(r) {
+						p = r.Prog
+						copysub(&p.From, v1, v2, 1)
+						copysub1(p, v1, v2, 1)
+						copysub(&p.To, v1, v2, 1)
+						if gc.Debug['P'] != 0 {
+							fmt.Printf("%v\n", r.Prog)
+						}
+					}
+
+					t := int(int(v1.Reg))
+					v1.Reg = v2.Reg
+					v2.Reg = int16(t)
+					if gc.Debug['P'] != 0 {
+						fmt.Printf("%v last\n", r.Prog)
+					}
+					return true
 				}
 			}
 		}
@@ -439,34 +461,6 @@
 	}
 
 	return false
-
-gotit:
-	copysub(&p.To, v1, v2, 1)
-	if gc.Debug['P'] != 0 {
-		fmt.Printf("gotit: %v->%v\n%v", gc.Ctxt.Dconv(v1), gc.Ctxt.Dconv(v2), r.Prog)
-		if p.From.Type == v2.Type {
-			fmt.Printf(" excise")
-		}
-		fmt.Printf("\n")
-	}
-
-	for r = gc.Uniqs(r); r != r0; r = gc.Uniqs(r) {
-		p = r.Prog
-		copysub(&p.From, v1, v2, 1)
-		copysub1(p, v1, v2, 1)
-		copysub(&p.To, v1, v2, 1)
-		if gc.Debug['P'] != 0 {
-			fmt.Printf("%v\n", r.Prog)
-		}
-	}
-
-	t := int(int(v1.Reg))
-	v1.Reg = v2.Reg
-	v2.Reg = int16(t)
-	if gc.Debug['P'] != 0 {
-		fmt.Printf("%v last\n", r.Prog)
-	}
-	return true
 }
 
 /*
@@ -619,7 +613,7 @@
 
 	switch p.As {
 	default:
-		fmt.Printf("copyu: can't find %v\n", ppc64.Aconv(int(p.As)))
+		fmt.Printf("copyu: can't find %v\n", obj.Aconv(int(p.As)))
 		return 2
 
 	case obj.ANOP, /* read p->from, write p->to */
diff --git a/src/cmd/9g/prog.go b/src/cmd/9g/prog.go
index b971256..e28e389 100644
--- a/src/cmd/9g/prog.go
+++ b/src/cmd/9g/prog.go
@@ -5,10 +5,10 @@
 package main
 
 import (
+	"cmd/internal/gc"
 	"cmd/internal/obj"
 	"cmd/internal/obj/ppc64"
 )
-import "cmd/internal/gc"
 
 const (
 	LeftRdwr  uint32 = gc.LeftRead | gc.LeftWrite
@@ -24,84 +24,84 @@
 // size variants of an operation even if we just use a subset.
 //
 // The table is formatted for 8-space tabs.
-var progtable = [ppc64.ALAST]gc.ProgInfo{
-	obj.ATYPE:     gc.ProgInfo{gc.Pseudo | gc.Skip, 0, 0, 0},
-	obj.ATEXT:     gc.ProgInfo{gc.Pseudo, 0, 0, 0},
-	obj.AFUNCDATA: gc.ProgInfo{gc.Pseudo, 0, 0, 0},
-	obj.APCDATA:   gc.ProgInfo{gc.Pseudo, 0, 0, 0},
-	obj.AUNDEF:    gc.ProgInfo{gc.Break, 0, 0, 0},
-	obj.AUSEFIELD: gc.ProgInfo{gc.OK, 0, 0, 0},
-	obj.ACHECKNIL: gc.ProgInfo{gc.LeftRead, 0, 0, 0},
-	obj.AVARDEF:   gc.ProgInfo{gc.Pseudo | gc.RightWrite, 0, 0, 0},
-	obj.AVARKILL:  gc.ProgInfo{gc.Pseudo | gc.RightWrite, 0, 0, 0},
+var progtable = [ppc64.ALAST]obj.ProgInfo{
+	obj.ATYPE:     {gc.Pseudo | gc.Skip, 0, 0, 0},
+	obj.ATEXT:     {gc.Pseudo, 0, 0, 0},
+	obj.AFUNCDATA: {gc.Pseudo, 0, 0, 0},
+	obj.APCDATA:   {gc.Pseudo, 0, 0, 0},
+	obj.AUNDEF:    {gc.Break, 0, 0, 0},
+	obj.AUSEFIELD: {gc.OK, 0, 0, 0},
+	obj.ACHECKNIL: {gc.LeftRead, 0, 0, 0},
+	obj.AVARDEF:   {gc.Pseudo | gc.RightWrite, 0, 0, 0},
+	obj.AVARKILL:  {gc.Pseudo | gc.RightWrite, 0, 0, 0},
 
 	// NOP is an internal no-op that also stands
 	// for USED and SET annotations, not the Power opcode.
-	obj.ANOP: gc.ProgInfo{gc.LeftRead | gc.RightWrite, 0, 0, 0},
+	obj.ANOP: {gc.LeftRead | gc.RightWrite, 0, 0, 0},
 
 	// Integer
-	ppc64.AADD:    gc.ProgInfo{gc.SizeQ | gc.LeftRead | gc.RegRead | gc.RightWrite, 0, 0, 0},
-	ppc64.ASUB:    gc.ProgInfo{gc.SizeQ | gc.LeftRead | gc.RegRead | gc.RightWrite, 0, 0, 0},
-	ppc64.ANEG:    gc.ProgInfo{gc.SizeQ | gc.LeftRead | gc.RegRead | gc.RightWrite, 0, 0, 0},
-	ppc64.AAND:    gc.ProgInfo{gc.SizeQ | gc.LeftRead | gc.RegRead | gc.RightWrite, 0, 0, 0},
-	ppc64.AOR:     gc.ProgInfo{gc.SizeQ | gc.LeftRead | gc.RegRead | gc.RightWrite, 0, 0, 0},
-	ppc64.AXOR:    gc.ProgInfo{gc.SizeQ | gc.LeftRead | gc.RegRead | gc.RightWrite, 0, 0, 0},
-	ppc64.AMULLD:  gc.ProgInfo{gc.SizeQ | gc.LeftRead | gc.RegRead | gc.RightWrite, 0, 0, 0},
-	ppc64.AMULLW:  gc.ProgInfo{gc.SizeL | gc.LeftRead | gc.RegRead | gc.RightWrite, 0, 0, 0},
-	ppc64.AMULHD:  gc.ProgInfo{gc.SizeL | gc.LeftRead | gc.RegRead | gc.RightWrite, 0, 0, 0},
-	ppc64.AMULHDU: gc.ProgInfo{gc.SizeL | gc.LeftRead | gc.RegRead | gc.RightWrite, 0, 0, 0},
-	ppc64.ADIVD:   gc.ProgInfo{gc.SizeQ | gc.LeftRead | gc.RegRead | gc.RightWrite, 0, 0, 0},
-	ppc64.ADIVDU:  gc.ProgInfo{gc.SizeQ | gc.LeftRead | gc.RegRead | gc.RightWrite, 0, 0, 0},
-	ppc64.ASLD:    gc.ProgInfo{gc.SizeQ | gc.LeftRead | gc.RegRead | gc.RightWrite, 0, 0, 0},
-	ppc64.ASRD:    gc.ProgInfo{gc.SizeQ | gc.LeftRead | gc.RegRead | gc.RightWrite, 0, 0, 0},
-	ppc64.ASRAD:   gc.ProgInfo{gc.SizeQ | gc.LeftRead | gc.RegRead | gc.RightWrite, 0, 0, 0},
-	ppc64.ACMP:    gc.ProgInfo{gc.SizeQ | gc.LeftRead | gc.RightRead, 0, 0, 0},
-	ppc64.ACMPU:   gc.ProgInfo{gc.SizeQ | gc.LeftRead | gc.RightRead, 0, 0, 0},
-	ppc64.ATD:     gc.ProgInfo{gc.SizeQ | gc.RightRead, 0, 0, 0},
+	ppc64.AADD:    {gc.SizeQ | gc.LeftRead | gc.RegRead | gc.RightWrite, 0, 0, 0},
+	ppc64.ASUB:    {gc.SizeQ | gc.LeftRead | gc.RegRead | gc.RightWrite, 0, 0, 0},
+	ppc64.ANEG:    {gc.SizeQ | gc.LeftRead | gc.RegRead | gc.RightWrite, 0, 0, 0},
+	ppc64.AAND:    {gc.SizeQ | gc.LeftRead | gc.RegRead | gc.RightWrite, 0, 0, 0},
+	ppc64.AOR:     {gc.SizeQ | gc.LeftRead | gc.RegRead | gc.RightWrite, 0, 0, 0},
+	ppc64.AXOR:    {gc.SizeQ | gc.LeftRead | gc.RegRead | gc.RightWrite, 0, 0, 0},
+	ppc64.AMULLD:  {gc.SizeQ | gc.LeftRead | gc.RegRead | gc.RightWrite, 0, 0, 0},
+	ppc64.AMULLW:  {gc.SizeL | gc.LeftRead | gc.RegRead | gc.RightWrite, 0, 0, 0},
+	ppc64.AMULHD:  {gc.SizeL | gc.LeftRead | gc.RegRead | gc.RightWrite, 0, 0, 0},
+	ppc64.AMULHDU: {gc.SizeL | gc.LeftRead | gc.RegRead | gc.RightWrite, 0, 0, 0},
+	ppc64.ADIVD:   {gc.SizeQ | gc.LeftRead | gc.RegRead | gc.RightWrite, 0, 0, 0},
+	ppc64.ADIVDU:  {gc.SizeQ | gc.LeftRead | gc.RegRead | gc.RightWrite, 0, 0, 0},
+	ppc64.ASLD:    {gc.SizeQ | gc.LeftRead | gc.RegRead | gc.RightWrite, 0, 0, 0},
+	ppc64.ASRD:    {gc.SizeQ | gc.LeftRead | gc.RegRead | gc.RightWrite, 0, 0, 0},
+	ppc64.ASRAD:   {gc.SizeQ | gc.LeftRead | gc.RegRead | gc.RightWrite, 0, 0, 0},
+	ppc64.ACMP:    {gc.SizeQ | gc.LeftRead | gc.RightRead, 0, 0, 0},
+	ppc64.ACMPU:   {gc.SizeQ | gc.LeftRead | gc.RightRead, 0, 0, 0},
+	ppc64.ATD:     {gc.SizeQ | gc.RightRead, 0, 0, 0},
 
 	// Floating point.
-	ppc64.AFADD:   gc.ProgInfo{gc.SizeD | gc.LeftRead | gc.RegRead | gc.RightWrite, 0, 0, 0},
-	ppc64.AFADDS:  gc.ProgInfo{gc.SizeF | gc.LeftRead | gc.RegRead | gc.RightWrite, 0, 0, 0},
-	ppc64.AFSUB:   gc.ProgInfo{gc.SizeD | gc.LeftRead | gc.RegRead | gc.RightWrite, 0, 0, 0},
-	ppc64.AFSUBS:  gc.ProgInfo{gc.SizeF | gc.LeftRead | gc.RegRead | gc.RightWrite, 0, 0, 0},
-	ppc64.AFMUL:   gc.ProgInfo{gc.SizeD | gc.LeftRead | gc.RegRead | gc.RightWrite, 0, 0, 0},
-	ppc64.AFMULS:  gc.ProgInfo{gc.SizeF | gc.LeftRead | gc.RegRead | gc.RightWrite, 0, 0, 0},
-	ppc64.AFDIV:   gc.ProgInfo{gc.SizeD | gc.LeftRead | gc.RegRead | gc.RightWrite, 0, 0, 0},
-	ppc64.AFDIVS:  gc.ProgInfo{gc.SizeF | gc.LeftRead | gc.RegRead | gc.RightWrite, 0, 0, 0},
-	ppc64.AFCTIDZ: gc.ProgInfo{gc.SizeF | gc.LeftRead | gc.RegRead | gc.RightWrite, 0, 0, 0},
-	ppc64.AFCFID:  gc.ProgInfo{gc.SizeF | gc.LeftRead | gc.RegRead | gc.RightWrite, 0, 0, 0},
-	ppc64.AFCMPU:  gc.ProgInfo{gc.SizeD | gc.LeftRead | gc.RightRead, 0, 0, 0},
-	ppc64.AFRSP:   gc.ProgInfo{gc.SizeD | gc.LeftRead | gc.RightWrite | gc.Conv, 0, 0, 0},
+	ppc64.AFADD:   {gc.SizeD | gc.LeftRead | gc.RegRead | gc.RightWrite, 0, 0, 0},
+	ppc64.AFADDS:  {gc.SizeF | gc.LeftRead | gc.RegRead | gc.RightWrite, 0, 0, 0},
+	ppc64.AFSUB:   {gc.SizeD | gc.LeftRead | gc.RegRead | gc.RightWrite, 0, 0, 0},
+	ppc64.AFSUBS:  {gc.SizeF | gc.LeftRead | gc.RegRead | gc.RightWrite, 0, 0, 0},
+	ppc64.AFMUL:   {gc.SizeD | gc.LeftRead | gc.RegRead | gc.RightWrite, 0, 0, 0},
+	ppc64.AFMULS:  {gc.SizeF | gc.LeftRead | gc.RegRead | gc.RightWrite, 0, 0, 0},
+	ppc64.AFDIV:   {gc.SizeD | gc.LeftRead | gc.RegRead | gc.RightWrite, 0, 0, 0},
+	ppc64.AFDIVS:  {gc.SizeF | gc.LeftRead | gc.RegRead | gc.RightWrite, 0, 0, 0},
+	ppc64.AFCTIDZ: {gc.SizeF | gc.LeftRead | gc.RegRead | gc.RightWrite, 0, 0, 0},
+	ppc64.AFCFID:  {gc.SizeF | gc.LeftRead | gc.RegRead | gc.RightWrite, 0, 0, 0},
+	ppc64.AFCMPU:  {gc.SizeD | gc.LeftRead | gc.RightRead, 0, 0, 0},
+	ppc64.AFRSP:   {gc.SizeD | gc.LeftRead | gc.RightWrite | gc.Conv, 0, 0, 0},
 
 	// Moves
-	ppc64.AMOVB:  gc.ProgInfo{gc.SizeB | gc.LeftRead | gc.RightWrite | gc.Move | gc.Conv, 0, 0, 0},
-	ppc64.AMOVBU: gc.ProgInfo{gc.SizeB | gc.LeftRead | gc.RightWrite | gc.Move | gc.Conv | gc.PostInc, 0, 0, 0},
-	ppc64.AMOVBZ: gc.ProgInfo{gc.SizeB | gc.LeftRead | gc.RightWrite | gc.Move | gc.Conv, 0, 0, 0},
-	ppc64.AMOVH:  gc.ProgInfo{gc.SizeW | gc.LeftRead | gc.RightWrite | gc.Move | gc.Conv, 0, 0, 0},
-	ppc64.AMOVHU: gc.ProgInfo{gc.SizeW | gc.LeftRead | gc.RightWrite | gc.Move | gc.Conv | gc.PostInc, 0, 0, 0},
-	ppc64.AMOVHZ: gc.ProgInfo{gc.SizeW | gc.LeftRead | gc.RightWrite | gc.Move | gc.Conv, 0, 0, 0},
-	ppc64.AMOVW:  gc.ProgInfo{gc.SizeL | gc.LeftRead | gc.RightWrite | gc.Move | gc.Conv, 0, 0, 0},
+	ppc64.AMOVB:  {gc.SizeB | gc.LeftRead | gc.RightWrite | gc.Move | gc.Conv, 0, 0, 0},
+	ppc64.AMOVBU: {gc.SizeB | gc.LeftRead | gc.RightWrite | gc.Move | gc.Conv | gc.PostInc, 0, 0, 0},
+	ppc64.AMOVBZ: {gc.SizeB | gc.LeftRead | gc.RightWrite | gc.Move | gc.Conv, 0, 0, 0},
+	ppc64.AMOVH:  {gc.SizeW | gc.LeftRead | gc.RightWrite | gc.Move | gc.Conv, 0, 0, 0},
+	ppc64.AMOVHU: {gc.SizeW | gc.LeftRead | gc.RightWrite | gc.Move | gc.Conv | gc.PostInc, 0, 0, 0},
+	ppc64.AMOVHZ: {gc.SizeW | gc.LeftRead | gc.RightWrite | gc.Move | gc.Conv, 0, 0, 0},
+	ppc64.AMOVW:  {gc.SizeL | gc.LeftRead | gc.RightWrite | gc.Move | gc.Conv, 0, 0, 0},
 
 	// there is no AMOVWU.
-	ppc64.AMOVWZU: gc.ProgInfo{gc.SizeL | gc.LeftRead | gc.RightWrite | gc.Move | gc.Conv | gc.PostInc, 0, 0, 0},
-	ppc64.AMOVWZ:  gc.ProgInfo{gc.SizeL | gc.LeftRead | gc.RightWrite | gc.Move | gc.Conv, 0, 0, 0},
-	ppc64.AMOVD:   gc.ProgInfo{gc.SizeQ | gc.LeftRead | gc.RightWrite | gc.Move, 0, 0, 0},
-	ppc64.AMOVDU:  gc.ProgInfo{gc.SizeQ | gc.LeftRead | gc.RightWrite | gc.Move | gc.PostInc, 0, 0, 0},
-	ppc64.AFMOVS:  gc.ProgInfo{gc.SizeF | gc.LeftRead | gc.RightWrite | gc.Move | gc.Conv, 0, 0, 0},
-	ppc64.AFMOVD:  gc.ProgInfo{gc.SizeD | gc.LeftRead | gc.RightWrite | gc.Move, 0, 0, 0},
+	ppc64.AMOVWZU: {gc.SizeL | gc.LeftRead | gc.RightWrite | gc.Move | gc.Conv | gc.PostInc, 0, 0, 0},
+	ppc64.AMOVWZ:  {gc.SizeL | gc.LeftRead | gc.RightWrite | gc.Move | gc.Conv, 0, 0, 0},
+	ppc64.AMOVD:   {gc.SizeQ | gc.LeftRead | gc.RightWrite | gc.Move, 0, 0, 0},
+	ppc64.AMOVDU:  {gc.SizeQ | gc.LeftRead | gc.RightWrite | gc.Move | gc.PostInc, 0, 0, 0},
+	ppc64.AFMOVS:  {gc.SizeF | gc.LeftRead | gc.RightWrite | gc.Move | gc.Conv, 0, 0, 0},
+	ppc64.AFMOVD:  {gc.SizeD | gc.LeftRead | gc.RightWrite | gc.Move, 0, 0, 0},
 
 	// Jumps
-	ppc64.ABR:     gc.ProgInfo{gc.Jump | gc.Break, 0, 0, 0},
-	ppc64.ABL:     gc.ProgInfo{gc.Call, 0, 0, 0},
-	ppc64.ABEQ:    gc.ProgInfo{gc.Cjmp, 0, 0, 0},
-	ppc64.ABNE:    gc.ProgInfo{gc.Cjmp, 0, 0, 0},
-	ppc64.ABGE:    gc.ProgInfo{gc.Cjmp, 0, 0, 0},
-	ppc64.ABLT:    gc.ProgInfo{gc.Cjmp, 0, 0, 0},
-	ppc64.ABGT:    gc.ProgInfo{gc.Cjmp, 0, 0, 0},
-	ppc64.ABLE:    gc.ProgInfo{gc.Cjmp, 0, 0, 0},
-	ppc64.ARETURN: gc.ProgInfo{gc.Break, 0, 0, 0},
-	obj.ADUFFZERO: gc.ProgInfo{gc.Call, 0, 0, 0},
-	obj.ADUFFCOPY: gc.ProgInfo{gc.Call, 0, 0, 0},
+	ppc64.ABR:     {gc.Jump | gc.Break, 0, 0, 0},
+	ppc64.ABL:     {gc.Call, 0, 0, 0},
+	ppc64.ABEQ:    {gc.Cjmp, 0, 0, 0},
+	ppc64.ABNE:    {gc.Cjmp, 0, 0, 0},
+	ppc64.ABGE:    {gc.Cjmp, 0, 0, 0},
+	ppc64.ABLT:    {gc.Cjmp, 0, 0, 0},
+	ppc64.ABGT:    {gc.Cjmp, 0, 0, 0},
+	ppc64.ABLE:    {gc.Cjmp, 0, 0, 0},
+	ppc64.ARETURN: {gc.Break, 0, 0, 0},
+	obj.ADUFFZERO: {gc.Call, 0, 0, 0},
+	obj.ADUFFCOPY: {gc.Call, 0, 0, 0},
 }
 
 var initproginfo_initialized int
@@ -133,12 +133,12 @@
 	}
 }
 
-func proginfo(info *gc.ProgInfo, p *obj.Prog) {
+func proginfo(p *obj.Prog) {
 	initproginfo()
 
+	info := &p.Info
 	*info = progtable[p.As]
 	if info.Flags == 0 {
-		*info = progtable[ppc64.AADD]
 		gc.Fatal("proginfo: unknown instruction %v", p)
 	}
 
@@ -302,7 +302,7 @@
 			return i
 		}
 	}
-	gc.Fatal("as2variant: instruction %v is not a variant of itself", ppc64.Aconv(as))
+	gc.Fatal("as2variant: instruction %v is not a variant of itself", obj.Aconv(as))
 	return 0
 }
 
diff --git a/src/cmd/9g/reg.go b/src/cmd/9g/reg.go
index b1b681a..fb0c2e3 100644
--- a/src/cmd/9g/reg.go
+++ b/src/cmd/9g/reg.go
@@ -34,7 +34,7 @@
 import "cmd/internal/gc"
 
 const (
-	NREGVAR = 64
+	NREGVAR = 64 /* 32 general + 32 floating */
 )
 
 var regname = []string{
diff --git a/src/cmd/9l/asm.go b/src/cmd/9l/asm.go
index 3197f51..a32b39c 100644
--- a/src/cmd/9l/asm.go
+++ b/src/cmd/9l/asm.go
@@ -31,24 +31,22 @@
 package main
 
 import (
+	"cmd/internal/ld"
 	"cmd/internal/obj"
+	"encoding/binary"
 	"fmt"
 	"log"
 )
-import "cmd/internal/ld"
 
 func needlib(name string) int {
-	var p string
-	var s *ld.LSym
-
 	if name[0] == '\x00' {
 		return 0
 	}
 
 	/* reuse hash code in symbol table */
-	p = fmt.Sprintf(".dynlib.%s", name)
+	p := fmt.Sprintf(".dynlib.%s", name)
 
-	s = ld.Linklookup(ld.Ctxt, p, 0)
+	s := ld.Linklookup(ld.Ctxt, p, 0)
 
 	if s.Type == 0 {
 		s.Type = 100 // avoid SDATA, etc.
@@ -117,7 +115,7 @@
 	// us to save and restore the TOC pointer.
 	pprevtextp = &ld.Ctxt.Textp
 
-	for s = *pprevtextp; s != nil; (func() { pprevtextp = &s.Next; s = *pprevtextp })() {
+	for s = *pprevtextp; s != nil; pprevtextp, s = &s.Next, s.Next {
 		for i = range s.R {
 			r = &s.R[i]
 			if r.Type != 256+ld.R_PPC64_REL24 || r.Sym.Type != ld.SDYNIMPORT {
@@ -154,7 +152,7 @@
 			// Restore TOC after bl.  The compiler put a
 			// nop here for us to overwrite.
 			o1 = 0xe8410018 // ld r2,24(r1)
-			ld.Ctxt.Arch.ByteOrder.PutUint32(s.P[r.Off:], o1)
+			ld.Ctxt.Arch.ByteOrder.PutUint32(s.P[r.Off+4:], o1)
 		}
 	}
 }
@@ -162,16 +160,13 @@
 // Construct a call stub in stub that calls symbol targ via its PLT
 // entry.
 func gencallstub(abicase int, stub *ld.LSym, targ *ld.LSym) {
-	var plt *ld.LSym
-	var r *ld.Reloc
-
 	if abicase != 1 {
 		// If we see R_PPC64_TOCSAVE or R_PPC64_REL24_NOTOC
 		// relocations, we'll need to implement cases 2 and 3.
 		log.Fatalf("gencallstub only implements case 1 calls")
 	}
 
-	plt = ld.Linklookup(ld.Ctxt, ".plt", 0)
+	plt := ld.Linklookup(ld.Ctxt, ".plt", 0)
 
 	stub.Type = ld.STEXT
 
@@ -179,13 +174,13 @@
 	ld.Adduint32(ld.Ctxt, stub, 0xf8410018) // std r2,24(r1)
 
 	// Load the function pointer from the PLT.
-	r = ld.Addrel(stub)
+	r := ld.Addrel(stub)
 
 	r.Off = int32(stub.Size)
 	r.Sym = plt
 	r.Add = int64(targ.Plt)
 	r.Siz = 2
-	if ld.Ctxt.Arch.Endian == ld.BigEndian {
+	if ld.Ctxt.Arch.ByteOrder == binary.BigEndian {
 		r.Off += int32(r.Siz)
 	}
 	r.Type = ld.R_POWER_TOC
@@ -196,7 +191,7 @@
 	r.Sym = plt
 	r.Add = int64(targ.Plt)
 	r.Siz = 2
-	if ld.Ctxt.Arch.Endian == ld.BigEndian {
+	if ld.Ctxt.Arch.ByteOrder == binary.BigEndian {
 		r.Off += int32(r.Siz)
 	}
 	r.Type = ld.R_POWER_TOC
@@ -213,10 +208,7 @@
 }
 
 func adddynrel(s *ld.LSym, r *ld.Reloc) {
-	var targ *ld.LSym
-	var rela *ld.LSym
-
-	targ = r.Sym
+	targ := r.Sym
 	ld.Ctxt.Cursym = s
 
 	switch r.Type {
@@ -250,7 +242,7 @@
 			// These happen in .toc sections
 			adddynsym(ld.Ctxt, targ)
 
-			rela = ld.Linklookup(ld.Ctxt, ".rela", 0)
+			rela := ld.Linklookup(ld.Ctxt, ".rela", 0)
 			ld.Addaddrplus(ld.Ctxt, rela, s, int64(r.Off))
 			ld.Adduint64(ld.Ctxt, rela, ld.ELF64_R_INFO(uint32(targ.Dynid), ld.R_PPC64_ADDR64))
 			ld.Adduint64(ld.Ctxt, rela, uint64(r.Add))
@@ -324,9 +316,7 @@
 }
 
 func elfsetupplt() {
-	var plt *ld.LSym
-
-	plt = ld.Linklookup(ld.Ctxt, ".plt", 0)
+	plt := ld.Linklookup(ld.Ctxt, ".plt", 0)
 	if plt.Size == 0 {
 		// The dynamic linker stores the address of the
 		// dynamic resolver and the DSO identifier in the two
@@ -359,10 +349,6 @@
 }
 
 func archreloc(r *ld.Reloc, s *ld.LSym, val *int64) int {
-	var o1 uint32
-	var o2 uint32
-	var t int64
-
 	if ld.Linkmode == ld.LinkExternal {
 		// TODO(minux): translate R_ADDRPOWER and R_CALLPOWER into standard ELF relocations.
 		// R_ADDRPOWER corresponds to R_PPC_ADDR16_HA and R_PPC_ADDR16_LO.
@@ -385,9 +371,9 @@
 		// The encoding of the immediate x<<16 + y,
 		// where x is the low 16 bits of the first instruction and y is the low 16
 		// bits of the second. Both x and y are signed (int16, not uint16).
-		o1 = uint32(r.Add >> 32)
-		o2 = uint32(r.Add)
-		t = ld.Symaddr(r.Sym)
+		o1 := uint32(r.Add >> 32)
+		o2 := uint32(r.Add)
+		t := ld.Symaddr(r.Sym)
 		if t < 0 {
 			ld.Ctxt.Diag("relocation for %s is too big (>=2G): %d", s.Name, ld.Symaddr(r.Sym))
 		}
@@ -400,7 +386,7 @@
 		o2 = o2&0xffff0000 | uint32(t)&0xffff
 
 		// when laid out, the instruction order must always be o1, o2.
-		if ld.Ctxt.Arch.Endian == ld.BigEndian {
+		if ld.Ctxt.Arch.ByteOrder == binary.BigEndian {
 			*val = int64(o1)<<32 | int64(o2)
 		} else {
 			*val = int64(o2)<<32 | int64(o1)
@@ -409,13 +395,14 @@
 
 	case ld.R_CALLPOWER:
 		// Bits 6 through 29 = (S + A - P) >> 2
-		if ld.Ctxt.Arch.Endian == ld.BigEndian {
+		var o1 uint32
+		if ld.Ctxt.Arch.ByteOrder == binary.BigEndian {
 			o1 = ld.Be32(s.P[r.Off:])
 		} else {
 			o1 = ld.Le32(s.P[r.Off:])
 		}
 
-		t = ld.Symaddr(r.Sym) + r.Add - (s.Value + int64(r.Off))
+		t := ld.Symaddr(r.Sym) + r.Add - (s.Value + int64(r.Off))
 		if t&3 != 0 {
 			ld.Ctxt.Diag("relocation for %s+%d is not aligned: %d", r.Sym.Name, r.Off, t)
 		}
@@ -438,7 +425,6 @@
 }
 
 func archrelocvariant(r *ld.Reloc, s *ld.LSym, t int64) int64 {
-	var o1 uint32
 	switch r.Variant & ld.RV_TYPE_MASK {
 	default:
 		ld.Diag("unexpected relocation variant %d", r.Variant)
@@ -451,7 +437,8 @@
 		if r.Variant&ld.RV_CHECK_OVERFLOW != 0 {
 			// Whether to check for signed or unsigned
 			// overflow depends on the instruction
-			if ld.Ctxt.Arch.Endian == ld.BigEndian {
+			var o1 uint32
+			if ld.Ctxt.Arch.ByteOrder == binary.BigEndian {
 				o1 = ld.Be32(s.P[r.Off-2:])
 			} else {
 				o1 = ld.Le32(s.P[r.Off:])
@@ -484,7 +471,8 @@
 		if r.Variant&ld.RV_CHECK_OVERFLOW != 0 {
 			// Whether to check for signed or unsigned
 			// overflow depends on the instruction
-			if ld.Ctxt.Arch.Endian == ld.BigEndian {
+			var o1 uint32
+			if ld.Ctxt.Arch.ByteOrder == binary.BigEndian {
 				o1 = ld.Be32(s.P[r.Off-2:])
 			} else {
 				o1 = ld.Le32(s.P[r.Off:])
@@ -507,7 +495,8 @@
 		return int64(int16(t))
 
 	case ld.RV_POWER_DS:
-		if ld.Ctxt.Arch.Endian == ld.BigEndian {
+		var o1 uint32
+		if ld.Ctxt.Arch.ByteOrder == binary.BigEndian {
 			o1 = uint32(ld.Be16(s.P[r.Off:]))
 		} else {
 			o1 = uint32(ld.Le16(s.P[r.Off:]))
@@ -534,23 +523,18 @@
 	adddynsym(ctxt, s)
 
 	if ld.Iself {
-		var plt *ld.LSym
-		var rela *ld.LSym
-		var glink *ld.LSym
-		var r *ld.Reloc
-
-		plt = ld.Linklookup(ctxt, ".plt", 0)
-		rela = ld.Linklookup(ctxt, ".rela.plt", 0)
+		plt := ld.Linklookup(ctxt, ".plt", 0)
+		rela := ld.Linklookup(ctxt, ".rela.plt", 0)
 		if plt.Size == 0 {
 			elfsetupplt()
 		}
 
 		// Create the glink resolver if necessary
-		glink = ensureglinkresolver()
+		glink := ensureglinkresolver()
 
 		// Write symbol resolver stub (just a branch to the
 		// glink resolver stub)
-		r = ld.Addrel(glink)
+		r := ld.Addrel(glink)
 
 		r.Sym = glink
 		r.Off = int32(glink.Size)
@@ -578,11 +562,7 @@
 
 // Generate the glink resolver stub if necessary and return the .glink section
 func ensureglinkresolver() *ld.LSym {
-	var glink *ld.LSym
-	var s *ld.LSym
-	var r *ld.Reloc
-
-	glink = ld.Linklookup(ld.Ctxt, ".glink", 0)
+	glink := ld.Linklookup(ld.Ctxt, ".glink", 0)
 	if glink.Size != 0 {
 		return glink
 	}
@@ -609,7 +589,7 @@
 	ld.Adduint32(ld.Ctxt, glink, 0x7800f082) // srdi r0,r0,2
 
 	// r11 = address of the first byte of the PLT
-	r = ld.Addrel(glink)
+	r := ld.Addrel(glink)
 
 	r.Off = int32(glink.Size)
 	r.Sym = ld.Linklookup(ld.Ctxt, ".plt", 0)
@@ -635,7 +615,7 @@
 
 	// Add DT_PPC64_GLINK .dynamic entry, which points to 32 bytes
 	// before the first symbol resolver stub.
-	s = ld.Linklookup(ld.Ctxt, ".dynamic", 0)
+	s := ld.Linklookup(ld.Ctxt, ".dynamic", 0)
 
 	ld.Elfwritedynentsymplus(s, ld.DT_PPC64_GLINK, glink, glink.Size-32)
 
@@ -643,10 +623,6 @@
 }
 
 func adddynsym(ctxt *ld.Link, s *ld.LSym) {
-	var d *ld.LSym
-	var t int
-	var name string
-
 	if s.Dynid >= 0 {
 		return
 	}
@@ -655,13 +631,13 @@
 		s.Dynid = int32(ld.Nelfsym)
 		ld.Nelfsym++
 
-		d = ld.Linklookup(ctxt, ".dynsym", 0)
+		d := ld.Linklookup(ctxt, ".dynsym", 0)
 
-		name = s.Extname
+		name := s.Extname
 		ld.Adduint32(ctxt, d, uint32(ld.Addstring(ld.Linklookup(ctxt, ".dynstr", 0), name)))
 
 		/* type */
-		t = ld.STB_GLOBAL << 4
+		t := ld.STB_GLOBAL << 4
 
 		if s.Cgoexport != 0 && s.Type&ld.SMASK == ld.STEXT {
 			t |= ld.STT_FUNC
@@ -695,14 +671,12 @@
 }
 
 func adddynlib(lib string) {
-	var s *ld.LSym
-
 	if needlib(lib) == 0 {
 		return
 	}
 
 	if ld.Iself {
-		s = ld.Linklookup(ld.Ctxt, ".dynstr", 0)
+		s := ld.Linklookup(ld.Ctxt, ".dynstr", 0)
 		if s.Size == 0 {
 			ld.Addstring(s, "")
 		}
@@ -713,11 +687,6 @@
 }
 
 func asmb() {
-	var symo uint32
-	var sect *ld.Section
-	var sym *ld.LSym
-	var i int
-
 	if ld.Debug['v'] != 0 {
 		fmt.Fprintf(&ld.Bso, "%5.2f asmb\n", obj.Cputime())
 	}
@@ -727,7 +696,7 @@
 		ld.Asmbelfsetup()
 	}
 
-	sect = ld.Segtext.Sect
+	sect := ld.Segtext.Sect
 	ld.Cseek(int64(sect.Vaddr - ld.Segtext.Vaddr + ld.Segtext.Fileoff))
 	ld.Codeblk(int64(sect.Vaddr), int64(sect.Length))
 	for sect = sect.Next; sect != nil; sect = sect.Next {
@@ -757,7 +726,7 @@
 	ld.Symsize = 0
 
 	ld.Lcsize = 0
-	symo = 0
+	symo := uint32(0)
 	if ld.Debug['s'] == 0 {
 		// TODO: rationalize
 		if ld.Debug['v'] != 0 {
@@ -800,10 +769,10 @@
 			ld.Asmplan9sym()
 			ld.Cflush()
 
-			sym = ld.Linklookup(ld.Ctxt, "pclntab", 0)
+			sym := ld.Linklookup(ld.Ctxt, "pclntab", 0)
 			if sym != nil {
 				ld.Lcsize = int32(len(sym.P))
-				for i = 0; int32(i) < ld.Lcsize; i++ {
+				for i := 0; int32(i) < ld.Lcsize; i++ {
 					ld.Cput(uint8(sym.P[i]))
 				}
 
diff --git a/src/cmd/9l/l.go b/src/cmd/9l/l.go
index 7ddac3f..e7dc102 100644
--- a/src/cmd/9l/l.go
+++ b/src/cmd/9l/l.go
@@ -66,7 +66,7 @@
 	PtrSize   = 8
 	IntSize   = 8
 	RegSize   = 8
-	MaxAlign  = 32
+	MaxAlign  = 32 // max data alignment
 	FuncAlign = 8
 	MINLC     = 4
 )
diff --git a/src/cmd/9l/obj.go b/src/cmd/9l/obj.go
index 8bba6be..29b384a 100644
--- a/src/cmd/9l/obj.go
+++ b/src/cmd/9l/obj.go
@@ -31,11 +31,11 @@
 package main
 
 import (
+	"cmd/internal/ld"
 	"cmd/internal/obj"
 	"fmt"
 	"log"
 )
-import "cmd/internal/ld"
 
 // Reading object files.
 
diff --git a/src/cmd/asm/internal/arch/arch.go b/src/cmd/asm/internal/arch/arch.go
index 987f5a5..1f176dd 100644
--- a/src/cmd/asm/internal/arch/arch.go
+++ b/src/cmd/asm/internal/arch/arch.go
@@ -7,10 +7,11 @@
 import (
 	"cmd/internal/obj"
 	"cmd/internal/obj/arm"
-	"cmd/internal/obj/i386" // == 386
+	"cmd/internal/obj/arm64"
 	"cmd/internal/obj/ppc64"
-	"cmd/internal/obj/x86" // == amd64
+	"cmd/internal/obj/x86"
 	"fmt"
+	"strings"
 )
 
 // Pseudo-registers whose names are the constant name without the leading R.
@@ -32,12 +33,8 @@
 	RegisterPrefix map[string]bool
 	// RegisterNumber converts R(10) into arm.REG_R10.
 	RegisterNumber func(string, int16) (int16, bool)
-	// Instructions that take one operand whose result is a destination.
-	UnaryDestination map[int]bool
 	// Instruction is a jump.
 	IsJump func(word string) bool
-	// Aconv pretty-prints an instruction opcode for this architecture.
-	Aconv func(int) string
 }
 
 // nilRegisterNumber is the register number function for architectures
@@ -57,18 +54,17 @@
 // Set configures the architecture specified by GOARCH and returns its representation.
 // It returns nil if GOARCH is not recognized.
 func Set(GOARCH string) *Arch {
-	// TODO: Is this how to set this up?
 	switch GOARCH {
 	case "386":
-		return arch386()
+		return archX86(&x86.Link386)
 	case "amd64":
-		return archAmd64()
+		return archX86(&x86.Linkamd64)
 	case "amd64p32":
-		a := archAmd64()
-		a.LinkArch = &x86.Linkamd64p32
-		return a
+		return archX86(&x86.Linkamd64p32)
 	case "arm":
 		return archArm()
+	case "arm64":
+		return archArm64()
 	case "ppc64":
 		a := archPPC64()
 		a.LinkArch = &ppc64.Linkppc64
@@ -81,118 +77,13 @@
 	return nil
 }
 
-func jump386(word string) bool {
-	return word[0] == 'J' || word == "CALL"
+func jumpX86(word string) bool {
+	return word[0] == 'J' || word == "CALL" || strings.HasPrefix(word, "LOOP")
 }
 
-func arch386() *Arch {
+func archX86(linkArch *obj.LinkArch) *Arch {
 	register := make(map[string]int16)
 	// Create maps for easy lookup of instruction names etc.
-	// TODO: Should this be done in obj for us?
-	for i, s := range i386.Register {
-		register[s] = int16(i + i386.REG_AL)
-	}
-	// Pseudo-registers.
-	register["SB"] = RSB
-	register["FP"] = RFP
-	register["PC"] = RPC
-	// Prefixes not used on this architecture.
-
-	instructions := make(map[string]int)
-	for i, s := range i386.Anames {
-		instructions[s] = i
-	}
-	// Annoying aliases.
-	instructions["JA"] = i386.AJHI
-	instructions["JAE"] = i386.AJCC
-	instructions["JB"] = i386.AJCS
-	instructions["JBE"] = i386.AJLS
-	instructions["JC"] = i386.AJCS
-	instructions["JE"] = i386.AJEQ
-	instructions["JG"] = i386.AJGT
-	instructions["JHS"] = i386.AJCC
-	instructions["JL"] = i386.AJLT
-	instructions["JLO"] = i386.AJCS
-	instructions["JNA"] = i386.AJLS
-	instructions["JNAE"] = i386.AJCS
-	instructions["JNB"] = i386.AJCC
-	instructions["JNBE"] = i386.AJHI
-	instructions["JNC"] = i386.AJCC
-	instructions["JNG"] = i386.AJLE
-	instructions["JNGE"] = i386.AJLT
-	instructions["JNL"] = i386.AJGE
-	instructions["JNLE"] = i386.AJGT
-	instructions["JNO"] = i386.AJOC
-	instructions["JNP"] = i386.AJPC
-	instructions["JNS"] = i386.AJPL
-	instructions["JNZ"] = i386.AJNE
-	instructions["JO"] = i386.AJOS
-	instructions["JP"] = i386.AJPS
-	instructions["JPE"] = i386.AJPS
-	instructions["JPO"] = i386.AJPC
-	instructions["JS"] = i386.AJMI
-	instructions["JZ"] = i386.AJEQ
-	instructions["MASKMOVDQU"] = i386.AMASKMOVOU
-	instructions["MOVOA"] = i386.AMOVO
-	instructions["MOVNTDQ"] = i386.AMOVNTO
-
-	unaryDestination := make(map[int]bool) // Instruction takes one operand and result is a destination.
-	// These instructions write to prog.To.
-	unaryDestination[i386.ABSWAPL] = true
-	unaryDestination[i386.ACMPXCHG8B] = true
-	unaryDestination[i386.ADECB] = true
-	unaryDestination[i386.ADECL] = true
-	unaryDestination[i386.ADECW] = true
-	unaryDestination[i386.AINCB] = true
-	unaryDestination[i386.AINCL] = true
-	unaryDestination[i386.AINCW] = true
-	unaryDestination[i386.ANEGB] = true
-	unaryDestination[i386.ANEGL] = true
-	unaryDestination[i386.ANEGW] = true
-	unaryDestination[i386.ANOTB] = true
-	unaryDestination[i386.ANOTL] = true
-	unaryDestination[i386.ANOTW] = true
-	unaryDestination[i386.APOPL] = true
-	unaryDestination[i386.APOPW] = true
-	unaryDestination[i386.ASETCC] = true
-	unaryDestination[i386.ASETCS] = true
-	unaryDestination[i386.ASETEQ] = true
-	unaryDestination[i386.ASETGE] = true
-	unaryDestination[i386.ASETGT] = true
-	unaryDestination[i386.ASETHI] = true
-	unaryDestination[i386.ASETLE] = true
-	unaryDestination[i386.ASETLS] = true
-	unaryDestination[i386.ASETLT] = true
-	unaryDestination[i386.ASETMI] = true
-	unaryDestination[i386.ASETNE] = true
-	unaryDestination[i386.ASETOC] = true
-	unaryDestination[i386.ASETOS] = true
-	unaryDestination[i386.ASETPC] = true
-	unaryDestination[i386.ASETPL] = true
-	unaryDestination[i386.ASETPS] = true
-	unaryDestination[i386.AFFREE] = true
-	unaryDestination[i386.AFLDENV] = true
-	unaryDestination[i386.AFSAVE] = true
-	unaryDestination[i386.AFSTCW] = true
-	unaryDestination[i386.AFSTENV] = true
-	unaryDestination[i386.AFSTSW] = true
-
-	return &Arch{
-		LinkArch:         &i386.Link386,
-		Instructions:     instructions,
-		Register:         register,
-		RegisterPrefix:   nil,
-		RegisterNumber:   nilRegisterNumber,
-		UnaryDestination: unaryDestination,
-		IsJump:           jump386,
-		Aconv:            i386.Aconv,
-	}
-}
-
-func archAmd64() *Arch {
-	register := make(map[string]int16)
-	// Create maps for easy lookup of instruction names etc.
-	// TODO: Should this be done in obj for us?
 	for i, s := range x86.Register {
 		register[s] = int16(i + x86.REG_AL)
 	}
@@ -203,9 +94,14 @@
 	// Register prefix not used on this architecture.
 
 	instructions := make(map[string]int)
-	for i, s := range x86.Anames {
+	for i, s := range obj.Anames {
 		instructions[s] = i
 	}
+	for i, s := range x86.Anames {
+		if i >= obj.A_ARCHSPECIFIC {
+			instructions[s] = i + obj.ABaseAMD64
+		}
+	}
 	// Annoying aliases.
 	instructions["JA"] = x86.AJHI
 	instructions["JAE"] = x86.AJCC
@@ -247,74 +143,20 @@
 	instructions["PSLLDQ"] = x86.APSLLO
 	instructions["PSRLDQ"] = x86.APSRLO
 
-	unaryDestination := make(map[int]bool) // Instruction takes one operand and result is a destination.
-	// These instructions write to prog.To.
-	unaryDestination[x86.ABSWAPL] = true
-	unaryDestination[x86.ABSWAPQ] = true
-	unaryDestination[x86.ACMPXCHG8B] = true
-	unaryDestination[x86.ADECB] = true
-	unaryDestination[x86.ADECL] = true
-	unaryDestination[x86.ADECQ] = true
-	unaryDestination[x86.ADECW] = true
-	unaryDestination[x86.AINCB] = true
-	unaryDestination[x86.AINCL] = true
-	unaryDestination[x86.AINCQ] = true
-	unaryDestination[x86.AINCW] = true
-	unaryDestination[x86.ANEGB] = true
-	unaryDestination[x86.ANEGL] = true
-	unaryDestination[x86.ANEGQ] = true
-	unaryDestination[x86.ANEGW] = true
-	unaryDestination[x86.ANOTB] = true
-	unaryDestination[x86.ANOTL] = true
-	unaryDestination[x86.ANOTQ] = true
-	unaryDestination[x86.ANOTW] = true
-	unaryDestination[x86.APOPL] = true
-	unaryDestination[x86.APOPQ] = true
-	unaryDestination[x86.APOPW] = true
-	unaryDestination[x86.ASETCC] = true
-	unaryDestination[x86.ASETCS] = true
-	unaryDestination[x86.ASETEQ] = true
-	unaryDestination[x86.ASETGE] = true
-	unaryDestination[x86.ASETGT] = true
-	unaryDestination[x86.ASETHI] = true
-	unaryDestination[x86.ASETLE] = true
-	unaryDestination[x86.ASETLS] = true
-	unaryDestination[x86.ASETLT] = true
-	unaryDestination[x86.ASETMI] = true
-	unaryDestination[x86.ASETNE] = true
-	unaryDestination[x86.ASETOC] = true
-	unaryDestination[x86.ASETOS] = true
-	unaryDestination[x86.ASETPC] = true
-	unaryDestination[x86.ASETPL] = true
-	unaryDestination[x86.ASETPS] = true
-	unaryDestination[x86.AFFREE] = true
-	unaryDestination[x86.AFLDENV] = true
-	unaryDestination[x86.AFSAVE] = true
-	unaryDestination[x86.AFSTCW] = true
-	unaryDestination[x86.AFSTENV] = true
-	unaryDestination[x86.AFSTSW] = true
-	unaryDestination[x86.AFXSAVE] = true
-	unaryDestination[x86.AFXSAVE64] = true
-	unaryDestination[x86.ASTMXCSR] = true
-
 	return &Arch{
-		LinkArch:         &x86.Linkamd64,
-		Instructions:     instructions,
-		Register:         register,
-		RegisterPrefix:   nil,
-		RegisterNumber:   nilRegisterNumber,
-		UnaryDestination: unaryDestination,
-		IsJump:           jump386,
-		Aconv:            x86.Aconv,
+		LinkArch:       linkArch,
+		Instructions:   instructions,
+		Register:       register,
+		RegisterPrefix: nil,
+		RegisterNumber: nilRegisterNumber,
+		IsJump:         jumpX86,
 	}
 }
 
 func archArm() *Arch {
 	register := make(map[string]int16)
 	// Create maps for easy lookup of instruction names etc.
-	// TODO: Should this be done in obj for us?
-	// Note that there is no list of names as there is for 386 and amd64.
-	// TODO: Are there aliases we need to add?
+	// Note that there is no list of names as there is for x86.
 	for i := arm.REG_R0; i < arm.REG_SPSR; i++ {
 		register[obj.Rconv(i)] = int16(i)
 	}
@@ -336,36 +178,119 @@
 	}
 
 	instructions := make(map[string]int)
-	for i, s := range arm.Anames {
+	for i, s := range obj.Anames {
 		instructions[s] = i
 	}
+	for i, s := range arm.Anames {
+		if i >= obj.A_ARCHSPECIFIC {
+			instructions[s] = i + obj.ABaseARM
+		}
+	}
 	// Annoying aliases.
 	instructions["B"] = obj.AJMP
 	instructions["BL"] = obj.ACALL
-
-	unaryDestination := make(map[int]bool) // Instruction takes one operand and result is a destination.
-	// These instructions write to prog.To.
-	// TODO: These are silly. Fix once C assembler is gone.
-	unaryDestination[arm.ASWI] = true
-	unaryDestination[arm.AWORD] = true
+	// MCR differs from MRC by the way fields of the word are encoded.
+	// (Details in arm.go). Here we add the instruction so parse will find
+	// it, but give it an opcode number known only to us.
+	instructions["MCR"] = aMCR
 
 	return &Arch{
-		LinkArch:         &arm.Linkarm,
-		Instructions:     instructions,
-		Register:         register,
-		RegisterPrefix:   registerPrefix,
-		RegisterNumber:   armRegisterNumber,
-		UnaryDestination: unaryDestination,
-		IsJump:           jumpArm,
-		Aconv:            arm.Aconv,
+		LinkArch:       &arm.Linkarm,
+		Instructions:   instructions,
+		Register:       register,
+		RegisterPrefix: registerPrefix,
+		RegisterNumber: armRegisterNumber,
+		IsJump:         jumpArm,
 	}
 }
 
+func archArm64() *Arch {
+	register := make(map[string]int16)
+	// Create maps for easy lookup of instruction names etc.
+	// Note that there is no list of names as there is for 386 and amd64.
+	register[arm64.Rconv(arm64.REGSP)] = int16(arm64.REGSP)
+	for i := arm64.REG_R0; i <= arm64.REG_R31; i++ {
+		register[arm64.Rconv(i)] = int16(i)
+	}
+	for i := arm64.REG_F0; i <= arm64.REG_F31; i++ {
+		register[arm64.Rconv(i)] = int16(i)
+	}
+	for i := arm64.REG_V0; i <= arm64.REG_V31; i++ {
+		register[arm64.Rconv(i)] = int16(i)
+	}
+	register["LR"] = arm64.REGLINK
+	register["DAIF"] = arm64.REG_DAIF
+	register["NZCV"] = arm64.REG_NZCV
+	register["FPSR"] = arm64.REG_FPSR
+	register["FPCR"] = arm64.REG_FPCR
+	register["SPSR_EL1"] = arm64.REG_SPSR_EL1
+	register["ELR_EL1"] = arm64.REG_ELR_EL1
+	register["SPSR_EL2"] = arm64.REG_SPSR_EL2
+	register["ELR_EL2"] = arm64.REG_ELR_EL2
+	register["CurrentEL"] = arm64.REG_CurrentEL
+	register["SP_EL0"] = arm64.REG_SP_EL0
+	register["SPSel"] = arm64.REG_SPSel
+	register["DAIFSet"] = arm64.REG_DAIFSet
+	register["DAIFClr"] = arm64.REG_DAIFClr
+	// Conditional operators, like EQ, NE, etc.
+	register["EQ"] = arm64.COND_EQ
+	register["NE"] = arm64.COND_NE
+	register["HS"] = arm64.COND_HS
+	register["LO"] = arm64.COND_LO
+	register["MI"] = arm64.COND_MI
+	register["PL"] = arm64.COND_PL
+	register["VS"] = arm64.COND_VS
+	register["VC"] = arm64.COND_VC
+	register["HI"] = arm64.COND_HI
+	register["LS"] = arm64.COND_LS
+	register["GE"] = arm64.COND_GE
+	register["LT"] = arm64.COND_LT
+	register["GT"] = arm64.COND_GT
+	register["LE"] = arm64.COND_LE
+	register["AL"] = arm64.COND_AL
+	register["NV"] = arm64.COND_NV
+	// Pseudo-registers.
+	register["SB"] = RSB
+	register["FP"] = RFP
+	register["PC"] = RPC
+	register["SP"] = RSP
+	// Avoid unintentionally clobbering g using R28.
+	delete(register, "R28")
+	register["g"] = arm64.REG_R28
+	registerPrefix := map[string]bool{
+		"F": true,
+		"R": true,
+		"V": true,
+	}
+
+	instructions := make(map[string]int)
+	for i, s := range obj.Anames {
+		instructions[s] = i
+	}
+	for i, s := range arm64.Anames {
+		if i >= obj.A_ARCHSPECIFIC {
+			instructions[s] = i + obj.ABaseARM64
+		}
+	}
+	// Annoying aliases.
+	instructions["B"] = arm64.AB
+	instructions["BL"] = arm64.ABL
+
+	return &Arch{
+		LinkArch:       &arm64.Linkarm64,
+		Instructions:   instructions,
+		Register:       register,
+		RegisterPrefix: registerPrefix,
+		RegisterNumber: arm64RegisterNumber,
+		IsJump:         jumpArm64,
+	}
+
+}
+
 func archPPC64() *Arch {
 	register := make(map[string]int16)
 	// Create maps for easy lookup of instruction names etc.
-	// TODO: Should this be done in obj for us?
-	// Note that there is no list of names as there is for 386 and amd64.
+	// Note that there is no list of names as there is for x86.
 	for i := ppc64.REG_R0; i <= ppc64.REG_R31; i++ {
 		register[obj.Rconv(i)] = int16(i)
 	}
@@ -399,22 +324,25 @@
 	}
 
 	instructions := make(map[string]int)
-	for i, s := range ppc64.Anames {
+	for i, s := range obj.Anames {
 		instructions[s] = i
 	}
+	for i, s := range ppc64.Anames {
+		if i >= obj.A_ARCHSPECIFIC {
+			instructions[s] = i + obj.ABasePPC64
+		}
+	}
 	// Annoying aliases.
 	instructions["BR"] = ppc64.ABR
 	instructions["BL"] = ppc64.ABL
 	instructions["RETURN"] = ppc64.ARETURN
 
 	return &Arch{
-		LinkArch:         &ppc64.Linkppc64,
-		Instructions:     instructions,
-		Register:         register,
-		RegisterPrefix:   registerPrefix,
-		RegisterNumber:   ppc64RegisterNumber,
-		UnaryDestination: nil,
-		IsJump:           jumpPPC64,
-		Aconv:            ppc64.Aconv,
+		LinkArch:       &ppc64.Linkppc64,
+		Instructions:   instructions,
+		Register:       register,
+		RegisterPrefix: registerPrefix,
+		RegisterNumber: ppc64RegisterNumber,
+		IsJump:         jumpPPC64,
 	}
 }
diff --git a/src/cmd/asm/internal/arch/arm.go b/src/cmd/asm/internal/arch/arm.go
index fab896a..2354d61 100644
--- a/src/cmd/asm/internal/arch/arm.go
+++ b/src/cmd/asm/internal/arch/arm.go
@@ -105,16 +105,47 @@
 	return false
 }
 
+// MCR is not defined by the obj/arm; instead we define it privately here.
+// It is encoded as an MRC with a bit inside the instruction word,
+// passed to arch.ARMMRCOffset.
+const aMCR = arm.ALAST + 1
+
 // IsARMMRC reports whether the op (as defined by an arm.A* constant) is
 // MRC or MCR
 func IsARMMRC(op int) bool {
 	switch op {
-	case arm.AMRC /*, arm.AMCR*/ :
+	case arm.AMRC, aMCR: // Note: aMCR is defined in this package.
 		return true
 	}
 	return false
 }
 
+// ARMMRCOffset implements the peculiar encoding of the MRC and MCR instructions.
+// The difference between MRC and MCR is represented by a bit high in the word, not
+// in the usual way by the opcode itself. Asm must use AMRC for both instructions, so
+// we return the opcode for MRC so that asm doesn't need to import obj/arm.
+func ARMMRCOffset(op int, cond string, x0, x1, x2, x3, x4, x5 int64) (offset int64, op0 int16, ok bool) {
+	op1 := int64(0)
+	if op == arm.AMRC {
+		op1 = 1
+	}
+	bits, ok := ParseARMCondition(cond)
+	if !ok {
+		return
+	}
+	offset = (0xe << 24) | // opcode
+		(op1 << 20) | // MCR/MRC
+		((int64(bits) ^ arm.C_SCOND_XOR) << 28) | // scond
+		((x0 & 15) << 8) | //coprocessor number
+		((x1 & 7) << 21) | // coprocessor operation
+		((x2 & 15) << 12) | // ARM register
+		((x3 & 15) << 16) | // Crn
+		((x4 & 15) << 0) | // Crm
+		((x5 & 7) << 5) | // coprocessor information
+		(1 << 4) /* must be set */
+	return offset, arm.AMRC, true
+}
+
 // IsARMMULA reports whether the op (as defined by an arm.A* constant) is
 // MULA, MULAWT or MULAWB, the 4-operand instructions.
 func IsARMMULA(op int) bool {
@@ -167,6 +198,10 @@
 // The input is a single string consisting of period-separated condition
 // codes, such as ".P.W". An initial period is ignored.
 func ParseARMCondition(cond string) (uint8, bool) {
+	return parseARMCondition(cond, armLS, armSCOND)
+}
+
+func parseARMCondition(cond string, ls, scond map[string]uint8) (uint8, bool) {
 	if strings.HasPrefix(cond, ".") {
 		cond = cond[1:]
 	}
@@ -176,11 +211,11 @@
 	names := strings.Split(cond, ".")
 	bits := uint8(0)
 	for _, name := range names {
-		if b, present := armLS[name]; present {
+		if b, present := ls[name]; present {
 			bits |= b
 			continue
 		}
-		if b, present := armSCOND[name]; present {
+		if b, present := scond[name]; present {
 			bits = (bits &^ arm.C_SCOND) | b
 			continue
 		}
diff --git a/src/cmd/asm/internal/arch/arm64.go b/src/cmd/asm/internal/arch/arm64.go
new file mode 100644
index 0000000..a0a0082
--- /dev/null
+++ b/src/cmd/asm/internal/arch/arm64.go
@@ -0,0 +1,114 @@
+// Copyright 2015 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.
+
+// This file encapsulates some of the odd characteristics of the ARM64
+// instruction set, to minimize its interaction with the core of the
+// assembler.
+
+package arch
+
+import (
+	"cmd/internal/obj"
+	"cmd/internal/obj/arm64"
+)
+
+var arm64LS = map[string]uint8{
+	"P": arm64.C_XPOST,
+	"W": arm64.C_XPRE,
+}
+
+var arm64Jump = map[string]bool{
+	"B":     true,
+	"BL":    true,
+	"BEQ":   true,
+	"BNE":   true,
+	"BCS":   true,
+	"BHS":   true,
+	"BCC":   true,
+	"BLO":   true,
+	"BMI":   true,
+	"BPL":   true,
+	"BVS":   true,
+	"BVC":   true,
+	"BHI":   true,
+	"BLS":   true,
+	"BGE":   true,
+	"BLT":   true,
+	"BGT":   true,
+	"BLE":   true,
+	"CALL":  true,
+	"CBZ":   true,
+	"CBZW":  true,
+	"CBNZ":  true,
+	"CBNZW": true,
+}
+
+func jumpArm64(word string) bool {
+	return arm64Jump[word]
+}
+
+// IsARM64CMP reports whether the op (as defined by an arm.A* constant) is
+// one of the comparison instructions that require special handling.
+func IsARM64CMP(op int) bool {
+	switch op {
+	case arm64.ACMN, arm64.ACMP, arm64.ATST,
+		arm64.ACMNW, arm64.ACMPW, arm64.ATSTW:
+		return true
+	}
+	return false
+}
+
+// IsARM64STLXR reports whether the op (as defined by an arm64.A*
+// constant) is one of the STLXR-like instructions that require special
+// handling.
+func IsARM64STLXR(op int) bool {
+	switch op {
+	case arm64.ASTLXRB, arm64.ASTLXRH, arm64.ASTLXRW, arm64.ASTLXR:
+		return true
+	}
+	return false
+}
+
+// ARM64Suffix handles the special suffix for the ARM64.
+// It returns a boolean to indicate success; failure means
+// cond was unrecognized.
+func ARM64Suffix(prog *obj.Prog, cond string) bool {
+	if cond == "" {
+		return true
+	}
+	bits, ok := ParseARM64Suffix(cond)
+	if !ok {
+		return false
+	}
+	prog.Scond = bits
+	return true
+}
+
+// ParseARM64Suffix parses the suffix attached to an ARM64 instruction.
+// The input is a single string consisting of period-separated condition
+// codes, such as ".P.W". An initial period is ignored.
+func ParseARM64Suffix(cond string) (uint8, bool) {
+	if cond == "" {
+		return 0, true
+	}
+	return parseARMCondition(cond, arm64LS, nil)
+}
+
+func arm64RegisterNumber(name string, n int16) (int16, bool) {
+	switch name {
+	case "F":
+		if 0 <= n && n <= 31 {
+			return arm64.REG_F0 + n, true
+		}
+	case "R":
+		if 0 <= n && n <= 30 { // not 31
+			return arm64.REG_R0 + n, true
+		}
+	case "V":
+		if 0 <= n && n <= 31 {
+			return arm64.REG_V0 + n, true
+		}
+	}
+	return 0, false
+}
diff --git a/src/cmd/asm/internal/asm/asm.go b/src/cmd/asm/internal/asm/asm.go
index 6487e7c..811853b 100644
--- a/src/cmd/asm/internal/asm/asm.go
+++ b/src/cmd/asm/internal/asm/asm.go
@@ -13,8 +13,6 @@
 	"cmd/asm/internal/flags"
 	"cmd/asm/internal/lex"
 	"cmd/internal/obj"
-	"cmd/internal/obj/arm"
-	"cmd/internal/obj/ppc64"
 )
 
 // TODO: configure the architecture
@@ -24,9 +22,20 @@
 // append adds the Prog to the end of the program-thus-far.
 // If doLabel is set, it also defines the labels collect for this Prog.
 func (p *Parser) append(prog *obj.Prog, cond string, doLabel bool) {
-	if p.arch.Thechar == '5' {
-		if !arch.ARMConditionCodes(prog, cond) {
-			p.errorf("unrecognized condition code .%q", cond)
+	if cond != "" {
+		switch p.arch.Thechar {
+		case '5':
+			if !arch.ARMConditionCodes(prog, cond) {
+				p.errorf("unrecognized condition code .%q", cond)
+			}
+
+		case '7':
+			if !arch.ARM64Suffix(prog, cond) {
+				p.errorf("unrecognized suffix .%q", cond)
+			}
+
+		default:
+			p.errorf("unrecognized suffix .%q", cond)
 		}
 	}
 	if p.firstProg == nil {
@@ -143,6 +152,7 @@
 		Lineno: p.histLineNum,
 		From:   nameAddr,
 		From3: obj.Addr{
+			Type:   obj.TYPE_CONST,
 			Offset: flag,
 		},
 		To: obj.Addr{
@@ -151,7 +161,7 @@
 			// Argsize set below.
 		},
 	}
-	prog.To.U.Argsize = int32(argSize)
+	prog.To.Val = int32(argSize)
 
 	p.append(prog, "", true)
 }
@@ -308,14 +318,9 @@
 	case 1:
 		target = &a[0]
 	case 2:
-		if p.arch.Thechar == '9' {
-			// Special 2-operand jumps.
-			target = &a[1]
-			prog.From = a[0]
-			break
-		}
-		p.errorf("wrong number of arguments to %s instruction", p.arch.Aconv(op))
-		return
+		// Special 2-operand jumps.
+		target = &a[1]
+		prog.From = a[0]
 	case 3:
 		if p.arch.Thechar == '9' {
 			// Special 3-operand jumps.
@@ -325,12 +330,17 @@
 				Type:   obj.TYPE_CONST,
 				Offset: p.getConstant(prog, op, &a[0]),
 			}
-			prog.Reg = int16(ppc64.REG_R0 + p.getConstant(prog, op, &a[1]))
+			reg := int16(p.getConstant(prog, op, &a[1]))
+			reg, ok := p.arch.RegisterNumber("R", int16(reg))
+			if !ok {
+				p.errorf("bad register number %d", reg)
+			}
+			prog.Reg = reg
 			break
 		}
 		fallthrough
 	default:
-		p.errorf("wrong number of arguments to %s instruction", p.arch.Aconv(op))
+		p.errorf("wrong number of arguments to %s instruction", obj.Aconv(op))
 		return
 	}
 	switch {
@@ -396,13 +406,13 @@
 		Type:  obj.TYPE_BRANCH,
 		Index: 0,
 	}
-	jmp.To.U.Branch = target
+	jmp.To.Val = target
 }
 
 // asmInstruction assembles an instruction.
 // MOVW R9, (R10)
 func (p *Parser) asmInstruction(op int, cond string, a []obj.Addr) {
-	// fmt.Printf("%s %+v\n", p.arch.Aconv(op), a)
+	// fmt.Printf("%s %+v\n", obj.Aconv(op), a)
 	prog := &obj.Prog{
 		Ctxt:   p.ctxt,
 		Lineno: p.histLineNum,
@@ -412,7 +422,7 @@
 	case 0:
 		// Nothing to do.
 	case 1:
-		if p.arch.UnaryDestination[op] {
+		if p.arch.UnaryDst[op] {
 			// prog.From is no address.
 			prog.To = a[0]
 		} else {
@@ -451,41 +461,19 @@
 					prog.To = a[1]
 					break
 				}
-				p.errorf("unrecognized addressing for %s", p.arch.Aconv(op))
+				p.errorf("unrecognized addressing for %s", obj.Aconv(op))
 			}
+		} else if p.arch.Thechar == '7' && arch.IsARM64CMP(op) {
+			prog.From = a[0]
+			prog.Reg = p.getRegister(prog, op, &a[1])
+			break
 		}
 		prog.From = a[0]
 		prog.To = a[1]
-		switch p.arch.Thechar {
-		case '6', '8':
-			// DX:AX as a register pair can only appear on the RHS.
-			// Bizarrely, to obj it's specified by setting index on the LHS.
-			// TODO: can we fix this?
-			if a[1].Reg2 != 0 {
-				if a[0].Reg2 != 0 {
-					p.errorf("register pair must be on LHS")
-				}
-				prog.From.Index = int16(a[1].Reg2)
-				prog.To.Reg2 = 0
-			}
-		case '9':
-			var reg0, reg1 int16
-			// Handle (R1+R2)
-			if a[0].Scale != 0 {
-				reg0 = int16(a[0].Scale)
-				prog.Reg = reg0
-			} else if a[1].Scale != 0 {
-				reg1 = int16(a[1].Scale)
-				prog.Reg = reg1
-			}
-			if reg0 != 0 && reg1 != 0 {
-				p.errorf("register pair cannot be both left and right operands")
-			}
-		}
 	case 3:
 		switch p.arch.Thechar {
 		case '5':
-			// Strange special case.
+			// Special cases.
 			if arch.IsARMSTREX(op) {
 				/*
 					STREX x, (y), z
@@ -500,21 +488,21 @@
 			prog.From = a[0]
 			prog.Reg = p.getRegister(prog, op, &a[1])
 			prog.To = a[2]
-		case '6', '8':
-			// CMPSD etc.; third operand is imm8, stored in offset, or a register.
-			prog.From = a[0]
-			prog.To = a[1]
-			switch a[2].Type {
-			case obj.TYPE_MEM:
-				prog.To.Offset = p.getConstant(prog, op, &a[2])
-			case obj.TYPE_REG:
-				// Strange reordering.
-				prog.To = a[2]
-				prog.From = a[1]
-				prog.To.Offset = p.getImmediate(prog, op, &a[0])
-			default:
-				p.errorf("expected offset or register for 3rd operand")
+		case '7':
+			// ARM64 instructions with one input and two outputs.
+			if arch.IsARM64STLXR(op) {
+				prog.From = a[0]
+				prog.To = a[1]
+				prog.To2 = a[2]
+				break
 			}
+			prog.From = a[0]
+			prog.Reg = p.getRegister(prog, op, &a[1])
+			prog.To = a[2]
+		case '6', '8':
+			prog.From = a[0]
+			prog.From3 = a[1]
+			prog.To = a[2]
 		case '9':
 			if arch.IsPPC64CMP(op) {
 				// CMPW etc.; third argument is a CR register that goes into prog.Reg.
@@ -538,7 +526,7 @@
 				prog.From3 = a[1]
 				prog.To = a[2]
 			default:
-				p.errorf("invalid addressing modes for %s instruction", p.arch.Aconv(op))
+				p.errorf("invalid addressing modes for %s instruction", obj.Aconv(op))
 			}
 		default:
 			p.errorf("TODO: implement three-operand instructions for this architecture")
@@ -567,7 +555,7 @@
 			prog.To = a[3]
 			break
 		}
-		p.errorf("can't handle %s instruction with 4 operands", p.arch.Aconv(op))
+		p.errorf("can't handle %s instruction with 4 operands", obj.Aconv(op))
 	case 5:
 		if p.arch.Thechar == '9' && arch.IsPPC64RLD(op) {
 			// Always reg, reg, con, con, reg.  (con, con is a 'mask').
@@ -588,50 +576,30 @@
 			prog.To = a[4]
 			break
 		}
-		p.errorf("can't handle %s instruction with 5 operands", p.arch.Aconv(op))
+		p.errorf("can't handle %s instruction with 5 operands", obj.Aconv(op))
 	case 6:
-		// MCR and MRC on ARM
 		if p.arch.Thechar == '5' && arch.IsARMMRC(op) {
 			// Strange special case: MCR, MRC.
-			// TODO: Move this to arch? (It will be hard to disentangle.)
 			prog.To.Type = obj.TYPE_CONST
-			bits, ok := uint8(0), false
-			if cond != "" {
-				// Cond is handled specially for this instruction.
-				bits, ok = arch.ParseARMCondition(cond)
-				if !ok {
-					p.errorf("unrecognized condition code .%q", cond)
-				}
-				cond = ""
-			}
-			// First argument is a condition code as a constant.
 			x0 := p.getConstant(prog, op, &a[0])
 			x1 := p.getConstant(prog, op, &a[1])
 			x2 := int64(p.getRegister(prog, op, &a[2]))
 			x3 := int64(p.getRegister(prog, op, &a[3]))
 			x4 := int64(p.getRegister(prog, op, &a[4]))
 			x5 := p.getConstant(prog, op, &a[5])
-			// TODO only MCR is defined.
-			op1 := int64(0)
-			if op == arm.AMRC {
-				op1 = 1
+			// Cond is handled specially for this instruction.
+			offset, MRC, ok := arch.ARMMRCOffset(op, cond, x0, x1, x2, x3, x4, x5)
+			if !ok {
+				p.errorf("unrecognized condition code .%q", cond)
 			}
-			prog.To.Offset =
-				(0xe << 24) | // opcode
-					(op1 << 20) | // MCR/MRC
-					((int64(bits) ^ arm.C_SCOND_XOR) << 28) | // scond
-					((x0 & 15) << 8) | //coprocessor number
-					((x1 & 7) << 21) | // coprocessor operation
-					((x2 & 15) << 12) | // ARM register
-					((x3 & 15) << 16) | // Crn
-					((x4 & 15) << 0) | // Crm
-					((x5 & 7) << 5) | // coprocessor information
-					(1 << 4) /* must be set */
+			prog.To.Offset = offset
+			cond = ""
+			prog.As = MRC // Both instructions are coded as MRC.
 			break
 		}
 		fallthrough
 	default:
-		p.errorf("can't handle %s instruction with %d operands", p.arch.Aconv(op), len(a))
+		p.errorf("can't handle %s instruction with %d operands", obj.Aconv(op), len(a))
 	}
 
 	p.append(prog, cond, true)
@@ -650,7 +618,7 @@
 // getConstant checks that addr represents a plain constant and returns its value.
 func (p *Parser) getConstant(prog *obj.Prog, op int, addr *obj.Addr) int64 {
 	if addr.Type != obj.TYPE_MEM || addr.Name != 0 || addr.Reg != 0 || addr.Index != 0 {
-		p.errorf("%s: expected integer constant; found %s", p.arch.Aconv(op), obj.Dconv(prog, addr))
+		p.errorf("%s: expected integer constant; found %s", obj.Aconv(op), obj.Dconv(prog, addr))
 	}
 	return addr.Offset
 }
@@ -658,7 +626,7 @@
 // getImmediate checks that addr represents an immediate constant and returns its value.
 func (p *Parser) getImmediate(prog *obj.Prog, op int, addr *obj.Addr) int64 {
 	if addr.Type != obj.TYPE_CONST || addr.Name != 0 || addr.Reg != 0 || addr.Index != 0 {
-		p.errorf("%s: expected immediate constant; found %s", p.arch.Aconv(op), obj.Dconv(prog, addr))
+		p.errorf("%s: expected immediate constant; found %s", obj.Aconv(op), obj.Dconv(prog, addr))
 	}
 	return addr.Offset
 }
@@ -666,7 +634,7 @@
 // getRegister checks that addr represents a register and returns its value.
 func (p *Parser) getRegister(prog *obj.Prog, op int, addr *obj.Addr) int16 {
 	if addr.Type != obj.TYPE_REG || addr.Offset != 0 || addr.Name != 0 || addr.Index != 0 {
-		p.errorf("%s: expected register; found %s", p.arch.Aconv(op), obj.Dconv(prog, addr))
+		p.errorf("%s: expected register; found %s", obj.Aconv(op), obj.Dconv(prog, addr))
 	}
 	return addr.Reg
 }
diff --git a/src/cmd/asm/internal/asm/endtoend_test.go b/src/cmd/asm/internal/asm/endtoend_test.go
index 7b4bdfc..58c3238 100644
--- a/src/cmd/asm/internal/asm/endtoend_test.go
+++ b/src/cmd/asm/internal/asm/endtoend_test.go
@@ -38,7 +38,7 @@
 	obj.Binitw(ioutil.Discard)
 	pList.Firstpc, ok = parser.Parse()
 	if !ok {
-		t.Fatalf("asm: ppc64 assembly failed")
+		t.Fatalf("asm: %s assembly failed", goarch)
 	}
 	result := string(testOut.Bytes())
 	expect, err := ioutil.ReadFile(output)
@@ -56,7 +56,7 @@
 		r := strings.Split(result, "\n")
 		e := strings.Split(string(expect), "\n")
 		if len(r) != len(e) {
-			t.Errorf("%s: expected %d lines, got %d", len(e), len(r))
+			t.Errorf("%s: expected %d lines, got %d", goarch, len(e), len(r))
 		}
 		n := len(e)
 		if n > len(r) {
diff --git a/src/cmd/asm/internal/asm/operand_test.go b/src/cmd/asm/internal/asm/operand_test.go
index fd0331e..1b10a3a 100644
--- a/src/cmd/asm/internal/asm/operand_test.go
+++ b/src/cmd/asm/internal/asm/operand_test.go
@@ -41,69 +41,28 @@
 	}
 }
 
-func testX86RegisterPair(t *testing.T, parser *Parser) {
-	// Special case for AX:DX, which is really two operands so isn't printed correcctly
-	// by Aconv, but is OK by the -S output.
-	parser.start(lex.Tokenize("AX:BX)"))
-	addr := obj.Addr{}
-	parser.operand(&addr)
-	want := obj.Addr{
-		Type: obj.TYPE_REG,
-		Reg:  parser.arch.Register["AX"],
-		Reg2: parser.arch.Register["BX"], // TODO: clean up how this is encoded in parse.go
-	}
-	if want != addr {
-		t.Errorf("AX:DX: expected %+v got %+v", want, addr)
-	}
-	// Special case for foo(SB):DX, which is really two operands so isn't printed correctly
-	// by Aconv, but is OK by the -S output.
-	parser.start(lex.Tokenize("foo+4(SB):AX"))
-	addr = obj.Addr{}
-	parser.operand(&addr)
-	want = obj.Addr{
-		Type:   obj.TYPE_MEM,
-		Name:   obj.NAME_EXTERN,
-		Offset: 4,
-		Sym:    obj.Linklookup(parser.ctxt, "foo", 0),
-		Reg2:   parser.arch.Register["AX"], // TODO: clean up how this is encoded in parse.go
-	}
-	if want != addr {
-		t.Errorf("foo+4(SB):AX: expected %+v got %+v", want, addr)
-	}
-}
-
 func TestAMD64OperandParser(t *testing.T) {
 	parser := newParser("amd64")
 	testOperandParser(t, parser, amd64OperandTests)
-	testX86RegisterPair(t, parser)
 }
 
 func Test386OperandParser(t *testing.T) {
 	parser := newParser("386")
 	testOperandParser(t, parser, x86OperandTests)
-	testX86RegisterPair(t, parser)
 }
 
 func TestARMOperandParser(t *testing.T) {
 	parser := newParser("arm")
 	testOperandParser(t, parser, armOperandTests)
 }
+func TestARM64OperandParser(t *testing.T) {
+	parser := newParser("arm64")
+	testOperandParser(t, parser, arm64OperandTests)
+}
 
 func TestPPC64OperandParser(t *testing.T) {
 	parser := newParser("ppc64")
 	testOperandParser(t, parser, ppc64OperandTests)
-	// Special encoding for (R1+R2).
-	parser.start(lex.Tokenize("(R1+R2)"))
-	addr := obj.Addr{}
-	parser.operand(&addr)
-	want := obj.Addr{
-		Type:  obj.TYPE_MEM,
-		Reg:   parser.arch.Register["R1"],
-		Scale: parser.arch.Register["R2"], // TODO: clean up how this is encoded in parse.go
-	}
-	if want != addr {
-		t.Errorf("(R1+R2): expected %+v got %+v", want, addr)
-	}
 }
 
 type operandTest struct {
@@ -113,7 +72,6 @@
 // Examples collected by scanning all the assembly in the standard repo.
 
 var amd64OperandTests = []operandTest{
-	// {"AX:DX", "AX:DX"}, Handled in TestAMD64OperandParser directly.
 	{"$(-1.0)", "$(-1.0)"},
 	{"$(0.0)", "$(0.0)"},
 	{"$(0x2000000+116)", "$33554548"},
@@ -289,7 +247,7 @@
 	{"$256", "$256"},
 	{"(R0)", "(R0)"},
 	{"(R11)", "(R11)"},
-	{"(g)", "(R10)"}, // TODO: Should print 0(g).
+	{"(g)", "(g)"},
 	{"-12(R4)", "-12(R4)"},
 	{"0(PC)", "0(PC)"},
 	{"1024", "1024"},
@@ -324,7 +282,7 @@
 	{"armCAS64(SB)", "armCAS64(SB)"},
 	{"asmcgocall<>(SB)", "asmcgocall<>(SB)"},
 	{"c+28(FP)", "c+28(FP)"},
-	{"g", "R10"}, // TODO: Should print g.
+	{"g", "g"},
 	{"gosave<>(SB)", "gosave<>(SB)"},
 	{"retlo+12(FP)", "retlo+12(FP)"},
 	{"runtime·_sfloat2(SB)", "runtime._sfloat2(SB)"},
@@ -349,12 +307,14 @@
 	{"$~3", "$-4"},
 	{"(-288-3*8)(R1)", "-312(R1)"},
 	{"(16)(R7)", "16(R7)"},
-	{"(8)(g)", "8(R30)"}, // TODO: Should print 8(g)
+	{"(8)(g)", "8(g)"},
 	{"(CTR)", "(CTR)"},
 	{"(R0)", "(R0)"},
 	{"(R3)", "(R3)"},
 	{"(R4)", "(R4)"},
 	{"(R5)", "(R5)"},
+	{"(R5)(R6*1)", "(R5)(R6*1)"},
+	{"(R5+R6)", "(R5)(R6*1)"}, // Old syntax.
 	{"-1(R4)", "-1(R4)"},
 	{"-1(R5)", "-1(R5)"},
 	{"6(PC)", "6(PC)"},
@@ -411,9 +371,57 @@
 	{"R9", "R9"},
 	{"SPR(269)", "SPR(269)"},
 	{"a(FP)", "a(FP)"},
-	{"g", "R30"}, // TODO: Should print g.
+	{"g", "g"},
 	{"ret+8(FP)", "ret+8(FP)"},
 	{"runtime·abort(SB)", "runtime.abort(SB)"},
 	{"·AddUint32(SB)", "\"\".AddUint32(SB)"},
 	{"·trunc(SB)", "\"\".trunc(SB)"},
 }
+
+var arm64OperandTests = []operandTest{
+	{"$0", "$0"},
+	{"$0.5", "$(0.5)"},
+	{"0(R26)", "(R26)"},
+	{"0(RSP)", "(RSP)"},
+	{"$1", "$1"},
+	{"$-1", "$-1"},
+	{"$1000", "$1000"},
+	{"$1000000000", "$1000000000"},
+	{"$0x7fff3c000", "$34358935552"},
+	{"$1234", "$1234"},
+	{"$~15", "$-16"},
+	{"$16", "$16"},
+	{"-16(RSP)", "-16(RSP)"},
+	{"16(RSP)", "16(RSP)"},
+	{"1(R1)", "1(R1)"},
+	{"-1(R4)", "-1(R4)"},
+	{"18740(R5)", "18740(R5)"},
+	{"$2", "$2"},
+	{"$-24(R4)", "$-24(R4)"},
+	{"-24(RSP)", "-24(RSP)"},
+	{"$24(RSP)", "$24(RSP)"},
+	{"-32(RSP)", "-32(RSP)"},
+	{"$48", "$48"},
+	{"$(-64*1024)(R7)", "$-65536(R7)"},
+	{"$(8-1)", "$7"},
+	{"a+0(FP)", "a(FP)"},
+	{"a1+8(FP)", "a1+8(FP)"},
+	{"·AddInt32(SB)", `"".AddInt32(SB)`},
+	{"runtime·divWVW(SB)", "runtime.divWVW(SB)"},
+	{"$argframe+0(FP)", "$argframe(FP)"},
+	{"$asmcgocall<>(SB)", "$asmcgocall<>(SB)"},
+	{"EQ", "EQ"},
+	{"F29", "F29"},
+	{"F3", "F3"},
+	{"F30", "F30"},
+	{"g", "g"},
+	{"LR", "R30"},
+	{"(LR)", "(R30)"},
+	{"R0", "R0"},
+	{"R10", "R10"},
+	{"R11", "R11"},
+	{"$4503601774854144.0", "$(4503601774854144.0)"},
+	{"$runtime·badsystemstack(SB)", "$runtime.badsystemstack(SB)"},
+	{"ZR", "ZR"},
+	{"(ZR)", "(ZR)"},
+}
diff --git a/src/cmd/asm/internal/asm/parse.go b/src/cmd/asm/internal/asm/parse.go
index 27d3112..81d7ccc 100644
--- a/src/cmd/asm/internal/asm/parse.go
+++ b/src/cmd/asm/internal/asm/parse.go
@@ -109,13 +109,14 @@
 	operands := make([][]lex.Token, 0, 3)
 	// Zero or more comma-separated operands, one per loop.
 	nesting := 0
+	colon := -1
 	for tok != '\n' && tok != ';' {
 		// Process one operand.
 		items := make([]lex.Token, 0, 3)
 		for {
 			tok = p.lex.Next()
 			if len(operands) == 0 && len(items) == 0 {
-				if p.arch.Thechar == '5' && tok == '.' {
+				if (p.arch.Thechar == '5' || p.arch.Thechar == '7') && tok == '.' {
 					// ARM conditionals.
 					tok = p.lex.Next()
 					str := p.lex.Text()
@@ -135,7 +136,16 @@
 				p.errorf("unexpected EOF")
 				return false
 			}
-			if tok == '\n' || tok == ';' || (nesting == 0 && tok == ',') {
+			// Split operands on comma. Also, the old syntax on x86 for a "register pair"
+			// was AX:DX, for which the new syntax is DX, AX. Note the reordering.
+			if tok == '\n' || tok == ';' || (nesting == 0 && (tok == ',' || tok == ':')) {
+				if tok == ':' {
+					// Remember this location so we can swap the operands below.
+					if colon >= 0 {
+						p.errorf("invalid ':' in operand")
+					}
+					colon = len(operands)
+				}
 				break
 			}
 			if tok == '(' || tok == '[' {
@@ -148,8 +158,13 @@
 		}
 		if len(items) > 0 {
 			operands = append(operands, items)
-		} else if len(operands) > 0 || tok == ',' {
-			// Had a comma with nothing after.
+			if colon >= 0 && len(operands) == colon+2 {
+				// AX:DX becomes DX, AX.
+				operands[colon], operands[colon+1] = operands[colon+1], operands[colon]
+				colon = -1
+			}
+		} else if len(operands) > 0 || tok == ',' || colon >= 0 {
+			// Had a separator with nothing after.
 			p.errorf("missing operand")
 		}
 	}
@@ -226,7 +241,7 @@
 
 // operand parses a general operand and stores the result in *a.
 func (p *Parser) operand(a *obj.Addr) bool {
-	// fmt.Printf("Operand: %v\n", p.input)
+	//fmt.Printf("Operand: %v\n", p.input)
 	if len(p.input) == 0 {
 		p.errorf("empty operand: cannot happen")
 		return false
@@ -297,6 +312,8 @@
 			if r2 != 0 {
 				// Form is R1:R2. It is on RHS and the second register
 				// needs to go into the LHS. This is a horrible hack. TODO.
+				// TODO: If we never see this again, can delete Addr.Reg2.
+				panic("cannot happen")
 				a.Reg2 = r2
 			}
 		}
@@ -326,7 +343,7 @@
 				p.errorf("floating-point constant must be an immediate")
 			}
 			a.Type = obj.TYPE_FCONST
-			a.U.Dval = p.floatExpr()
+			a.Val = p.floatExpr()
 			// fmt.Printf("FCONST %s\n", obj.Dconv(&emptyProg, 0, a))
 			p.expect(scanner.EOF)
 			return true
@@ -340,7 +357,7 @@
 				p.errorf("string parse error: %s", err)
 			}
 			a.Type = obj.TYPE_SCONST
-			a.U.Sval = str
+			a.Val = str
 			// fmt.Printf("SCONST %s\n", obj.Dconv(&emptyProg, 0, a))
 			p.expect(scanner.EOF)
 			return true
@@ -362,18 +379,8 @@
 		// fmt.Printf("offset %d \n", a.Offset)
 	}
 
-	// Odd x86 case: sym+4(SB):AX. Have name, colon, register.
-	if p.peek() == ':' && a.Name != obj.NAME_NONE && a.Reg2 == 0 && (p.arch.Thechar == '6' || p.arch.Thechar == '8') {
-		p.get(':')
-		r2, ok := p.registerReference(p.next().String())
-		if !ok {
-			return false
-		}
-		a.Reg2 = r2 // TODO: See comment about Reg3 above.
-	} else {
-		// Register indirection: (reg) or (index*scale). We are on the opening paren.
-		p.registerIndirect(a, prefix)
-	}
+	// Register indirection: (reg) or (index*scale). We are on the opening paren.
+	p.registerIndirect(a, prefix)
 	// fmt.Printf("DONE %s\n", p.arch.Dconv(&emptyProg, 0, a))
 
 	p.expect(scanner.EOF)
@@ -449,15 +456,10 @@
 	}
 	c := p.peek()
 	if c == ':' || c == ',' || c == '+' {
-		// 2nd register; syntax (R1:R2) etc. No two architectures agree.
+		// 2nd register; syntax (R1+R2) etc. No two architectures agree.
 		// Check the architectures match the syntax.
 		char := p.arch.Thechar
 		switch p.next().ScanToken {
-		case ':':
-			if char != '6' && char != '8' {
-				p.errorf("illegal register pair syntax")
-				return
-			}
 		case ',':
 			if char != '5' {
 				p.errorf("illegal register pair syntax")
@@ -644,9 +646,9 @@
 				p.errorf("illegal address mode for register pair")
 				return
 			}
-			// TODO: This is rewritten in asm. Clumsy.
 			a.Type = obj.TYPE_MEM
-			a.Scale = r2
+			a.Scale = 1
+			a.Index = r2
 			// Nothing may follow.
 			return
 		}
diff --git a/src/cmd/asm/internal/asm/testdata/386.out b/src/cmd/asm/internal/asm/testdata/386.out
index 59c7f89..be43ccb 100644
--- a/src/cmd/asm/internal/asm/testdata/386.out
+++ b/src/cmd/asm/internal/asm/testdata/386.out
@@ -1,48 +1,49 @@
-5 00001 (testdata/386.s:5)	TEXT	foo(SB),$0
-8 00002 (testdata/386.s:8)	SETCC	,AX
-9 00003 (testdata/386.s:9)	SETCC	,foo+4(SB)
-12 00004 (testdata/386.s:12)	DIVB	AX,
-13 00005 (testdata/386.s:13)	DIVB	foo+4(SB),
-14 00006 (testdata/386.s:14)	PUSHL	$foo+4(SB),
-15 00007 (testdata/386.s:15)	POPL	,AX
-18 00008 (testdata/386.s:18)	SUBB	$1,AX
-19 00009 (testdata/386.s:19)	SUBB	$1,foo+4(SB)
-20 00010 (testdata/386.s:20)	SUBB	BX,AX
-21 00011 (testdata/386.s:21)	SUBB	BX,foo+4(SB)
-24 00012 (testdata/386.s:24)	CMPB	AX,$1
-25 00013 (testdata/386.s:25)	CMPB	foo+4(SB),$4
-26 00014 (testdata/386.s:26)	CMPB	BX,AX
-27 00015 (testdata/386.s:27)	CMPB	foo+4(SB),BX
-31 00016 (testdata/386.s:31)	JCS	,
-32 00017 (testdata/386.s:32)	JCS	,16(PC)
-35 00018 (testdata/386.s:35)	CALL	,AX
-36 00019 (testdata/386.s:36)	JMP	,AX
-37 00020 (testdata/386.s:37)	CALL	,*foo(SB)
-38 00021 (testdata/386.s:38)	JMP	,$4
-39 00022 (testdata/386.s:39)	JMP	,16
-40 00023 (testdata/386.s:40)	CALL	,foo(SB)
-42 00024 (testdata/386.s:42)	CALL	,foo+4(SB)(AX*4)
-43 00025 (testdata/386.s:43)	CALL	,4(SP)
-44 00026 (testdata/386.s:44)	CALL	,(AX)
-45 00027 (testdata/386.s:45)	CALL	,(SP)
-47 00028 (testdata/386.s:47)	CALL	,(AX)(AX*4)
-48 00029 (testdata/386.s:48)	CALL	,4(SP)
-49 00030 (testdata/386.s:49)	CALL	,(AX)
-50 00031 (testdata/386.s:50)	CALL	,(SP)
-52 00032 (testdata/386.s:52)	JMP	,(AX)(AX*4)
-55 00033 (testdata/386.s:55)	NOP	,
-56 00034 (testdata/386.s:56)	NOP	AX,
-57 00035 (testdata/386.s:57)	NOP	foo+4(SB),
-60 00036 (testdata/386.s:60)	SHLL	$4,BX
-61 00037 (testdata/386.s:61)	SHLL	$4,foo+4(SB)
-62 00038 (testdata/386.s:62)	SHLL	$4,foo+4(SB):AX
-65 00039 (testdata/386.s:65)	MOVL	AX,BX
-66 00040 (testdata/386.s:66)	MOVL	$4,BX
-69 00041 (testdata/386.s:69)	IMULL	AX,
-70 00042 (testdata/386.s:70)	IMULL	$4,CX
-71 00043 (testdata/386.s:71)	IMULL	AX,BX
-74 00044 (testdata/386.s:74)	CMPPD	X0,$4,X1
-75 00045 (testdata/386.s:75)	CMPPD	X0,foo+4(SB)
-78 00046 (testdata/386.s:78)	PINSRD	(AX),$1,X0
-79 00047 (testdata/386.s:79)	PINSRD	foo+4(FP),$2,X0
-82 00048 (testdata/386.s:82)	RET	,
+5 00001 (testdata/386.s:5)	TEXT	foo(SB), 0, $0
+8 00002 (testdata/386.s:8)	SETCC	AX
+9 00003 (testdata/386.s:9)	SETCC	foo+4(SB)
+12 00004 (testdata/386.s:12)	DIVB	AX
+13 00005 (testdata/386.s:13)	DIVB	foo+4(SB)
+14 00006 (testdata/386.s:14)	PUSHL	$foo+4(SB)
+15 00007 (testdata/386.s:15)	POPL	AX
+18 00008 (testdata/386.s:18)	SUBB	$1, AX
+19 00009 (testdata/386.s:19)	SUBB	$1, foo+4(SB)
+20 00010 (testdata/386.s:20)	SUBB	BX, AX
+21 00011 (testdata/386.s:21)	SUBB	BX, foo+4(SB)
+24 00012 (testdata/386.s:24)	CMPB	AX, $1
+25 00013 (testdata/386.s:25)	CMPB	foo+4(SB), $4
+26 00014 (testdata/386.s:26)	CMPB	BX, AX
+27 00015 (testdata/386.s:27)	CMPB	foo+4(SB), BX
+31 00016 (testdata/386.s:31)	JCS
+32 00017 (testdata/386.s:32)	JCS	16(PC)
+35 00018 (testdata/386.s:35)	CALL	AX
+36 00019 (testdata/386.s:36)	JMP	AX
+37 00020 (testdata/386.s:37)	CALL	*foo(SB)
+38 00021 (testdata/386.s:38)	JMP	$4
+39 00022 (testdata/386.s:39)	JMP	16
+40 00023 (testdata/386.s:40)	CALL	foo(SB)
+42 00024 (testdata/386.s:42)	CALL	foo+4(SB)(AX*4)
+43 00025 (testdata/386.s:43)	CALL	4(SP)
+44 00026 (testdata/386.s:44)	CALL	(AX)
+45 00027 (testdata/386.s:45)	CALL	(SP)
+47 00028 (testdata/386.s:47)	CALL	(AX)(AX*4)
+48 00029 (testdata/386.s:48)	CALL	4(SP)
+49 00030 (testdata/386.s:49)	CALL	(AX)
+50 00031 (testdata/386.s:50)	CALL	(SP)
+52 00032 (testdata/386.s:52)	JMP	(AX)(AX*4)
+55 00033 (testdata/386.s:55)	NOP
+56 00034 (testdata/386.s:56)	NOP	AX
+57 00035 (testdata/386.s:57)	NOP	foo+4(SB)
+60 00036 (testdata/386.s:60)	SHLL	$4, BX
+61 00037 (testdata/386.s:61)	SHLL	$4, foo+4(SB)
+62 00038 (testdata/386.s:62)	SHLL	$4, AX, foo+4(SB)
+65 00039 (testdata/386.s:65)	MOVL	AX, BX
+66 00040 (testdata/386.s:66)	MOVL	$4, BX
+69 00041 (testdata/386.s:69)	IMULL	AX
+70 00042 (testdata/386.s:70)	IMULL	$4, CX
+71 00043 (testdata/386.s:71)	IMULL	AX, BX
+74 00044 (testdata/386.s:74)	CMPPD	X0, X1, 4
+75 00045 (testdata/386.s:75)	CMPPD	X0, foo+4(SB), 4
+78 00046 (testdata/386.s:78)	PINSRD	$1, (AX), X0
+79 00047 (testdata/386.s:79)	PINSRD	$2, foo+4(FP), X0
+83 00048 (testdata/386.s:83)	LOOP
+86 00049 (testdata/386.s:86)	RET
diff --git a/src/cmd/asm/internal/asm/testdata/386.s b/src/cmd/asm/internal/asm/testdata/386.s
index 67c48d0..6bee39f3 100644
--- a/src/cmd/asm/internal/asm/testdata/386.s
+++ b/src/cmd/asm/internal/asm/testdata/386.s
@@ -78,5 +78,9 @@
 	PINSRD	$1, (AX), X0
 	PINSRD	$2, foo+4(FP), X0
 
+// Was bug: LOOP is a branch instruction.
+loop:
+	LOOP	loop
+
 // LTYPE0 nonnon	{ outcode(int($1), &$2); }
 	RET
diff --git a/src/cmd/asm/internal/asm/testdata/amd64.out b/src/cmd/asm/internal/asm/testdata/amd64.out
index a17ae0f..51932fa 100644
--- a/src/cmd/asm/internal/asm/testdata/amd64.out
+++ b/src/cmd/asm/internal/asm/testdata/amd64.out
@@ -1,56 +1,57 @@
-5 00001 (testdata/amd64.s:5)	TEXT	foo(SB),$0
-8 00002 (testdata/amd64.s:8)	NEGQ	,R11
-9 00003 (testdata/amd64.s:9)	NEGQ	,4(R11)
-10 00004 (testdata/amd64.s:10)	NEGQ	,foo+4(SB)
-13 00005 (testdata/amd64.s:13)	INT	$4,
-14 00006 (testdata/amd64.s:14)	DIVB	R11,
-15 00007 (testdata/amd64.s:15)	DIVB	4(R11),
-16 00008 (testdata/amd64.s:16)	DIVB	foo+4(SB),
-19 00009 (testdata/amd64.s:19)	SUBQ	$4,DI
-20 00010 (testdata/amd64.s:20)	SUBQ	R11,DI
-21 00011 (testdata/amd64.s:21)	SUBQ	4(R11),DI
-22 00012 (testdata/amd64.s:22)	SUBQ	foo+4(SB),DI
-23 00013 (testdata/amd64.s:23)	SUBQ	$4,8(R12)
-24 00014 (testdata/amd64.s:24)	SUBQ	R11,8(R12)
-25 00015 (testdata/amd64.s:25)	SUBQ	R11,foo+4(SB)
-28 00016 (testdata/amd64.s:28)	CMPB	CX,$4
-32 00017 (testdata/amd64.s:32)	JCS	,13(PC)
-33 00018 (testdata/amd64.s:33)	JCS	,17
-36 00019 (testdata/amd64.s:36)	JMP	,15(PC)
-37 00020 (testdata/amd64.s:37)	JMP	,17
-38 00021 (testdata/amd64.s:38)	JMP	,foo+4(SB)
-39 00022 (testdata/amd64.s:39)	JMP	,bar<>+4(SB)
-40 00023 (testdata/amd64.s:40)	JMP	,bar<>+4(SB)(R11*4)
-41 00024 (testdata/amd64.s:41)	JMP	,4(SP)
-42 00025 (testdata/amd64.s:42)	JMP	,(R12)
-44 00026 (testdata/amd64.s:44)	JMP	,(R12)(R13*4)
-45 00027 (testdata/amd64.s:45)	JMP	,(AX)
-46 00028 (testdata/amd64.s:46)	JMP	,(SP)
-48 00029 (testdata/amd64.s:48)	JMP	,(AX)(AX*4)
-49 00030 (testdata/amd64.s:49)	JMP	,4(SP)
-50 00031 (testdata/amd64.s:50)	JMP	,(R12)
-52 00032 (testdata/amd64.s:52)	JMP	,(R12)(R13*4)
-53 00033 (testdata/amd64.s:53)	JMP	,(AX)
-54 00034 (testdata/amd64.s:54)	JMP	,(SP)
-56 00035 (testdata/amd64.s:56)	JMP	,(AX)(AX*4)
-57 00036 (testdata/amd64.s:57)	JMP	,R13
-60 00037 (testdata/amd64.s:60)	NOP	,
-61 00038 (testdata/amd64.s:61)	NOP	AX,
-62 00039 (testdata/amd64.s:62)	NOP	foo+4(SB),
-65 00040 (testdata/amd64.s:65)	SHLL	R11,R12
-66 00041 (testdata/amd64.s:66)	SHLL	R11,foo+4(SB)
-67 00042 (testdata/amd64.s:67)	SHLL	R11,R11:AX
-70 00043 (testdata/amd64.s:70)	MOVL	AX,R11
-71 00044 (testdata/amd64.s:71)	MOVL	$4,R11
-72 00045 (testdata/amd64.s:72)	MOVL	AX,AX:CS
-75 00046 (testdata/amd64.s:75)	IMULB	$4,
-76 00047 (testdata/amd64.s:76)	IMULB	R11,
-77 00048 (testdata/amd64.s:77)	IMULB	$4,R11
-78 00049 (testdata/amd64.s:78)	IMULB	R11,R12
-79 00050 (testdata/amd64.s:79)	IMULB	R11,foo+4(SB)
-82 00051 (testdata/amd64.s:82)	CMPPD	R11,$4,R12
-83 00052 (testdata/amd64.s:83)	CMPPD	R11,foo+4(SB)
-86 00053 (testdata/amd64.s:86)	PINSRW	R11,$4,AX
-87 00054 (testdata/amd64.s:87)	PINSRW	foo+4(SB),$4,AX
-90 00055 (testdata/amd64.s:90)	RETFL	$4,
-93 00056 (testdata/amd64.s:93)	RET	,
+5 00001 (testdata/amd64.s:5)	TEXT	foo(SB), 0, $0
+8 00002 (testdata/amd64.s:8)	NEGQ	R11
+9 00003 (testdata/amd64.s:9)	NEGQ	4(R11)
+10 00004 (testdata/amd64.s:10)	NEGQ	foo+4(SB)
+13 00005 (testdata/amd64.s:13)	INT	$4
+14 00006 (testdata/amd64.s:14)	DIVB	R11
+15 00007 (testdata/amd64.s:15)	DIVB	4(R11)
+16 00008 (testdata/amd64.s:16)	DIVB	foo+4(SB)
+19 00009 (testdata/amd64.s:19)	SUBQ	$4, DI
+20 00010 (testdata/amd64.s:20)	SUBQ	R11, DI
+21 00011 (testdata/amd64.s:21)	SUBQ	4(R11), DI
+22 00012 (testdata/amd64.s:22)	SUBQ	foo+4(SB), DI
+23 00013 (testdata/amd64.s:23)	SUBQ	$4, 8(R12)
+24 00014 (testdata/amd64.s:24)	SUBQ	R11, 8(R12)
+25 00015 (testdata/amd64.s:25)	SUBQ	R11, foo+4(SB)
+28 00016 (testdata/amd64.s:28)	CMPB	CX, $4
+32 00017 (testdata/amd64.s:32)	JCS	13(PC)
+33 00018 (testdata/amd64.s:33)	JCS	17
+36 00019 (testdata/amd64.s:36)	JMP	15(PC)
+37 00020 (testdata/amd64.s:37)	JMP	17
+38 00021 (testdata/amd64.s:38)	JMP	foo+4(SB)
+39 00022 (testdata/amd64.s:39)	JMP	bar<>+4(SB)
+40 00023 (testdata/amd64.s:40)	JMP	bar<>+4(SB)(R11*4)
+41 00024 (testdata/amd64.s:41)	JMP	4(SP)
+42 00025 (testdata/amd64.s:42)	JMP	(R12)
+44 00026 (testdata/amd64.s:44)	JMP	(R12)(R13*4)
+45 00027 (testdata/amd64.s:45)	JMP	(AX)
+46 00028 (testdata/amd64.s:46)	JMP	(SP)
+48 00029 (testdata/amd64.s:48)	JMP	(AX)(AX*4)
+49 00030 (testdata/amd64.s:49)	JMP	4(SP)
+50 00031 (testdata/amd64.s:50)	JMP	(R12)
+52 00032 (testdata/amd64.s:52)	JMP	(R12)(R13*4)
+53 00033 (testdata/amd64.s:53)	JMP	(AX)
+54 00034 (testdata/amd64.s:54)	JMP	(SP)
+56 00035 (testdata/amd64.s:56)	JMP	(AX)(AX*4)
+57 00036 (testdata/amd64.s:57)	JMP	R13
+60 00037 (testdata/amd64.s:60)	NOP
+61 00038 (testdata/amd64.s:61)	NOP	AX
+62 00039 (testdata/amd64.s:62)	NOP	foo+4(SB)
+65 00040 (testdata/amd64.s:65)	SHLL	R11, R12
+66 00041 (testdata/amd64.s:66)	SHLL	R11, foo+4(SB)
+67 00042 (testdata/amd64.s:67)	SHLL	R11, AX, R11
+70 00043 (testdata/amd64.s:70)	MOVL	AX, R11
+71 00044 (testdata/amd64.s:71)	MOVL	$4, R11
+72 00045 (testdata/amd64.s:72)	MOVL	AX, CS, AX
+75 00046 (testdata/amd64.s:75)	IMULB	$4
+76 00047 (testdata/amd64.s:76)	IMULB	R11
+77 00048 (testdata/amd64.s:77)	IMULB	$4, R11
+78 00049 (testdata/amd64.s:78)	IMULB	R11, R12
+79 00050 (testdata/amd64.s:79)	IMULB	R11, foo+4(SB)
+82 00051 (testdata/amd64.s:82)	CMPPD	R11, R12, 4
+83 00052 (testdata/amd64.s:83)	CMPPD	R11, foo+4(SB), 4
+86 00053 (testdata/amd64.s:86)	PINSRW	$4, R11, AX
+87 00054 (testdata/amd64.s:87)	PINSRW	$4, foo+4(SB), AX
+90 00055 (testdata/amd64.s:90)	RETFL	$4
+94 00056 (testdata/amd64.s:94)	LOOP
+97 00057 (testdata/amd64.s:97)	RET
diff --git a/src/cmd/asm/internal/asm/testdata/amd64.s b/src/cmd/asm/internal/asm/testdata/amd64.s
index cb925f2..4100576 100644
--- a/src/cmd/asm/internal/asm/testdata/amd64.s
+++ b/src/cmd/asm/internal/asm/testdata/amd64.s
@@ -64,7 +64,7 @@
 // LTYPES spec5	{ outcode($1, &$2); }
 	SHLL	R11, R12
 	SHLL	R11, foo+4(SB)
-	SHLL	R11, R11:AX
+	SHLL	R11, R11:AX // Old syntax, still accepted.
 
 // LTYPEM spec6	{ outcode($1, &$2); }
 	MOVL	AX, R11
@@ -89,5 +89,9 @@
 // LTYPERT spec10	{ outcode($1, &$2); }
 	RETFL	$4
 
+// Was bug: LOOP is a branch instruction.
+loop:
+	LOOP	loop
+
 // LTYPE0 nonnon	{ outcode($1, &$2); }
 	RET
diff --git a/src/cmd/asm/internal/asm/testdata/arm.out b/src/cmd/asm/internal/asm/testdata/arm.out
index 9e6f080..0e23a02 100644
--- a/src/cmd/asm/internal/asm/testdata/arm.out
+++ b/src/cmd/asm/internal/asm/testdata/arm.out
@@ -1,53 +1,55 @@
-5 00001 (testdata/arm.s:5)	TEXT	foo(SB),0,$0
-14 00002 (testdata/arm.s:14)	ADD	$1,R2,R3
-15 00003 (testdata/arm.s:15)	ADD	R1<<R2,R3,R4
-16 00004 (testdata/arm.s:16)	ADD	R1>>R2,R3,R4
-17 00005 (testdata/arm.s:17)	ADD	R1@>R2,R3,R4
-18 00006 (testdata/arm.s:18)	ADD	R1->R2,R3,R4
-19 00007 (testdata/arm.s:19)	ADD	R1,R2,R3
-20 00008 (testdata/arm.s:20)	ADD	R1<<R2,R3,R4
-30 00009 (testdata/arm.s:30)	ADD	$1,R2
-31 00010 (testdata/arm.s:31)	ADD	R1<<R2,R3
-32 00011 (testdata/arm.s:32)	ADD	R1>>R2,R3
-33 00012 (testdata/arm.s:33)	ADD	R1@>R2,R3
-34 00013 (testdata/arm.s:34)	ADD	R1->R2,R3
-35 00014 (testdata/arm.s:35)	ADD	R1,R2
-44 00015 (testdata/arm.s:44)	CLZ.S	R1,R2
-53 00016 (testdata/arm.s:53)	MOVW.S	R1,R2
-54 00017 (testdata/arm.s:54)	MOVW.S	$1,R2
-55 00018 (testdata/arm.s:55)	MOVW.S	R1<<R2,R3
-64 00019 (testdata/arm.s:64)	JMP.S	,20(PC)
-70 00020 (testdata/arm.s:70)	JMP.S	,(R2)
-71 00021 (testdata/arm.s:71)	JMP.S	,foo(SB)
-72 00022 (testdata/arm.s:72)	JMP.S	,bar<>(SB)
-81 00023 (testdata/arm.s:81)	BX	(R2),
-90 00024 (testdata/arm.s:90)	BEQ	,25(PC)
-99 00025 (testdata/arm.s:99)	SWI.S	,R1
-100 00026 (testdata/arm.s:100)	SWI.S	,(R1)
-101 00027 (testdata/arm.s:101)	SWI.S	,foo(SB)
-110 00028 (testdata/arm.s:110)	CMP.S	$1,R2,
-111 00029 (testdata/arm.s:111)	CMP.S	R1<<R2,R3,
-112 00030 (testdata/arm.s:112)	CMP.S	R1,R2,
-126 00031 (testdata/arm.s:126)	MOVM	(R1),[R2,R5,R8,g]
-127 00032 (testdata/arm.s:127)	MOVM	(R1),[R2,R3,R4,R5]
-128 00033 (testdata/arm.s:128)	MOVM.S	(R1),[R2]
-139 00034 (testdata/arm.s:139)	MOVM	[R2,R5,R8,g],(R1)
-140 00035 (testdata/arm.s:140)	MOVM	[R2,R3,R4,R5],(R1)
-141 00036 (testdata/arm.s:141)	MOVM.S	[R2],(R1)
-150 00037 (testdata/arm.s:150)	STREX.S	(R2),R1,R3
-156 00038 (testdata/arm.s:156)	STREX.S	(R2),R1,R1
-162 00039 (testdata/arm.s:162)	STREX.S	(R2),R3,R3
-170 00040 (testdata/arm.s:170)	CASE.S	R1,
-179 00041 (testdata/arm.s:179)	WORD	,$1234
-188 00042 (testdata/arm.s:188)	ABSF.S	F1,F2
-194 00043 (testdata/arm.s:194)	ADDD.S	F1,F2
-195 00044 (testdata/arm.s:195)	ADDD.S	$(0.5),F2
-201 00045 (testdata/arm.s:201)	ADDD.S	F1,F2,F3
-202 00046 (testdata/arm.s:202)	ADDD.S	$(0.5),F2,F3
-208 00047 (testdata/arm.s:208)	CMPD.S	F1,F2
-242 00048 (testdata/arm.s:242)	MULL	R1,R2,(R3, R4)
-254 00049 (testdata/arm.s:254)	MULAWT	R1,R2,R3, R4
-262 00050 (testdata/arm.s:262)	PLD	(R1),
-263 00051 (testdata/arm.s:263)	PLD	4(R1),
-272 00052 (testdata/arm.s:272)	RET	,
-281 00053 (testdata/arm.s:281)	END	,
+5 00001 (testdata/arm.s:5)	TEXT	foo(SB), 0, $0
+14 00002 (testdata/arm.s:14)	ADD	$1, R2, R3
+15 00003 (testdata/arm.s:15)	ADD	R1<<R2, R3, R4
+16 00004 (testdata/arm.s:16)	ADD	R1>>R2, R3, R4
+17 00005 (testdata/arm.s:17)	ADD	R1@>R2, R3, R4
+18 00006 (testdata/arm.s:18)	ADD	R1->R2, R3, R4
+19 00007 (testdata/arm.s:19)	ADD	R1, R2, R3
+20 00008 (testdata/arm.s:20)	ADD	R1<<R2, R3, R4
+30 00009 (testdata/arm.s:30)	ADD	$1, R2
+31 00010 (testdata/arm.s:31)	ADD	R1<<R2, R3
+32 00011 (testdata/arm.s:32)	ADD	R1>>R2, R3
+33 00012 (testdata/arm.s:33)	ADD	R1@>R2, R3
+34 00013 (testdata/arm.s:34)	ADD	R1->R2, R3
+35 00014 (testdata/arm.s:35)	ADD	R1, R2
+44 00015 (testdata/arm.s:44)	CLZ.S	R1, R2
+53 00016 (testdata/arm.s:53)	MOVW.S	R1, R2
+54 00017 (testdata/arm.s:54)	MOVW.S	$1, R2
+55 00018 (testdata/arm.s:55)	MOVW.S	R1<<R2, R3
+64 00019 (testdata/arm.s:64)	JMP.S	20(PC)
+70 00020 (testdata/arm.s:70)	JMP.S	(R2)
+71 00021 (testdata/arm.s:71)	JMP.S	foo(SB)
+72 00022 (testdata/arm.s:72)	JMP.S	bar<>(SB)
+81 00023 (testdata/arm.s:81)	BX	(R2)
+90 00024 (testdata/arm.s:90)	BEQ	25(PC)
+99 00025 (testdata/arm.s:99)	SWI.S	R1
+100 00026 (testdata/arm.s:100)	SWI.S	(R1)
+101 00027 (testdata/arm.s:101)	SWI.S	foo(SB)
+110 00028 (testdata/arm.s:110)	CMP.S	$1, R2
+111 00029 (testdata/arm.s:111)	CMP.S	R1<<R2, R3
+112 00030 (testdata/arm.s:112)	CMP.S	R1, R2
+126 00031 (testdata/arm.s:126)	MOVM	(R1), [R2,R5,R8,g]
+127 00032 (testdata/arm.s:127)	MOVM	(R1), [R2,R3,R4,R5]
+128 00033 (testdata/arm.s:128)	MOVM.S	(R1), [R2]
+139 00034 (testdata/arm.s:139)	MOVM	[R2,R5,R8,g], (R1)
+140 00035 (testdata/arm.s:140)	MOVM	[R2,R3,R4,R5], (R1)
+141 00036 (testdata/arm.s:141)	MOVM.S	[R2], (R1)
+150 00037 (testdata/arm.s:150)	STREX.S	(R2), R1, R3
+156 00038 (testdata/arm.s:156)	STREX.S	(R2), R1, R1
+162 00039 (testdata/arm.s:162)	STREX.S	(R2), R3, R3
+170 00040 (testdata/arm.s:170)	CASE.S	R1
+179 00041 (testdata/arm.s:179)	WORD	$1234
+188 00042 (testdata/arm.s:188)	ABSF.S	F1, F2
+194 00043 (testdata/arm.s:194)	ADDD.S	F1, F2
+195 00044 (testdata/arm.s:195)	ADDD.S	$(0.5), F2
+201 00045 (testdata/arm.s:201)	ADDD.S	F1, F2, F3
+202 00046 (testdata/arm.s:202)	ADDD.S	$(0.5), F2, F3
+208 00047 (testdata/arm.s:208)	CMPD.S	F1, F2
+232 00048 (testdata/arm.s:232)	MRC	$8301712627
+233 00049 (testdata/arm.s:233)	MRC	$8300664051
+242 00050 (testdata/arm.s:242)	MULL	R1, R2, (R3, R4)
+254 00051 (testdata/arm.s:254)	MULAWT	R1, R2, R3, R4
+262 00052 (testdata/arm.s:262)	PLD	(R1)
+263 00053 (testdata/arm.s:263)	PLD	4(R1)
+272 00054 (testdata/arm.s:272)	RET
+281 00055 (testdata/arm.s:281)	END
diff --git a/src/cmd/asm/internal/asm/testdata/arm.s b/src/cmd/asm/internal/asm/testdata/arm.s
index 8031075..3563919 100644
--- a/src/cmd/asm/internal/asm/testdata/arm.s
+++ b/src/cmd/asm/internal/asm/testdata/arm.s
@@ -229,8 +229,8 @@
 //			(1<<4));			/* must be set */
 //		outcode(AMRC, Always, &nullgen, 0, &g);
 //	}
-// TODO: Disabled until printout for this instruction is the same for 32 and 64 bits.
-//	MRC.S	4, 6, R1, C2, C3, 7
+	MRC.S	4, 6, R1, C2, C3, 7
+	MCR.S	4, 6, R1, C2, C3, 7
 
 //
 // MULL r1,r2,(hi,lo)
diff --git a/src/cmd/asm/internal/asm/testdata/ppc64.out b/src/cmd/asm/internal/asm/testdata/ppc64.out
index da9c1b4..79a995d 100644
--- a/src/cmd/asm/internal/asm/testdata/ppc64.out
+++ b/src/cmd/asm/internal/asm/testdata/ppc64.out
@@ -1,110 +1,110 @@
-5 00001 (testdata/ppc64.s:5)	TEXT	foo(SB),$0
-15 00002 (testdata/ppc64.s:15)	MOVW	R1,R2
-21 00003 (testdata/ppc64.s:21)	MOVW	foo<>+3(SB),R2
-22 00004 (testdata/ppc64.s:22)	MOVW	16(R1),R2
-28 00005 (testdata/ppc64.s:28)	MOVW	(R1),R2
-29 00006 (testdata/ppc64.s:29)	MOVW	(R1+R2),R3
-35 00007 (testdata/ppc64.s:35)	MOVW	R1,R2
-41 00008 (testdata/ppc64.s:41)	MOVB	foo<>+3(SB),R2
-42 00009 (testdata/ppc64.s:42)	MOVB	16(R1),R2
-48 00010 (testdata/ppc64.s:48)	MOVB	(R1),R2
-49 00011 (testdata/ppc64.s:49)	MOVB	(R1+R2),R3
-58 00012 (testdata/ppc64.s:58)	FMOVD	foo<>+3(SB),F2
-59 00013 (testdata/ppc64.s:59)	FMOVD	16(R1),F2
-65 00014 (testdata/ppc64.s:65)	FMOVD	(R1),F2
-71 00015 (testdata/ppc64.s:71)	FMOVD	$(0.10000000000000001),F2
-77 00016 (testdata/ppc64.s:77)	FMOVD	F1,F2
-83 00017 (testdata/ppc64.s:83)	FMOVD	F2,foo<>+3(SB)
-84 00018 (testdata/ppc64.s:84)	FMOVD	F2,16(R1)
-90 00019 (testdata/ppc64.s:90)	FMOVD	F2,(R1)
-99 00020 (testdata/ppc64.s:99)	MOVW	R1,foo<>+3(SB)
-100 00021 (testdata/ppc64.s:100)	MOVW	R1,16(R2)
-106 00022 (testdata/ppc64.s:106)	MOVW	R1,(R1)
-107 00023 (testdata/ppc64.s:107)	MOVW	R1,(R2+R3)
-113 00024 (testdata/ppc64.s:113)	MOVB	R1,foo<>+3(SB)
-114 00025 (testdata/ppc64.s:114)	MOVB	R1,16(R2)
-120 00026 (testdata/ppc64.s:120)	MOVB	R1,(R1)
-121 00027 (testdata/ppc64.s:121)	MOVB	R1,(R2+R3)
-129 00028 (testdata/ppc64.s:129)	FMOVD	F1,foo<>+3(SB)
-130 00029 (testdata/ppc64.s:130)	FMOVD	F1,16(R2)
-136 00030 (testdata/ppc64.s:136)	FMOVD	F1,(R1)
-145 00031 (testdata/ppc64.s:145)	MOVFL	FPSCR,F1
-151 00032 (testdata/ppc64.s:151)	MOVFL	F1,FPSCR
-157 00033 (testdata/ppc64.s:157)	MOVFL	F1,$4,FPSCR
-163 00034 (testdata/ppc64.s:163)	MOVFL	FPSCR,CR0
-184 00035 (testdata/ppc64.s:184)	MOVW	R1,CR1
-190 00036 (testdata/ppc64.s:190)	MOVW	R1,CR
-202 00037 (testdata/ppc64.s:202)	ADD	R1,R2,R3
-208 00038 (testdata/ppc64.s:208)	ADD	$1,R2,R3
-220 00039 (testdata/ppc64.s:220)	ADD	R1,R2
-226 00040 (testdata/ppc64.s:226)	ADD	$4,R1
-232 00041 (testdata/ppc64.s:232)	ADDE	R1,R2,R3
-238 00042 (testdata/ppc64.s:238)	ADDE	R1,R2
-244 00043 (testdata/ppc64.s:244)	SLW	R1,R2,R3
-250 00044 (testdata/ppc64.s:250)	SLW	R1,R2
-256 00045 (testdata/ppc64.s:256)	SLW	$4,R1,R2
-262 00046 (testdata/ppc64.s:262)	SLW	$4,R1
-268 00047 (testdata/ppc64.s:268)	SLW	$4,R1
-274 00048 (testdata/ppc64.s:274)	SUBME	R1,R1
-292 00049 (testdata/ppc64.s:292)	MOVW	$1,R1
-298 00050 (testdata/ppc64.s:298)	MOVW	$1,R1
-299 00051 (testdata/ppc64.s:299)	MOVW	$foo(SB),R1
-323 00052 (testdata/ppc64.s:323)	MOVFL	CR0,CR1
-335 00053 (testdata/ppc64.s:335)	MOVW	CR,R1
-341 00054 (testdata/ppc64.s:341)	MOVW	SPR(0),R1
-342 00055 (testdata/ppc64.s:342)	MOVW	SPR(7),R1
-348 00056 (testdata/ppc64.s:348)	MOVW	LR,R1
-349 00057 (testdata/ppc64.s:349)	MOVW	CTR,R1
-355 00058 (testdata/ppc64.s:355)	MOVW	R1,LR
-356 00059 (testdata/ppc64.s:356)	MOVW	R1,CTR
-368 00060 (testdata/ppc64.s:368)	MOVW	R1,SPR(7)
-380 00061 (testdata/ppc64.s:380)	JMP	,62(PC)
-381 00062 (testdata/ppc64.s:381)	JMP	,61
-387 00063 (testdata/ppc64.s:387)	JMP	,4(R1)
-388 00064 (testdata/ppc64.s:388)	JMP	,foo(SB)
-394 00065 (testdata/ppc64.s:394)	JMP	,CTR
-413 00066 (testdata/ppc64.s:413)	BEQ	CR1,67(PC)
-414 00067 (testdata/ppc64.s:414)	BEQ	CR1,66
-440 00068 (testdata/ppc64.s:440)	BC	4,CTR
-450 00069 (testdata/ppc64.s:450)	BC	$3,R4,66
-470 00070 (testdata/ppc64.s:470)	BC	$3,R3,LR
-500 00071 (testdata/ppc64.s:500)	FABS	F1,F2
-506 00072 (testdata/ppc64.s:506)	FADD	F1,F2
-512 00073 (testdata/ppc64.s:512)	FADD	F1,F2,F3
-518 00074 (testdata/ppc64.s:518)	FMADD	F1,F2,F3,F4
-524 00075 (testdata/ppc64.s:524)	FCMPU	F1,F2
-530 00076 (testdata/ppc64.s:530)	FCMPU	F1,F2,CR0
-539 00077 (testdata/ppc64.s:539)	CMP	R1,R2
-545 00078 (testdata/ppc64.s:545)	CMP	R1,$4
-551 00079 (testdata/ppc64.s:551)	CMP	R1,CR0,R2
-557 00080 (testdata/ppc64.s:557)	CMP	R1,CR0,$4
-566 00081 (testdata/ppc64.s:566)	RLDC	$4,R1,$5,R2
-572 00082 (testdata/ppc64.s:572)	RLDC	$26,R1,$201326592,R2
-578 00083 (testdata/ppc64.s:578)	RLDC	R1,R2,$4,R3
-584 00084 (testdata/ppc64.s:584)	RLWMI	R1,R2,$201326592,R3
-593 00085 (testdata/ppc64.s:593)	MOVMW	foo(SB),R2
-594 00086 (testdata/ppc64.s:594)	MOVMW	4(R1),R2
-600 00087 (testdata/ppc64.s:600)	MOVMW	R1,foo(SB)
-601 00088 (testdata/ppc64.s:601)	MOVMW	R1,4(R2)
-611 00089 (testdata/ppc64.s:611)	LSW	(R1),R2
-612 00090 (testdata/ppc64.s:612)	LSW	(R1+R2),R3
-618 00091 (testdata/ppc64.s:618)	LSW	(R1+NONE),R2
-619 00092 (testdata/ppc64.s:619)	LSW	(R1+NONE),R3
-625 00093 (testdata/ppc64.s:625)	STSW	R1,(R2)
-626 00094 (testdata/ppc64.s:626)	STSW	R1,(R2+R3)
-632 00095 (testdata/ppc64.s:632)	STSW	R1,(R2+NONE)
-633 00096 (testdata/ppc64.s:633)	STSW	R1,(R2+NONE)
-639 00097 (testdata/ppc64.s:639)	MOVHBR	(R1),R2
-640 00098 (testdata/ppc64.s:640)	MOVHBR	(R1+R2),R3
-646 00099 (testdata/ppc64.s:646)	MOVHBR	R1,(R2)
-647 00100 (testdata/ppc64.s:647)	MOVHBR	R1,(R2+R3)
-653 00101 (testdata/ppc64.s:653)	DCBF	(R1),
-654 00102 (testdata/ppc64.s:654)	DCBF	(R1),
-663 00103 (testdata/ppc64.s:663)	NOP	,
-669 00104 (testdata/ppc64.s:669)	NOP	R2,
-675 00105 (testdata/ppc64.s:675)	NOP	F2,
-681 00106 (testdata/ppc64.s:681)	NOP	R2,
-687 00107 (testdata/ppc64.s:687)	NOP	F2,
-693 00108 (testdata/ppc64.s:693)	NOP	$4,
-701 00109 (testdata/ppc64.s:701)	RET	,
-709 00110 (testdata/ppc64.s:709)	END	,
+5 00001 (testdata/ppc64.s:5)	TEXT	foo(SB), 0, $0
+15 00002 (testdata/ppc64.s:15)	MOVW	R1, R2
+21 00003 (testdata/ppc64.s:21)	MOVW	foo<>+3(SB), R2
+22 00004 (testdata/ppc64.s:22)	MOVW	16(R1), R2
+28 00005 (testdata/ppc64.s:28)	MOVW	(R1), R2
+29 00006 (testdata/ppc64.s:29)	MOVW	(R1)(R2*1), R3
+35 00007 (testdata/ppc64.s:35)	MOVW	R1, R2
+41 00008 (testdata/ppc64.s:41)	MOVB	foo<>+3(SB), R2
+42 00009 (testdata/ppc64.s:42)	MOVB	16(R1), R2
+48 00010 (testdata/ppc64.s:48)	MOVB	(R1), R2
+49 00011 (testdata/ppc64.s:49)	MOVB	(R1)(R2*1), R3
+58 00012 (testdata/ppc64.s:58)	FMOVD	foo<>+3(SB), F2
+59 00013 (testdata/ppc64.s:59)	FMOVD	16(R1), F2
+65 00014 (testdata/ppc64.s:65)	FMOVD	(R1), F2
+71 00015 (testdata/ppc64.s:71)	FMOVD	$(0.10000000000000001), F2
+77 00016 (testdata/ppc64.s:77)	FMOVD	F1, F2
+83 00017 (testdata/ppc64.s:83)	FMOVD	F2, foo<>+3(SB)
+84 00018 (testdata/ppc64.s:84)	FMOVD	F2, 16(R1)
+90 00019 (testdata/ppc64.s:90)	FMOVD	F2, (R1)
+99 00020 (testdata/ppc64.s:99)	MOVW	R1, foo<>+3(SB)
+100 00021 (testdata/ppc64.s:100)	MOVW	R1, 16(R2)
+106 00022 (testdata/ppc64.s:106)	MOVW	R1, (R1)
+107 00023 (testdata/ppc64.s:107)	MOVW	R1, (R2)(R3*1)
+113 00024 (testdata/ppc64.s:113)	MOVB	R1, foo<>+3(SB)
+114 00025 (testdata/ppc64.s:114)	MOVB	R1, 16(R2)
+120 00026 (testdata/ppc64.s:120)	MOVB	R1, (R1)
+121 00027 (testdata/ppc64.s:121)	MOVB	R1, (R2)(R3*1)
+129 00028 (testdata/ppc64.s:129)	FMOVD	F1, foo<>+3(SB)
+130 00029 (testdata/ppc64.s:130)	FMOVD	F1, 16(R2)
+136 00030 (testdata/ppc64.s:136)	FMOVD	F1, (R1)
+145 00031 (testdata/ppc64.s:145)	MOVFL	FPSCR, F1
+151 00032 (testdata/ppc64.s:151)	MOVFL	F1, FPSCR
+157 00033 (testdata/ppc64.s:157)	MOVFL	F1, $4, FPSCR
+163 00034 (testdata/ppc64.s:163)	MOVFL	FPSCR, CR0
+184 00035 (testdata/ppc64.s:184)	MOVW	R1, CR1
+190 00036 (testdata/ppc64.s:190)	MOVW	R1, CR
+202 00037 (testdata/ppc64.s:202)	ADD	R1, R2, R3
+208 00038 (testdata/ppc64.s:208)	ADD	$1, R2, R3
+220 00039 (testdata/ppc64.s:220)	ADD	R1, R2
+226 00040 (testdata/ppc64.s:226)	ADD	$4, R1
+232 00041 (testdata/ppc64.s:232)	ADDE	R1, R2, R3
+238 00042 (testdata/ppc64.s:238)	ADDE	R1, R2
+244 00043 (testdata/ppc64.s:244)	SLW	R1, R2, R3
+250 00044 (testdata/ppc64.s:250)	SLW	R1, R2
+256 00045 (testdata/ppc64.s:256)	SLW	$4, R1, R2
+262 00046 (testdata/ppc64.s:262)	SLW	$4, R1
+268 00047 (testdata/ppc64.s:268)	SLW	$4, R1
+274 00048 (testdata/ppc64.s:274)	SUBME	R1, R1
+292 00049 (testdata/ppc64.s:292)	MOVW	$1, R1
+298 00050 (testdata/ppc64.s:298)	MOVW	$1, R1
+299 00051 (testdata/ppc64.s:299)	MOVW	$foo(SB), R1
+323 00052 (testdata/ppc64.s:323)	MOVFL	CR0, CR1
+335 00053 (testdata/ppc64.s:335)	MOVW	CR, R1
+341 00054 (testdata/ppc64.s:341)	MOVW	SPR(0), R1
+342 00055 (testdata/ppc64.s:342)	MOVW	SPR(7), R1
+348 00056 (testdata/ppc64.s:348)	MOVW	LR, R1
+349 00057 (testdata/ppc64.s:349)	MOVW	CTR, R1
+355 00058 (testdata/ppc64.s:355)	MOVW	R1, LR
+356 00059 (testdata/ppc64.s:356)	MOVW	R1, CTR
+368 00060 (testdata/ppc64.s:368)	MOVW	R1, SPR(7)
+380 00061 (testdata/ppc64.s:380)	JMP	62(PC)
+381 00062 (testdata/ppc64.s:381)	JMP	61
+387 00063 (testdata/ppc64.s:387)	JMP	4(R1)
+388 00064 (testdata/ppc64.s:388)	JMP	foo(SB)
+394 00065 (testdata/ppc64.s:394)	JMP	CTR
+413 00066 (testdata/ppc64.s:413)	BEQ	CR1, 67(PC)
+414 00067 (testdata/ppc64.s:414)	BEQ	CR1, 66
+440 00068 (testdata/ppc64.s:440)	BC	4, CTR
+450 00069 (testdata/ppc64.s:450)	BC	$3, R4, 66
+470 00070 (testdata/ppc64.s:470)	BC	$3, R3, LR
+500 00071 (testdata/ppc64.s:500)	FABS	F1, F2
+506 00072 (testdata/ppc64.s:506)	FADD	F1, F2
+512 00073 (testdata/ppc64.s:512)	FADD	F1, F2, F3
+518 00074 (testdata/ppc64.s:518)	FMADD	F1, F2, F3, F4
+524 00075 (testdata/ppc64.s:524)	FCMPU	F1, F2
+530 00076 (testdata/ppc64.s:530)	FCMPU	F1, F2, CR0
+539 00077 (testdata/ppc64.s:539)	CMP	R1, R2
+545 00078 (testdata/ppc64.s:545)	CMP	R1, $4
+551 00079 (testdata/ppc64.s:551)	CMP	R1, CR0, R2
+557 00080 (testdata/ppc64.s:557)	CMP	R1, CR0, $4
+566 00081 (testdata/ppc64.s:566)	RLDC	$4, R1, $5, R2
+572 00082 (testdata/ppc64.s:572)	RLDC	$26, R1, $201326592, R2
+578 00083 (testdata/ppc64.s:578)	RLDC	R1, R2, $4, R3
+584 00084 (testdata/ppc64.s:584)	RLWMI	R1, R2, $201326592, R3
+593 00085 (testdata/ppc64.s:593)	MOVMW	foo(SB), R2
+594 00086 (testdata/ppc64.s:594)	MOVMW	4(R1), R2
+600 00087 (testdata/ppc64.s:600)	MOVMW	R1, foo(SB)
+601 00088 (testdata/ppc64.s:601)	MOVMW	R1, 4(R2)
+611 00089 (testdata/ppc64.s:611)	LSW	(R1), R2
+612 00090 (testdata/ppc64.s:612)	LSW	(R1)(R2*1), R3
+618 00091 (testdata/ppc64.s:618)	LSW	(R1), $1, R2
+619 00092 (testdata/ppc64.s:619)	LSW	(R1)(R2*1), $1, R3
+625 00093 (testdata/ppc64.s:625)	STSW	R1, (R2)
+626 00094 (testdata/ppc64.s:626)	STSW	R1, (R2)(R3*1)
+632 00095 (testdata/ppc64.s:632)	STSW	R1, $1, (R2)
+633 00096 (testdata/ppc64.s:633)	STSW	R1, $1, (R2)(R3*1)
+639 00097 (testdata/ppc64.s:639)	MOVHBR	(R1), R2
+640 00098 (testdata/ppc64.s:640)	MOVHBR	(R1)(R2*1), R3
+646 00099 (testdata/ppc64.s:646)	MOVHBR	R1, (R2)
+647 00100 (testdata/ppc64.s:647)	MOVHBR	R1, (R2)(R3*1)
+653 00101 (testdata/ppc64.s:653)	DCBF	(R1)
+654 00102 (testdata/ppc64.s:654)	DCBF	(R1)(R2*1)
+663 00103 (testdata/ppc64.s:663)	NOP
+669 00104 (testdata/ppc64.s:669)	NOP	R2
+675 00105 (testdata/ppc64.s:675)	NOP	F2
+681 00106 (testdata/ppc64.s:681)	NOP	R2
+687 00107 (testdata/ppc64.s:687)	NOP	F2
+693 00108 (testdata/ppc64.s:693)	NOP	$4
+701 00109 (testdata/ppc64.s:701)	RET
+709 00110 (testdata/ppc64.s:709)	END
diff --git a/src/cmd/asm/internal/flags/flags.go b/src/cmd/asm/internal/flags/flags.go
index 12bd585..0fa997f 100644
--- a/src/cmd/asm/internal/flags/flags.go
+++ b/src/cmd/asm/internal/flags/flags.go
@@ -18,6 +18,7 @@
 	OutputFile = flag.String("o", "", "output file; default foo.6 for /a/b/c/foo.s on amd64")
 	PrintOut   = flag.Bool("S", false, "print assembly and machine code")
 	TrimPath   = flag.String("trimpath", "", "remove prefix from recorded source file paths")
+	Shared     = flag.Bool("shared", false, "generate code that can be linked into a shared library")
 )
 
 var (
diff --git a/src/cmd/asm/main.go b/src/cmd/asm/main.go
index 9df486e..e8b10ce 100644
--- a/src/cmd/asm/main.go
+++ b/src/cmd/asm/main.go
@@ -41,6 +41,9 @@
 		ctxt.Debugasm = 1
 	}
 	ctxt.Trimpath = *flags.TrimPath
+	if *flags.Shared {
+		ctxt.Flag_shared = 1
+	}
 	ctxt.Bso = obj.Binitw(os.Stdout)
 	defer obj.Bflush(ctxt.Bso)
 	ctxt.Diag = log.Fatalf
diff --git a/src/cmd/cgo/gcc.go b/src/cmd/cgo/gcc.go
index 4bc4d79..3ec753f5 100644
--- a/src/cmd/cgo/gcc.go
+++ b/src/cmd/cgo/gcc.go
@@ -1042,7 +1042,7 @@
 	return fmt.Sprintf(tr.Repr, tr.FormatArgs...)
 }
 
-// Empty returns true if the result of String would be "".
+// Empty reports whether the result of String would be "".
 func (tr *TypeRepr) Empty() bool {
 	return len(tr.Repr) == 0
 }
diff --git a/src/cmd/cgo/main.go b/src/cmd/cgo/main.go
index 4dbcf62..41abb2c 100644
--- a/src/cmd/cgo/main.go
+++ b/src/cmd/cgo/main.go
@@ -87,7 +87,7 @@
 	Const    string // constant definition
 }
 
-// IsVar returns true if Kind is either "var" or "fpvar"
+// IsVar reports whether Kind is either "var" or "fpvar"
 func (n *Name) IsVar() bool {
 	return n.Kind == "var" || n.Kind == "fpvar"
 }
@@ -133,6 +133,7 @@
 	"386":     4,
 	"amd64":   8,
 	"arm":     4,
+	"arm64":   8,
 	"ppc64":   8,
 	"ppc64le": 8,
 	"s390":    4,
@@ -143,6 +144,7 @@
 	"386":     4,
 	"amd64":   8,
 	"arm":     4,
+	"arm64":   8,
 	"ppc64":   8,
 	"ppc64le": 8,
 	"s390":    4,
diff --git a/src/cmd/cgo/util.go b/src/cmd/cgo/util.go
index 4e7800d..3adb8e8 100644
--- a/src/cmd/cgo/util.go
+++ b/src/cmd/cgo/util.go
@@ -55,7 +55,7 @@
 	fmt.Fprintf(os.Stderr, "\n")
 }
 
-// isName returns true if s is a valid C identifier
+// isName reports whether s is a valid C identifier
 func isName(s string) bool {
 	for i, v := range s {
 		if v != '_' && (v < 'A' || v > 'Z') && (v < 'a' || v > 'z') && (v < '0' || v > '9') {
diff --git a/src/cmd/dist/build.go b/src/cmd/dist/build.go
index 0b55196..ba624aa 100644
--- a/src/cmd/dist/build.go
+++ b/src/cmd/dist/build.go
@@ -49,7 +49,7 @@
 )
 
 // The known architecture letters.
-var gochars = "566899"
+var gochars = "5667899"
 
 // The known architectures.
 var okgoarch = []string{
@@ -57,6 +57,7 @@
 	"arm",
 	"amd64",
 	"amd64p32",
+	"arm64",
 	"386",
 	"ppc64",
 	"ppc64le",
@@ -613,10 +614,11 @@
 
 	// For package runtime, copy some files into the work space.
 	if dir == "runtime" {
+		xmkdirall(pathf("%s/pkg/include", goroot))
 		// For use by assembly and C files.
-		copyfile(pathf("%s/pkg/%s_%s/textflag.h", goroot, goos, goarch),
+		copyfile(pathf("%s/pkg/include/textflag.h", goroot),
 			pathf("%s/src/runtime/textflag.h", goroot), 0)
-		copyfile(pathf("%s/pkg/%s_%s/funcdata.h", goroot, goos, goarch),
+		copyfile(pathf("%s/pkg/include/funcdata.h", goroot),
 			pathf("%s/src/runtime/funcdata.h", goroot), 0)
 	}
 
@@ -691,7 +693,7 @@
 		compile = []string{
 			pathf("%s/asm", tooldir),
 			"-I", workdir,
-			"-I", pathf("%s/pkg/%s_%s", goroot, goos, goarch),
+			"-I", pathf("%s/pkg/include", goroot),
 			"-D", "GOOS_" + goos,
 			"-D", "GOARCH_" + goarch,
 			"-D", "GOOS_GOARCH_" + goos + "_" + goarch,
@@ -908,6 +910,8 @@
 	"cmd/5l",
 	"cmd/6g",
 	"cmd/6l",
+	"cmd/7g",
+	"cmd/7l",
 	"cmd/8g",
 	"cmd/8l",
 	"cmd/9g",
@@ -1016,6 +1020,7 @@
 		"clean          deletes all built files\n" +
 		"env [-p]       print environment (-p: include $PATH)\n" +
 		"install [dir]  install individual directory\n" +
+		"test [-h]      run Go test(s)\n" +
 		"version        print Go version\n" +
 		"\n" +
 		"All commands take -v flags to emit extra information.\n",
diff --git a/src/cmd/dist/buildruntime.go b/src/cmd/dist/buildruntime.go
index 1123265..73f4d8e 100644
--- a/src/cmd/dist/buildruntime.go
+++ b/src/cmd/dist/buildruntime.go
@@ -40,27 +40,38 @@
 //	const defaultGOROOT = <goroot>
 //	const defaultGO386 = <go386>
 //	const defaultGOARM = <goarm>
-//	const defaultGOOS = <goos>
-//	const defaultGOARCH = <goarch>
+//	const defaultGOOS = runtime.GOOS
+//	const defaultGOARCH = runtime.GOARCH
 //	const defaultGO_EXTLINK_ENABLED = <goextlinkenabled>
 //	const version = <version>
 //	const goexperiment = <goexperiment>
 //
+// The use of runtime.GOOS and runtime.GOARCH makes sure that
+// a cross-compiled compiler expects to compile for its own target
+// system. That is, if on a Mac you do:
+//
+//	GOOS=linux GOARCH=ppc64 go build cmd/9g
+//
+// the resulting compiler will default to generating linux/ppc64 object files.
+// This is more useful than having it default to generating objects for the
+// original target (in this example, a Mac).
 func mkzbootstrap(file string) {
 	out := fmt.Sprintf(
 		"// auto generated by go tool dist\n"+
 			"\n"+
 			"package obj\n"+
 			"\n"+
+			"import \"runtime\"\n"+
+			"\n"+
 			"const defaultGOROOT = `%s`\n"+
 			"const defaultGO386 = `%s`\n"+
 			"const defaultGOARM = `%s`\n"+
-			"const defaultGOOS = `%s`\n"+
-			"const defaultGOARCH = `%s`\n"+
+			"const defaultGOOS = runtime.GOOS\n"+
+			"const defaultGOARCH = runtime.GOARCH\n"+
 			"const defaultGO_EXTLINK_ENABLED = `%s`\n"+
 			"const version = `%s`\n"+
 			"const goexperiment = `%s`\n",
-		goroot_final, go386, goarm, gohostos, gohostarch, goextlinkenabled, findgoversion(), os.Getenv("GOEXPERIMENT"))
+		goroot_final, go386, goarm, goextlinkenabled, findgoversion(), os.Getenv("GOEXPERIMENT"))
 
 	writefile(out, file, 0)
 }
diff --git a/src/cmd/dist/buildtool.go b/src/cmd/dist/buildtool.go
index b8e46df..69e077c 100644
--- a/src/cmd/dist/buildtool.go
+++ b/src/cmd/dist/buildtool.go
@@ -27,6 +27,8 @@
 	"5l",
 	"6g",
 	"6l",
+	"7g",
+	"7l",
 	"8g",
 	"8l",
 	"9g",
@@ -41,7 +43,7 @@
 	"internal/ld",
 	"internal/obj",
 	"internal/obj/arm",
-	"internal/obj/i386",
+	"internal/obj/arm64",
 	"internal/obj/ppc64",
 	"internal/obj/x86",
 	"old5a",
@@ -137,7 +139,7 @@
 		}
 	}
 
-	lines[0] = "// Do not edit. Bootstrap copy of " + srcFile + "\n\n" + lines[0]
+	lines[0] = "// Do not edit. Bootstrap copy of " + srcFile + "\n\n//line " + srcFile + ":1\n" + lines[0]
 
 	return strings.Join(lines, "")
 }
diff --git a/src/cmd/dist/main.go b/src/cmd/dist/main.go
index a2ac65e..1f19a7c 100644
--- a/src/cmd/dist/main.go
+++ b/src/cmd/dist/main.go
@@ -21,6 +21,7 @@
 	{"clean", cmdclean},
 	{"env", cmdenv},
 	{"install", cmdinstall},
+	{"test", cmdtest},
 	{"version", cmdversion},
 }
 
diff --git a/src/cmd/dist/test.go b/src/cmd/dist/test.go
new file mode 100644
index 0000000..b0ffdcf
--- /dev/null
+++ b/src/cmd/dist/test.go
@@ -0,0 +1,585 @@
+// Copyright 2015 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 (
+	"bytes"
+	"errors"
+	"flag"
+	"fmt"
+	"log"
+	"os"
+	"os/exec"
+	"path/filepath"
+	"regexp"
+	"strconv"
+	"strings"
+	"time"
+)
+
+func cmdtest() {
+	var t tester
+	flag.BoolVar(&t.listMode, "list", false, "list available tests")
+	flag.BoolVar(&t.noRebuild, "no-rebuild", false, "don't rebuild std and cmd packages")
+	flag.StringVar(&t.banner, "banner", "##### ", "banner prefix; blank means no section banners")
+	flag.StringVar(&t.runRxStr, "run", "", "run only those tests matching the regular expression; empty means to run all")
+	xflagparse(0)
+	t.run()
+}
+
+// tester executes cmdtest.
+type tester struct {
+	listMode  bool
+	noRebuild bool
+	runRxStr  string
+	runRx     *regexp.Regexp
+	banner    string // prefix, or "" for none
+
+	goroot     string
+	goarch     string
+	gohostarch string
+	goos       string
+	gohostos   string
+	cgoEnabled bool
+	partial    bool
+	haveTime   bool // the 'time' binary is available
+
+	tests        []distTest
+	timeoutScale int
+}
+
+// A distTest is a test run by dist test.
+// Each test has a unique name and belongs to a group (heading)
+type distTest struct {
+	name    string // unique test name; may be filtered with -run flag
+	heading string // group section; this header is printed before the test is run.
+	fn      func() error
+}
+
+func mustEnv(k string) string {
+	v := os.Getenv(k)
+	if v == "" {
+		log.Fatalf("Unset environment variable %v", k)
+	}
+	return v
+}
+
+func (t *tester) run() {
+	t.goroot = mustEnv("GOROOT")
+	t.goos = mustEnv("GOOS")
+	t.gohostos = mustEnv("GOHOSTOS")
+	t.goarch = mustEnv("GOARCH")
+	t.gohostarch = mustEnv("GOHOSTARCH")
+	slurp, err := exec.Command("go", "env", "CGO_ENABLED").Output()
+	if err != nil {
+		log.Fatalf("Error running go env CGO_ENABLED: %v", err)
+	}
+	t.cgoEnabled, _ = strconv.ParseBool(strings.TrimSpace(string(slurp)))
+
+	if t.hasBash() {
+		if _, err := exec.LookPath("time"); err == nil {
+			t.haveTime = true
+		}
+	}
+
+	if !t.noRebuild {
+		t.out("Building packages and commands.")
+		cmd := exec.Command("go", "install", "-a", "-v", "std", "cmd")
+		cmd.Stdout = os.Stdout
+		cmd.Stderr = os.Stderr
+		if err := cmd.Run(); err != nil {
+			log.Fatalf("building packages and commands: %v", err)
+		}
+	}
+
+	t.timeoutScale = 1
+	if t.goarch == "arm" || t.goos == "windows" {
+		t.timeoutScale = 2
+	}
+
+	if t.runRxStr != "" {
+		t.runRx = regexp.MustCompile(t.runRxStr)
+	}
+
+	t.registerTests()
+	if t.listMode {
+		for _, tt := range t.tests {
+			fmt.Println(tt.name)
+		}
+		return
+	}
+
+	// we must unset GOROOT_FINAL before tests, because runtime/debug requires
+	// correct access to source code, so if we have GOROOT_FINAL in effect,
+	// at least runtime/debug test will fail.
+	os.Unsetenv("GOROOT_FINAL")
+
+	var lastHeading string
+	for _, dt := range t.tests {
+		if t.runRx != nil && !t.runRx.MatchString(dt.name) {
+			t.partial = true
+			continue
+		}
+		if dt.heading != "" && lastHeading != dt.heading {
+			lastHeading = dt.heading
+			t.out(dt.heading)
+		}
+		if vflag > 0 {
+			fmt.Printf("# go tool dist test -run=^%s$\n", dt.name)
+		}
+		if err := dt.fn(); err != nil {
+			log.Fatalf("Failed: %v", err)
+		}
+	}
+	if t.partial {
+		fmt.Println("\nALL TESTS PASSED (some were excluded)")
+	} else {
+		fmt.Println("\nALL TESTS PASSED")
+	}
+}
+
+func (t *tester) timeout(sec int) string {
+	return "-timeout=" + fmt.Sprint(time.Duration(sec)*time.Second*time.Duration(t.timeoutScale))
+}
+
+func (t *tester) registerTests() {
+	// Register a separate logical test for each package in the standard library
+	// but actually group them together at execution time to share the cost of
+	// building packages shared between them.
+	all, err := exec.Command("go", "list", "std", "cmd").Output()
+	if err != nil {
+		log.Fatalf("Error running go list std cmd: %v", err)
+	}
+	// ranGoTest and stdMatches are state closed over by the
+	// stdlib testing func below. The tests are run sequentially,
+	// so there'no need for locks.
+	var (
+		ranGoTest  bool
+		stdMatches []string
+	)
+	for _, pkg := range strings.Fields(string(all)) {
+		testName := "go_test:" + pkg
+		if t.runRx == nil || t.runRx.MatchString(testName) {
+			stdMatches = append(stdMatches, pkg)
+		}
+		t.tests = append(t.tests, distTest{
+			name:    testName,
+			heading: "Testing packages.",
+			fn: func() error {
+				if ranGoTest {
+					return nil
+				}
+				ranGoTest = true
+				cmd := exec.Command("go", append([]string{
+					"test",
+					"-short",
+					t.timeout(120),
+					"-gcflags=" + os.Getenv("GO_GCFLAGS"),
+				}, stdMatches...)...)
+				cmd.Stdout = os.Stdout
+				cmd.Stderr = os.Stderr
+				return cmd.Run()
+			},
+		})
+	}
+
+	// Old hack for when Plan 9 on GCE was too slow.
+	// We're keeping this until test sharding (Issue 10029) is finished, though.
+	if os.Getenv("GOTESTONLY") == "std" {
+		t.partial = true
+		return
+	}
+
+	// Runtime CPU tests.
+	for _, cpu := range []string{"1", "2", "4"} {
+		cpu := cpu
+		testName := "runtime:cpu" + cpu
+		t.tests = append(t.tests, distTest{
+			name:    testName,
+			heading: "GOMAXPROCS=2 runtime -cpu=1,2,4",
+			fn: func() error {
+				cmd := t.dirCmd(".", "go", "test", "-short", t.timeout(300), "runtime", "-cpu="+cpu)
+				// We set GOMAXPROCS=2 in addition to -cpu=1,2,4 in order to test runtime bootstrap code,
+				// creation of first goroutines and first garbage collections in the parallel setting.
+				cmd.Env = mergeEnvLists([]string{"GOMAXPROCS=2"}, os.Environ())
+				return cmd.Run()
+			},
+		})
+	}
+
+	// sync tests
+	t.tests = append(t.tests, distTest{
+		name:    "sync_cpu",
+		heading: "sync -cpu=10",
+		fn: func() error {
+			return t.dirCmd(".", "go", "test", "sync", "-short", t.timeout(120), "-cpu=10").Run()
+		},
+	})
+
+	iOS := t.goos == "darwin" && (t.goarch == "arm" || t.goarch == "arm64")
+
+	if t.cgoEnabled && t.goos != "android" && !iOS {
+		// Disabled on android and iOS. golang.org/issue/8345
+		t.tests = append(t.tests, distTest{
+			name:    "cgo_stdio",
+			heading: "../misc/cgo/stdio",
+			fn: func() error {
+				return t.dirCmd("misc/cgo/stdio",
+					"go", "run", filepath.Join(os.Getenv("GOROOT"), "test/run.go"), "-", ".").Run()
+			},
+		})
+		t.tests = append(t.tests, distTest{
+			name:    "cgo_life",
+			heading: "../misc/cgo/life",
+			fn: func() error {
+				return t.dirCmd("misc/cgo/life",
+					"go", "run", filepath.Join(os.Getenv("GOROOT"), "test/run.go"), "-", ".").Run()
+			},
+		})
+	}
+	if t.cgoEnabled && t.goos != "android" && !iOS {
+		// TODO(crawshaw): reenable on android and iOS
+		// golang.org/issue/8345
+		//
+		// These tests are not designed to run off the host.
+		t.tests = append(t.tests, distTest{
+			name:    "cgo_test",
+			heading: "../misc/cgo/test",
+			fn:      t.cgoTest,
+		})
+	}
+
+	if t.raceDetectorSupported() {
+		t.tests = append(t.tests, distTest{
+			name:    "race",
+			heading: "Testing race detector",
+			fn:      t.raceTest,
+		})
+	}
+
+	if t.hasBash() && t.cgoEnabled && t.goos != "android" && t.goos != "darwin" {
+		t.registerTest("testgodefs", "../misc/cgo/testgodefs", "./test.bash")
+	}
+	if t.cgoEnabled {
+		if t.gohostos == "windows" {
+			t.tests = append(t.tests, distTest{
+				name:    "testso",
+				heading: "../misc/cgo/testso",
+				fn:      t.cgoTestSOWindows,
+			})
+		} else if t.hasBash() && t.goos != "android" && !iOS {
+			t.registerTest("testso", "../misc/cgo/testso", "./test.bash")
+		}
+		if t.gohostos == "linux" && t.goarch == "amd64" {
+			t.registerTest("testasan", "../misc/cgo/testasan", "go", "run", "main.go")
+		}
+		if t.hasBash() && t.goos != "android" && !iOS && t.gohostos != "windows" {
+			t.registerTest("cgo_errors", "../misc/cgo/errors", "./test.bash")
+		}
+	}
+	if t.hasBash() && t.goos != "nacl" && t.goos != "android" && !iOS {
+		t.registerTest("doc_progs", "../doc/progs", "time", "./run")
+		t.registerTest("wiki", "../doc/articles/wiki", "./test.bash")
+		t.registerTest("codewalk", "../doc/codewalk", "time", "./run")
+		t.registerTest("shootout", "../test/bench/shootout", "time", "./timing.sh", "-test")
+	}
+	if t.goos != "android" && !iOS {
+		t.registerTest("bench_go1", "../test/bench/go1", "go", "test")
+	}
+	if t.goos != "android" && !iOS {
+		// TODO(bradfitz): shard down into these tests, as
+		// this is one of the slowest (and most shardable)
+		// tests.
+		t.tests = append(t.tests, distTest{
+			name:    "test",
+			heading: "../test",
+			fn:      t.testDirTest,
+		})
+	}
+	if t.goos != "nacl" && t.goos != "android" && !iOS {
+		t.tests = append(t.tests, distTest{
+			name:    "api",
+			heading: "API check",
+			fn: func() error {
+				return t.dirCmd(".", "go", "run", filepath.Join(t.goroot, "src/cmd/api/run.go")).Run()
+			},
+		})
+	}
+
+}
+
+func (t *tester) registerTest(name, dirBanner, bin string, args ...string) {
+	if bin == "time" && !t.haveTime {
+		bin, args = args[0], args[1:]
+	}
+	t.tests = append(t.tests, distTest{
+		name:    name,
+		heading: dirBanner,
+		fn: func() error {
+			return t.dirCmd(filepath.Join(t.goroot, "src", dirBanner), bin, args...).Run()
+		},
+	})
+}
+
+func (t *tester) dirCmd(dir string, bin string, args ...string) *exec.Cmd {
+	cmd := exec.Command(bin, args...)
+	if filepath.IsAbs(dir) {
+		cmd.Dir = dir
+	} else {
+		cmd.Dir = filepath.Join(t.goroot, dir)
+	}
+	cmd.Stdout = os.Stdout
+	cmd.Stderr = os.Stderr
+	return cmd
+}
+
+func (t *tester) out(v string) {
+	if t.banner == "" {
+		return
+	}
+	fmt.Println("\n" + t.banner + v)
+}
+
+func (t *tester) extLink() bool {
+	pair := t.gohostos + "-" + t.goarch
+	switch pair {
+	case "android-arm",
+		"dragonfly-386", "dragonfly-amd64",
+		"freebsd-386", "freebsd-amd64", "freebsd-arm",
+		"linux-386", "linux-amd64", "linux-arm",
+		"netbsd-386", "netbsd-amd64",
+		"openbsd-386", "openbsd-amd64",
+		"windows-386", "windows-amd64":
+		return true
+	case "darwin-386", "darwin-amd64":
+		// linkmode=external fails on OS X 10.6 and earlier == Darwin
+		// 10.8 and earlier.
+		unameR, err := exec.Command("uname", "-r").Output()
+		if err != nil {
+			log.Fatalf("uname -r: %v", err)
+		}
+		major, _ := strconv.Atoi(string(unameR[:bytes.IndexByte(unameR, '.')]))
+		return major > 10
+	}
+	return false
+}
+
+func (t *tester) cgoTest() error {
+	env := mergeEnvLists([]string{"GOTRACEBACK=2"}, os.Environ())
+
+	iOS := t.goos == "darwin" && (t.goarch == "arm" || t.goarch == "arm64")
+	if t.goos == "android" || iOS {
+		cmd := t.dirCmd("misc/cgo/test", "go", "test")
+		cmd.Env = env
+		return cmd.Run()
+	}
+
+	if t.gohostos != "dragonfly" {
+		// linkmode=internal fails on dragonfly since errno is a TLS relocation.
+		cmd := t.dirCmd("misc/cgo/test", "go", "test", "-ldflags", "-linkmode=internal")
+		cmd.Env = env
+		if err := cmd.Run(); err != nil {
+			return err
+		}
+	}
+
+	pair := t.gohostos + "-" + t.goarch
+	switch pair {
+	case "openbsd-386", "openbsd-amd64":
+		// test linkmode=external, but __thread not supported, so skip testtls.
+		cmd := t.dirCmd("misc/cgo/test", "go", "test", "-ldflags", "-linkmode=external")
+		cmd.Env = env
+		if err := cmd.Run(); err != nil {
+			return err
+		}
+	case "darwin-386", "darwin-amd64",
+		"windows-386", "windows-amd64":
+		if t.extLink() {
+			cmd := t.dirCmd("misc/cgo/test", "go", "test", "-ldflags", "-linkmode=external")
+			cmd.Env = env
+			if err := cmd.Run(); err != nil {
+				return err
+			}
+		}
+	case "android-arm",
+		"dragonfly-386", "dragonfly-amd64",
+		"freebsd-386", "freebsd-amd64", "freebsd-arm",
+		"linux-386", "linux-amd64", "linux-arm",
+		"netbsd-386", "netbsd-amd64":
+
+		cmd := t.dirCmd("misc/cgo/test", "go", "test", "-ldflags", "-linkmode=external")
+		cmd.Env = env
+		if err := cmd.Run(); err != nil {
+			return err
+		}
+		cmd = t.dirCmd("misc/cgo/testtls", "go", "test", "-ldflags", "-linkmode=auto")
+		cmd.Env = env
+		if err := cmd.Run(); err != nil {
+			return err
+		}
+		cmd = t.dirCmd("misc/cgo/testtls", "go", "test", "-ldflags", "-linkmode=external")
+		cmd.Env = env
+		if err := cmd.Run(); err != nil {
+			return err
+		}
+
+		switch pair {
+		case "netbsd-386", "netbsd-amd64":
+			// no static linking
+		case "freebsd-arm":
+			// -fPIC compiled tls code will use __tls_get_addr instead
+			// of __aeabi_read_tp, however, on FreeBSD/ARM, __tls_get_addr
+			// is implemented in rtld-elf, so -fPIC isn't compatible with
+			// static linking on FreeBSD/ARM with clang. (cgo depends on
+			// -fPIC fundamentally.)
+		default:
+			cc := mustEnv("CC")
+			cmd := t.dirCmd("misc/cgo/test",
+				cc, "-xc", "-o", "/dev/null", "-static", "-")
+			cmd.Env = env
+			cmd.Stdin = strings.NewReader("int main() {}")
+			if err := cmd.Run(); err != nil {
+				fmt.Println("No support for static linking found (lacks libc.a?), skip cgo static linking test.")
+			} else {
+				cmd = t.dirCmd("misc/cgo/testtls", "go", "test", "-ldflags", `-linkmode=external -extldflags "-static -pthread"`)
+				cmd.Env = env
+				if err := cmd.Run(); err != nil {
+					return err
+				}
+
+				cmd = t.dirCmd("misc/cgo/nocgo", "go", "test")
+				cmd.Env = env
+				if err := cmd.Run(); err != nil {
+					return err
+				}
+
+				cmd = t.dirCmd("misc/cgo/nocgo", "go", "test", "-ldflags", `-linkmode=external`)
+				cmd.Env = env
+				if err := cmd.Run(); err != nil {
+					return err
+				}
+
+				cmd = t.dirCmd("misc/cgo/nocgo", "go", "test", "-ldflags", `-linkmode=external -extldflags "-static -pthread"`)
+				cmd.Env = env
+				if err := cmd.Run(); err != nil {
+					return err
+				}
+			}
+
+			if pair != "freebsd-amd64" { // clang -pie fails to link misc/cgo/test
+				cmd := t.dirCmd("misc/cgo/test",
+					cc, "-xc", "-o", "/dev/null", "-pie", "-")
+				cmd.Env = env
+				cmd.Stdin = strings.NewReader("int main() {}")
+				if err := cmd.Run(); err != nil {
+					fmt.Println("No support for -pie found, skip cgo PIE test.")
+				} else {
+					cmd = t.dirCmd("misc/cgo/test", "go", "test", "-ldflags", `-linkmode=external -extldflags "-pie"`)
+					cmd.Env = env
+					if err := cmd.Run(); err != nil {
+						return fmt.Errorf("pie cgo/test: %v", err)
+					}
+					cmd = t.dirCmd("misc/cgo/testtls", "go", "test", "-ldflags", `-linkmode=external -extldflags "-pie"`)
+					cmd.Env = env
+					if err := cmd.Run(); err != nil {
+						return fmt.Errorf("pie cgo/testtls: %v", err)
+					}
+					cmd = t.dirCmd("misc/cgo/nocgo", "go", "test", "-ldflags", `-linkmode=external -extldflags "-pie"`)
+					cmd.Env = env
+					if err := cmd.Run(); err != nil {
+						return fmt.Errorf("pie cgo/nocgo: %v", err)
+					}
+				}
+			}
+		}
+	}
+
+	return nil
+}
+
+func (t *tester) cgoTestSOWindows() error {
+	cmd := t.dirCmd("misc/cgo/testso", `.\test`)
+	var buf bytes.Buffer
+	cmd.Stdout = &buf
+	cmd.Stderr = &buf
+	err := cmd.Run()
+	s := buf.String()
+	fmt.Println(s)
+	if err != nil {
+		return err
+	}
+	if strings.Contains(s, "FAIL") {
+		return errors.New("test failed")
+	}
+	return nil
+}
+
+func (t *tester) hasBash() bool {
+	switch t.gohostos {
+	case "windows", "plan9":
+		return false
+	}
+	return true
+}
+
+func (t *tester) raceDetectorSupported() bool {
+	switch t.gohostos {
+	case "linux", "darwin", "freebsd", "windows":
+		return t.cgoEnabled && t.goarch == "amd64" && t.gohostos == t.goos
+	}
+	return false
+}
+
+func (t *tester) raceTest() error {
+	if err := t.dirCmd(".", "go", "test", "-race", "-i", "runtime/race", "flag", "os/exec").Run(); err != nil {
+		return err
+	}
+	if err := t.dirCmd(".", "go", "test", "-race", "-run=Output", "runtime/race").Run(); err != nil {
+		return err
+	}
+	if err := t.dirCmd(".", "go", "test", "-race", "-short", "flag", "os/exec").Run(); err != nil {
+		return err
+	}
+	if t.extLink() {
+		// Test with external linking; see issue 9133.
+		if err := t.dirCmd(".", "go", "test", "-race", "-short", "-ldflags=-linkmode=external", "flag", "os/exec").Run(); err != nil {
+			return err
+		}
+	}
+	return nil
+}
+
+func (t *tester) testDirTest() error {
+	const runExe = "runtest.exe" // named exe for Windows, but harmless elsewhere
+	cmd := t.dirCmd("test", "go", "build", "-o", runExe, "run.go")
+	cmd.Env = mergeEnvLists([]string{"GOOS=" + t.gohostos, "GOARCH=" + t.gohostarch, "GOMAXPROCS="}, os.Environ())
+	if err := cmd.Run(); err != nil {
+		return err
+	}
+	absExe := filepath.Join(cmd.Dir, runExe)
+	defer os.Remove(absExe)
+	if t.haveTime {
+		return t.dirCmd("test", "time", absExe).Run()
+	}
+	return t.dirCmd("test", absExe).Run()
+}
+
+// mergeEnvLists merges the two environment lists such that
+// variables with the same name in "in" replace those in "out".
+// out may be mutated.
+func mergeEnvLists(in, out []string) []string {
+NextVar:
+	for _, inkv := range in {
+		k := strings.SplitAfterN(inkv, "=", 2)[0]
+		for i, outkv := range out {
+			if strings.HasPrefix(outkv, k) {
+				out[i] = inkv
+				continue NextVar
+			}
+		}
+		out = append(out, inkv)
+	}
+	return out
+}
diff --git a/src/cmd/dist/util.go b/src/cmd/dist/util.go
index d7e0078..0bbdbad 100644
--- a/src/cmd/dist/util.go
+++ b/src/cmd/dist/util.go
@@ -110,7 +110,7 @@
 		if mode&Background != 0 {
 			bgdied.Done()
 		}
-		fatal("FAILED: %v", strings.Join(cmd, " "))
+		fatal("FAILED: %v: %v", strings.Join(cmd, " "), err)
 	}
 	if mode&ShowOutput != 0 {
 		outputLock.Lock()
@@ -422,6 +422,8 @@
 			gohostarch = "386"
 		case strings.Contains(out, "arm"):
 			gohostarch = "arm"
+		case strings.Contains(out, "aarch64"):
+			gohostarch = "arm64"
 		case strings.Contains(out, "ppc64le"):
 			gohostarch = "ppc64le"
 		case strings.Contains(out, "ppc64"):
@@ -505,8 +507,9 @@
 		// Conservative default for cross-compilation.
 		return "5"
 	}
-	if goos == "freebsd" {
+	if goos == "freebsd" || goos == "openbsd" {
 		// FreeBSD has broken VFP support.
+		// OpenBSD currently only supports softfloat.
 		return "5"
 	}
 	if goos != "linux" {
diff --git a/src/cmd/fix/fix.go b/src/cmd/fix/fix.go
index a07bbac..160336c 100644
--- a/src/cmd/fix/fix.go
+++ b/src/cmd/fix/fix.go
@@ -282,7 +282,7 @@
 	after(x)
 }
 
-// imports returns true if f imports path.
+// imports reports whether f imports path.
 func imports(f *ast.File, path string) bool {
 	return importSpec(f, path) != nil
 }
@@ -322,33 +322,33 @@
 	return false
 }
 
-// isPkgDot returns true if t is the expression "pkg.name"
+// isPkgDot reports whether t is the expression "pkg.name"
 // where pkg is an imported identifier.
 func isPkgDot(t ast.Expr, pkg, name string) bool {
 	sel, ok := t.(*ast.SelectorExpr)
 	return ok && isTopName(sel.X, pkg) && sel.Sel.String() == name
 }
 
-// isPtrPkgDot returns true if f is the expression "*pkg.name"
+// isPtrPkgDot reports whether f is the expression "*pkg.name"
 // where pkg is an imported identifier.
 func isPtrPkgDot(t ast.Expr, pkg, name string) bool {
 	ptr, ok := t.(*ast.StarExpr)
 	return ok && isPkgDot(ptr.X, pkg, name)
 }
 
-// isTopName returns true if n is a top-level unresolved identifier with the given name.
+// isTopName reports whether n is a top-level unresolved identifier with the given name.
 func isTopName(n ast.Expr, name string) bool {
 	id, ok := n.(*ast.Ident)
 	return ok && id.Name == name && id.Obj == nil
 }
 
-// isName returns true if n is an identifier with the given name.
+// isName reports whether n is an identifier with the given name.
 func isName(n ast.Expr, name string) bool {
 	id, ok := n.(*ast.Ident)
 	return ok && id.String() == name
 }
 
-// isCall returns true if t is a call to pkg.name.
+// isCall reports whether t is a call to pkg.name.
 func isCall(t ast.Expr, pkg, name string) bool {
 	call, ok := t.(*ast.CallExpr)
 	return ok && isPkgDot(call.Fun, pkg, name)
@@ -360,7 +360,7 @@
 	return id
 }
 
-// refersTo returns true if n is a reference to the same object as x.
+// refersTo reports whether n is a reference to the same object as x.
 func refersTo(n ast.Node, x *ast.Ident) bool {
 	id, ok := n.(*ast.Ident)
 	// The test of id.Name == x.Name handles top-level unresolved
@@ -368,12 +368,12 @@
 	return ok && id.Obj == x.Obj && id.Name == x.Name
 }
 
-// isBlank returns true if n is the blank identifier.
+// isBlank reports whether n is the blank identifier.
 func isBlank(n ast.Expr) bool {
 	return isName(n, "_")
 }
 
-// isEmptyString returns true if n is an empty string literal.
+// isEmptyString reports whether n is an empty string literal.
 func isEmptyString(n ast.Expr) bool {
 	lit, ok := n.(*ast.BasicLit)
 	return ok && lit.Kind == token.STRING && len(lit.Value) == 2
@@ -430,7 +430,7 @@
 	}
 }
 
-// assignsTo returns true if any of the code in scope assigns to or takes the address of x.
+// assignsTo reports whether any of the code in scope assigns to or takes the address of x.
 func assignsTo(x *ast.Ident, scope []ast.Stmt) bool {
 	assigned := false
 	ff := func(n interface{}) {
diff --git a/src/cmd/go/build.go b/src/cmd/go/build.go
index 5e4d488..61453c7 100644
--- a/src/cmd/go/build.go
+++ b/src/cmd/go/build.go
@@ -88,6 +88,8 @@
 		or, if set explicitly, has _race appended to it.
 	-ldflags 'flag list'
 		arguments to pass on each 5l, 6l, 8l, or 9l linker invocation.
+	-asmflags 'flag list'
+		arguments to pass on each asm assembler invocation.
 	-tags 'tag list'
 		a list of build tags to consider satisfied during the build.
 		For more information about build tags, see the description of
@@ -137,6 +139,7 @@
 var buildI bool               // -i flag
 var buildO = cmdBuild.Flag.String("o", "", "output file")
 var buildWork bool           // -work flag
+var buildAsmflags []string   // -asmflags flag
 var buildGcflags []string    // -gcflags flag
 var buildLdflags []string    // -ldflags flag
 var buildGccgoflags []string // -gccgoflags flag
@@ -188,6 +191,7 @@
 	cmd.Flag.BoolVar(&buildV, "v", false, "")
 	cmd.Flag.BoolVar(&buildX, "x", false, "")
 	cmd.Flag.BoolVar(&buildWork, "work", false, "")
+	cmd.Flag.Var((*stringsFlag)(&buildAsmflags), "asmflags", "")
 	cmd.Flag.Var((*stringsFlag)(&buildGcflags), "gcflags", "")
 	cmd.Flag.Var((*stringsFlag)(&buildLdflags), "ldflags", "")
 	cmd.Flag.Var((*stringsFlag)(&buildGccgoflags), "gccgoflags", "")
@@ -384,8 +388,10 @@
 var (
 	goarch    string
 	goos      string
-	archChar  string
 	exeSuffix string
+
+	archCharVal string
+	archCharErr error
 )
 
 func init() {
@@ -394,16 +400,16 @@
 	if goos == "windows" {
 		exeSuffix = ".exe"
 	}
-	var err error
-	archChar, err = build.ArchChar(goarch)
-	if err != nil {
-		if _, isgc := buildToolchain.(gcToolchain); isgc {
-			fatalf("%s", err)
-		}
-		// archChar is only required for gcToolchain, if we're using
-		// another toolchain leave it blank.
-		archChar = ""
+	archCharVal, archCharErr = build.ArchChar(goarch)
+}
+
+// archChar returns the architecture character.  This is only needed
+// for the gc toolchain, so only fail if we actually need it.
+func archChar() string {
+	if archCharErr != nil {
+		fatalf("%s", archCharErr)
 	}
+	return archCharVal
 }
 
 // A builder holds global state about a build.
@@ -811,9 +817,7 @@
 func (b *builder) build(a *action) (err error) {
 	// Return an error if the package has CXX files but it's not using
 	// cgo nor SWIG, since the CXX files can only be processed by cgo
-	// and SWIG (it's possible to have packages with C files without
-	// using cgo, they will get compiled with the plan9 C compiler and
-	// linked with the rest of the package).
+	// and SWIG.
 	if len(a.p.CXXFiles) > 0 && !a.p.usesCgo() && !a.p.usesSwig() {
 		return fmt.Errorf("can't build package %s because it contains C++ files (%s) but it's not using cgo nor SWIG",
 			a.p.ImportPath, strings.Join(a.p.CXXFiles, ","))
@@ -841,7 +845,7 @@
 		fmt.Fprintf(os.Stderr, "%s\n", a.p.ImportPath)
 	}
 
-	if a.p.Standard && a.p.ImportPath == "runtime" && buildContext.Compiler == "gc" &&
+	if a.p.Standard && a.p.ImportPath == "runtime" && buildContext.Compiler == "gc" && archChar() != "" &&
 		(!hasString(a.p.GoFiles, "zgoos_"+buildContext.GOOS+".go") ||
 			!hasString(a.p.GoFiles, "zgoarch_"+buildContext.GOARCH+".go")) {
 		return fmt.Errorf("%s/%s must be bootstrapped using make%v", buildContext.GOOS, buildContext.GOARCH, defaultSuffix())
@@ -861,19 +865,35 @@
 		}
 	}
 
-	var gofiles, cfiles, sfiles, objects, cgoObjects, pcCFLAGS, pcLDFLAGS []string
+	var gofiles, cgofiles, cfiles, sfiles, cxxfiles, objects, cgoObjects, pcCFLAGS, pcLDFLAGS []string
 
 	gofiles = append(gofiles, a.p.GoFiles...)
+	cgofiles = append(cgofiles, a.p.CgoFiles...)
 	cfiles = append(cfiles, a.p.CFiles...)
 	sfiles = append(sfiles, a.p.SFiles...)
+	cxxfiles = append(cxxfiles, a.p.CXXFiles...)
 
 	if a.p.usesCgo() || a.p.usesSwig() {
 		if pcCFLAGS, pcLDFLAGS, err = b.getPkgConfigFlags(a.p); err != nil {
 			return
 		}
 	}
+
+	// Run SWIG on each .swig and .swigcxx file.
+	// Each run will generate two files, a .go file and a .c or .cxx file.
+	// The .go file will use import "C" and is to be processed by cgo.
+	if a.p.usesSwig() {
+		outGo, outC, outCXX, err := b.swig(a.p, obj, pcCFLAGS)
+		if err != nil {
+			return err
+		}
+		cgofiles = append(cgofiles, outGo...)
+		cfiles = append(cfiles, outC...)
+		cxxfiles = append(cxxfiles, outCXX...)
+	}
+
 	// Run cgo.
-	if a.p.usesCgo() {
+	if a.p.usesCgo() || a.p.usesSwig() {
 		// In a package using cgo, cgo compiles the C, C++ and assembly files with gcc.
 		// There is one exception: runtime/cgo's job is to bridge the
 		// cgo and non-cgo worlds, so it necessarily has files in both.
@@ -902,31 +922,7 @@
 		if a.cgo != nil && a.cgo.target != "" {
 			cgoExe = a.cgo.target
 		}
-		outGo, outObj, err := b.cgo(a.p, cgoExe, obj, pcCFLAGS, pcLDFLAGS, gccfiles, a.p.CXXFiles, a.p.MFiles)
-		if err != nil {
-			return err
-		}
-		cgoObjects = append(cgoObjects, outObj...)
-		gofiles = append(gofiles, outGo...)
-	}
-
-	// Run SWIG.
-	if a.p.usesSwig() {
-		// In a package using SWIG, any .c or .s files are
-		// compiled with gcc.
-		gccfiles := append(cfiles, sfiles...)
-		cxxfiles, mfiles := a.p.CXXFiles, a.p.MFiles
-		cfiles = nil
-		sfiles = nil
-
-		// Don't build c/c++ files twice if cgo is enabled (mainly for pkg-config).
-		if a.p.usesCgo() {
-			cxxfiles = nil
-			gccfiles = nil
-			mfiles = nil
-		}
-
-		outGo, outObj, err := b.swig(a.p, obj, pcCFLAGS, gccfiles, cxxfiles, mfiles)
+		outGo, outObj, err := b.cgo(a.p, cgoExe, obj, pcCFLAGS, pcLDFLAGS, cgofiles, gccfiles, cxxfiles, a.p.MFiles)
 		if err != nil {
 			return err
 		}
@@ -1012,9 +1008,11 @@
 		}
 	}
 
-	objExt := archChar
+	var objExt string
 	if _, ok := buildToolchain.(gccgoToolchain); ok {
 		objExt = "o"
+	} else {
+		objExt = archChar()
 	}
 
 	for _, file := range cfiles {
@@ -1267,15 +1265,15 @@
 }
 
 var objectMagic = [][]byte{
-	{'!', '<', 'a', 'r', 'c', 'h', '>', '\n'},        // Package archive
-	{'\x7F', 'E', 'L', 'F'},                          // ELF
-	{0xFE, 0xED, 0xFA, 0xCE},                         // Mach-O big-endian 32-bit
-	{0xFE, 0xED, 0xFA, 0xCF},                         // Mach-O big-endian 64-bit
-	{0xCE, 0xFA, 0xED, 0xFE},                         // Mach-O little-endian 32-bit
-	{0xCF, 0xFA, 0xED, 0xFE},                         // Mach-O little-endian 64-bit
-	{0x4d, 0x5a, 0x90, 0x00, 0x03, 0x00, 0x04, 0x00}, // PE (Windows) as generated by 6l/8l
-	{0x00, 0x00, 0x01, 0xEB},                         // Plan 9 i386
-	{0x00, 0x00, 0x8a, 0x97},                         // Plan 9 amd64
+	{'!', '<', 'a', 'r', 'c', 'h', '>', '\n'}, // Package archive
+	{'\x7F', 'E', 'L', 'F'},                   // ELF
+	{0xFE, 0xED, 0xFA, 0xCE},                  // Mach-O big-endian 32-bit
+	{0xFE, 0xED, 0xFA, 0xCF},                  // Mach-O big-endian 64-bit
+	{0xCE, 0xFA, 0xED, 0xFE},                  // Mach-O little-endian 32-bit
+	{0xCF, 0xFA, 0xED, 0xFE},                  // Mach-O little-endian 64-bit
+	{0x4d, 0x5a, 0x90, 0x00, 0x03, 0x00},      // PE (Windows) as generated by 6l/8l and gcc
+	{0x00, 0x00, 0x01, 0xEB},                  // Plan 9 i386
+	{0x00, 0x00, 0x8a, 0x97},                  // Plan 9 amd64
 }
 
 func isObject(s string) bool {
@@ -1647,18 +1645,18 @@
 type gcToolchain struct{}
 
 func (gcToolchain) compiler() string {
-	return tool(archChar + "g")
+	return tool(archChar() + "g")
 }
 
 func (gcToolchain) linker() string {
-	return tool(archChar + "l")
+	return tool(archChar() + "l")
 }
 
 func (gcToolchain) gc(b *builder, p *Package, archive, obj string, asmhdr bool, importArgs []string, gofiles []string) (ofile string, output []byte, err error) {
 	if archive != "" {
 		ofile = archive
 	} else {
-		out := "_go_." + archChar
+		out := "_go_." + archChar()
 		ofile = obj + out
 	}
 
@@ -1687,7 +1685,7 @@
 		gcargs = append(gcargs, "-installsuffix", buildContext.InstallSuffix)
 	}
 
-	args := []interface{}{buildToolExec, tool(archChar + "g"), "-o", ofile, "-trimpath", b.work, buildGcflags, gcargs, "-D", p.localPrefix, importArgs}
+	args := []interface{}{buildToolExec, tool(archChar() + "g"), "-o", ofile, "-trimpath", b.work, buildGcflags, gcargs, "-D", p.localPrefix, importArgs}
 	if ofile == archive {
 		args = append(args, "-pack")
 	}
@@ -1709,14 +1707,16 @@
 
 func (gcToolchain) asm(b *builder, p *Package, obj, ofile, sfile string) error {
 	// Add -I pkg/GOOS_GOARCH so #include "textflag.h" works in .s files.
-	inc := filepath.Join(goroot, "pkg", fmt.Sprintf("%s_%s", goos, goarch))
+	inc := filepath.Join(goroot, "pkg", "include")
 	sfile = mkAbs(p.Dir, sfile)
-	args := []interface{}{buildToolExec, tool("asm"), "-o", ofile, "-trimpath", b.work, "-I", obj, "-I", inc, "-D", "GOOS_" + goos, "-D", "GOARCH_" + goarch, sfile}
+	args := []interface{}{buildToolExec, tool("asm"), "-o", ofile, "-trimpath", b.work, "-I", obj, "-I", inc, "-D", "GOOS_" + goos, "-D", "GOARCH_" + goarch, buildAsmflags, sfile}
 	if err := b.run(p.Dir, p.ImportPath, nil, args...); err != nil {
 		return err
 	}
-	if verifyAsm {
-		if err := toolVerify(b, p, "old"+archChar+"a", ofile, args); err != nil {
+	// Disable checks when additional flags are passed, as the old assemblers
+	// don't implement some of them (e.g., -shared).
+	if verifyAsm && goarch != "arm64" && len(buildAsmflags) == 0 {
+		if err := toolVerify(b, p, "old"+archChar()+"a", ofile, args); err != nil {
 			return err
 		}
 	}
@@ -1839,9 +1839,9 @@
 
 func (gcToolchain) ld(b *builder, p *Package, out string, allactions []*action, mainpkg string, ofiles []string) error {
 	importArgs := b.includeArgs("-L", allactions)
-	cxx := len(p.CXXFiles) > 0
+	cxx := len(p.CXXFiles) > 0 || len(p.SwigCXXFiles) > 0
 	for _, a := range allactions {
-		if a.p != nil && len(a.p.CXXFiles) > 0 {
+		if a.p != nil && (len(a.p.CXXFiles) > 0 || len(a.p.SwigCXXFiles) > 0) {
 			cxx = true
 		}
 	}
@@ -1892,7 +1892,7 @@
 		}
 	}
 	ldflags = append(ldflags, buildLdflags...)
-	return b.run(".", p.ImportPath, nil, buildToolExec, tool(archChar+"l"), "-o", out, importArgs, ldflags, mainpkg)
+	return b.run(".", p.ImportPath, nil, buildToolExec, tool(archChar()+"l"), "-o", out, importArgs, ldflags, mainpkg)
 }
 
 func (gcToolchain) cc(b *builder, p *Package, objdir, ofile, cfile string) error {
@@ -1920,7 +1920,7 @@
 	return gccgoBin
 }
 
-func (gccgoToolchain) gc(b *builder, p *Package, archive, obj string, asmhdr bool, importArgs []string, gofiles []string) (ofile string, output []byte, err error) {
+func (tools gccgoToolchain) gc(b *builder, p *Package, archive, obj string, asmhdr bool, importArgs []string, gofiles []string) (ofile string, output []byte, err error) {
 	out := "_go_.o"
 	ofile = obj + out
 	gcargs := []string{"-g"}
@@ -1931,7 +1931,7 @@
 	if p.localPrefix != "" {
 		gcargs = append(gcargs, "-fgo-relative-import-path="+p.localPrefix)
 	}
-	args := stringList(gccgoName, importArgs, "-c", gcargs, "-o", ofile, buildGccgoflags)
+	args := stringList(tools.compiler(), importArgs, "-c", gcargs, "-o", ofile, buildGccgoflags)
 	for _, f := range gofiles {
 		args = append(args, mkAbs(p.Dir, f))
 	}
@@ -1940,14 +1940,14 @@
 	return ofile, output, err
 }
 
-func (gccgoToolchain) asm(b *builder, p *Package, obj, ofile, sfile string) error {
+func (tools gccgoToolchain) asm(b *builder, p *Package, obj, ofile, sfile string) error {
 	sfile = mkAbs(p.Dir, sfile)
 	defs := []string{"-D", "GOOS_" + goos, "-D", "GOARCH_" + goarch}
 	if pkgpath := gccgoCleanPkgpath(p); pkgpath != "" {
 		defs = append(defs, `-D`, `GOPKGPATH="`+pkgpath+`"`)
 	}
 	defs = append(defs, b.gccArchArgs()...)
-	return b.run(p.Dir, p.ImportPath, nil, gccgoName, "-I", obj, "-o", ofile, defs, sfile)
+	return b.run(p.Dir, p.ImportPath, nil, tools.compiler(), "-I", obj, "-o", ofile, defs, sfile)
 }
 
 func (gccgoToolchain) pkgpath(basedir string, p *Package) string {
@@ -1968,35 +1968,39 @@
 func (tools gccgoToolchain) ld(b *builder, p *Package, out string, allactions []*action, mainpkg string, ofiles []string) error {
 	// gccgo needs explicit linking with all package dependencies,
 	// and all LDFLAGS from cgo dependencies.
+	apackagesSeen := make(map[*Package]bool)
 	afiles := []string{}
+	xfiles := []string{}
 	ldflags := b.gccArchArgs()
 	cgoldflags := []string{}
 	usesCgo := false
-	cxx := len(p.CXXFiles) > 0
+	cxx := len(p.CXXFiles) > 0 || len(p.SwigCXXFiles) > 0
 	objc := len(p.MFiles) > 0
 
-	// For a given package import path:
-	//   1) prefer a test package (created by (*builder).test) to a non-test package
-	//   2) prefer the output of an install action to the output of a build action
-	//      because the install action will delete the output of the build
-	//      action
-	// Iterating over the list backwards (reverse dependency order) ensures that we
-	// always see an install before a build.
-	importPathsSeen := make(map[string]bool)
+	// Prefer the output of an install action to the output of a build action,
+	// because the install action will delete the output of the build action.
+	// Iterate over the list backward (reverse dependency order) so that we
+	// always see the install before the build.
 	for i := len(allactions) - 1; i >= 0; i-- {
 		a := allactions[i]
-		if a.p.fake && !importPathsSeen[a.p.ImportPath] {
-			importPathsSeen[a.p.ImportPath] = true
-			afiles = append(afiles, a.target)
+		if !a.p.Standard {
+			if a.p != nil && !apackagesSeen[a.p] {
+				apackagesSeen[a.p] = true
+				if a.p.fake && a.p.external {
+					// external _tests, if present must come before
+					// internal _tests. Store these on a seperate list
+					// and place them at the head after this loop.
+					xfiles = append(xfiles, a.target)
+				} else if a.p.fake {
+					// move _test files to the top of the link order
+					afiles = append([]string{a.target}, afiles...)
+				} else {
+					afiles = append(afiles, a.target)
+				}
+			}
 		}
 	}
-	for i := len(allactions) - 1; i >= 0; i-- {
-		a := allactions[i]
-		if !a.p.Standard && !importPathsSeen[a.p.ImportPath] {
-			importPathsSeen[a.p.ImportPath] = true
-			afiles = append(afiles, a.target)
-		}
-	}
+	afiles = append(xfiles, afiles...)
 
 	for _, a := range allactions {
 		cgoldflags = append(cgoldflags, a.p.CgoLDFLAGS...)
@@ -2006,7 +2010,7 @@
 		if a.p.usesSwig() {
 			usesCgo = true
 		}
-		if len(a.p.CXXFiles) > 0 {
+		if len(a.p.CXXFiles) > 0 || len(a.p.SwigCXXFiles) > 0 {
 			cxx = true
 		}
 		if len(a.p.MFiles) > 0 {
@@ -2026,11 +2030,11 @@
 	if objc {
 		ldflags = append(ldflags, "-lobjc")
 	}
-	return b.run(".", p.ImportPath, nil, gccgoName, "-o", out, ofiles, "-Wl,-(", ldflags, "-Wl,-)", buildGccgoflags)
+	return b.run(".", p.ImportPath, nil, tools.linker(), "-o", out, ofiles, "-Wl,-(", ldflags, "-Wl,-)", buildGccgoflags)
 }
 
 func (gccgoToolchain) cc(b *builder, p *Package, objdir, ofile, cfile string) error {
-	inc := filepath.Join(goroot, "pkg", fmt.Sprintf("%s_%s", goos, goarch))
+	inc := filepath.Join(goroot, "pkg", "include")
 	cfile = mkAbs(p.Dir, cfile)
 	defs := []string{"-D", "GOOS_" + goos, "-D", "GOARCH_" + goarch}
 	defs = append(defs, b.gccArchArgs()...)
@@ -2116,7 +2120,7 @@
 // gccld runs the gcc linker to create an executable from a set of object files.
 func (b *builder) gccld(p *Package, out string, flags []string, obj []string) error {
 	var cmd []string
-	if len(p.CXXFiles) > 0 {
+	if len(p.CXXFiles) > 0 || len(p.SwigCXXFiles) > 0 {
 		cmd = b.gxxCmd(p.Dir)
 	} else {
 		cmd = b.gccCmd(p.Dir)
@@ -2185,12 +2189,12 @@
 
 // gccArchArgs returns arguments to pass to gcc based on the architecture.
 func (b *builder) gccArchArgs() []string {
-	switch archChar {
-	case "8":
+	switch goarch {
+	case "386":
 		return []string{"-m32"}
-	case "6":
+	case "amd64", "amd64p32":
 		return []string{"-m64"}
-	case "5":
+	case "arm":
 		return []string{"-marm"} // not thumb
 	}
 	return nil
@@ -2228,7 +2232,7 @@
 	cgoLibGccFileOnce sync.Once
 )
 
-func (b *builder) cgo(p *Package, cgoExe, obj string, pcCFLAGS, pcLDFLAGS, gccfiles, gxxfiles, mfiles []string) (outGo, outObj []string, err error) {
+func (b *builder) cgo(p *Package, cgoExe, obj string, pcCFLAGS, pcLDFLAGS, cgofiles, gccfiles, gxxfiles, mfiles []string) (outGo, outObj []string, err error) {
 	cgoCPPFLAGS, cgoCFLAGS, cgoCXXFLAGS, cgoLDFLAGS := b.cflags(p, true)
 	_, cgoexeCFLAGS, _, _ := b.cflags(p, false)
 	cgoCPPFLAGS = append(cgoCPPFLAGS, pcCFLAGS...)
@@ -2245,7 +2249,7 @@
 	// TODO: CGOPKGPATH, CGO_FLAGS?
 	gofiles := []string{obj + "_cgo_gotypes.go"}
 	cfiles := []string{"_cgo_main.c", "_cgo_export.c"}
-	for _, fn := range p.CgoFiles {
+	for _, fn := range cgofiles {
 		f := cgoRe.ReplaceAllString(fn[:len(fn)-2], "_")
 		gofiles = append(gofiles, obj+f+"cgo1.go")
 		cfiles = append(cfiles, f+"cgo2.c")
@@ -2255,7 +2259,12 @@
 	cgoflags := []string{}
 	// TODO: make cgo not depend on $GOARCH?
 
-	objExt := archChar
+	var objExt string
+	if _, ok := buildToolchain.(gccgoToolchain); ok {
+		objExt = "o"
+	} else {
+		objExt = archChar()
+	}
 
 	if p.Standard && p.ImportPath == "runtime/cgo" {
 		cgoflags = append(cgoflags, "-import_runtime_cgo=false")
@@ -2279,9 +2288,8 @@
 		if pkgpath := gccgoPkgpath(p); pkgpath != "" {
 			cgoflags = append(cgoflags, "-gccgopkgpath="+pkgpath)
 		}
-		objExt = "o"
 	}
-	if err := b.run(p.Dir, p.ImportPath, cgoenv, buildToolExec, cgoExe, "-objdir", obj, cgoflags, "--", cgoCPPFLAGS, cgoexeCFLAGS, p.CgoFiles); err != nil {
+	if err := b.run(p.Dir, p.ImportPath, cgoenv, buildToolExec, cgoExe, "-objdir", obj, cgoflags, "--", cgoCPPFLAGS, cgoexeCFLAGS, cgofiles); err != nil {
 		return nil, nil, err
 	}
 	outGo = append(outGo, gofiles...)
@@ -2458,77 +2466,41 @@
 // Run SWIG on all SWIG input files.
 // TODO: Don't build a shared library, once SWIG emits the necessary
 // pragmas for external linking.
-func (b *builder) swig(p *Package, obj string, pcCFLAGS, gccfiles, gxxfiles, mfiles []string) (outGo, outObj []string, err error) {
-	cgoCPPFLAGS, cgoCFLAGS, cgoCXXFLAGS, _ := b.cflags(p, true)
-	cflags := stringList(cgoCPPFLAGS, cgoCFLAGS)
-	cxxflags := stringList(cgoCPPFLAGS, cgoCXXFLAGS)
-
-	for _, file := range gccfiles {
-		ofile := obj + cgoRe.ReplaceAllString(file[:len(file)-1], "_") + "o"
-		if err := b.gcc(p, ofile, cflags, file); err != nil {
-			return nil, nil, err
-		}
-		outObj = append(outObj, ofile)
-	}
-
-	for _, file := range gxxfiles {
-		// Append .o to the file, just in case the pkg has file.c and file.cpp
-		ofile := obj + cgoRe.ReplaceAllString(file, "_") + ".o"
-		if err := b.gxx(p, ofile, cxxflags, file); err != nil {
-			return nil, nil, err
-		}
-		outObj = append(outObj, ofile)
-	}
-
-	for _, file := range mfiles {
-		// Append .o to the file, just in case the pkg has file.c and file.cpp
-		ofile := obj + cgoRe.ReplaceAllString(file, "_") + ".o"
-		if err := b.gcc(p, ofile, cflags, file); err != nil {
-			return nil, nil, err
-		}
-		outObj = append(outObj, ofile)
-	}
-
+func (b *builder) swig(p *Package, obj string, pcCFLAGS []string) (outGo, outC, outCXX []string, err error) {
 	if err := b.swigVersionCheck(); err != nil {
-		return nil, nil, err
+		return nil, nil, nil, err
 	}
 
 	intgosize, err := b.swigIntSize(obj)
 	if err != nil {
-		return nil, nil, err
+		return nil, nil, nil, err
 	}
 
 	for _, f := range p.SwigFiles {
-		goFile, objFile, gccObjFile, err := b.swigOne(p, f, obj, pcCFLAGS, false, intgosize)
+		goFile, cFile, err := b.swigOne(p, f, obj, pcCFLAGS, false, intgosize)
 		if err != nil {
-			return nil, nil, err
+			return nil, nil, nil, err
 		}
 		if goFile != "" {
 			outGo = append(outGo, goFile)
 		}
-		if objFile != "" {
-			outObj = append(outObj, objFile)
-		}
-		if gccObjFile != "" {
-			outObj = append(outObj, gccObjFile)
+		if cFile != "" {
+			outC = append(outC, cFile)
 		}
 	}
 	for _, f := range p.SwigCXXFiles {
-		goFile, objFile, gccObjFile, err := b.swigOne(p, f, obj, pcCFLAGS, true, intgosize)
+		goFile, cxxFile, err := b.swigOne(p, f, obj, pcCFLAGS, true, intgosize)
 		if err != nil {
-			return nil, nil, err
+			return nil, nil, nil, err
 		}
 		if goFile != "" {
 			outGo = append(outGo, goFile)
 		}
-		if objFile != "" {
-			outObj = append(outObj, objFile)
-		}
-		if gccObjFile != "" {
-			outObj = append(outObj, gccObjFile)
+		if cxxFile != "" {
+			outCXX = append(outCXX, cxxFile)
 		}
 	}
-	return outGo, outObj, nil
+	return outGo, outC, outCXX, nil
 }
 
 // Make sure SWIG is new enough.
@@ -2542,20 +2514,51 @@
 	if err != nil {
 		return err
 	}
-	re := regexp.MustCompile(`[vV]ersion +([\d])`)
+	re := regexp.MustCompile(`[vV]ersion +([\d]+)([.][\d]+)?([.][\d]+)?`)
 	matches := re.FindSubmatch(out)
 	if matches == nil {
 		// Can't find version number; hope for the best.
 		return nil
 	}
+
 	major, err := strconv.Atoi(string(matches[1]))
 	if err != nil {
 		// Can't find version number; hope for the best.
 		return nil
 	}
+	const errmsg = "must have SWIG version >= 3.0.6"
 	if major < 3 {
-		return errors.New("must have SWIG version >= 3.0")
+		return errors.New(errmsg)
 	}
+	if major > 3 {
+		// 4.0 or later
+		return nil
+	}
+
+	// We have SWIG version 3.x.
+	if len(matches[2]) > 0 {
+		minor, err := strconv.Atoi(string(matches[2][1:]))
+		if err != nil {
+			return nil
+		}
+		if minor > 0 {
+			// 3.1 or later
+			return nil
+		}
+	}
+
+	// We have SWIG version 3.0.x.
+	if len(matches[3]) > 0 {
+		patch, err := strconv.Atoi(string(matches[3][1:]))
+		if err != nil {
+			return nil
+		}
+		if patch < 6 {
+			// Before 3.0.6.
+			return errors.New(errmsg)
+		}
+	}
+
 	return nil
 }
 
@@ -2593,7 +2596,7 @@
 }
 
 // Run SWIG on one SWIG input file.
-func (b *builder) swigOne(p *Package, file, obj string, pcCFLAGS []string, cxx bool, intgosize string) (outGo, outObj, objGccObj string, err error) {
+func (b *builder) swigOne(p *Package, file, obj string, pcCFLAGS []string, cxx bool, intgosize string) (outGo, outC string, err error) {
 	cgoCPPFLAGS, cgoCFLAGS, cgoCXXFLAGS, _ := b.cflags(p, true)
 	var cflags []string
 	if cxx {
@@ -2608,7 +2611,6 @@
 	}
 	base := file[:len(file)-n]
 	goFile := base + ".go"
-	cBase := base + "_gc."
 	gccBase := base + "_wrap."
 	gccExt := "c"
 	if cxx {
@@ -2620,6 +2622,7 @@
 	// swig
 	args := []string{
 		"-go",
+		"-cgo",
 		"-intgosize", intgosize,
 		"-module", base,
 		"-o", obj + gccBase + gccExt,
@@ -2644,37 +2647,16 @@
 
 	if out, err := b.runOut(p.Dir, p.ImportPath, nil, "swig", args, file); err != nil {
 		if len(out) > 0 {
-			if bytes.Contains(out, []byte("Unrecognized option -intgosize")) {
-				return "", "", "", errors.New("must have SWIG version >= 3.0")
+			if bytes.Contains(out, []byte("-intgosize")) || bytes.Contains(out, []byte("-cgo")) {
+				return "", "", errors.New("must have SWIG version >= 3.0.6")
 			}
 			b.showOutput(p.Dir, p.ImportPath, b.processOutput(out))
-			return "", "", "", errPrintedOutput
+			return "", "", errPrintedOutput
 		}
-		return "", "", "", err
+		return "", "", err
 	}
 
-	var cObj string
-	if !gccgo {
-		// cc
-		cObj = obj + cBase + archChar
-		if err := buildToolchain.cc(b, p, obj, cObj, obj+cBase+"c"); err != nil {
-			return "", "", "", err
-		}
-	}
-
-	// gcc
-	gccObj := obj + gccBase + "o"
-	if !cxx {
-		if err := b.gcc(p, gccObj, cflags, obj+gccBase+gccExt); err != nil {
-			return "", "", "", err
-		}
-	} else {
-		if err := b.gxx(p, gccObj, cflags, obj+gccBase+gccExt); err != nil {
-			return "", "", "", err
-		}
-	}
-
-	return obj + goFile, cObj, gccObj, nil
+	return obj + goFile, obj + gccBase + gccExt, nil
 }
 
 // An actionQueue is a priority queue of actions.
diff --git a/src/cmd/go/doc.go b/src/cmd/go/doc.go
index 7c92389..ba1a707 100644
--- a/src/cmd/go/doc.go
+++ b/src/cmd/go/doc.go
@@ -81,7 +81,8 @@
 		print the commands but do not run them.
 	-p n
 		the number of builds that can be run in parallel.
-		The default is the number of CPUs available.
+		The default is the number of CPUs available, except
+		on darwin/arm which defaults to 1.
 	-race
 		enable data race detection.
 		Supported only on linux/amd64, freebsd/amd64, darwin/amd64 and windows/amd64.
@@ -106,6 +107,8 @@
 		or, if set explicitly, has _race appended to it.
 	-ldflags 'flag list'
 		arguments to pass on each 5l, 6l, 8l, or 9l linker invocation.
+	-asmflags 'flag list'
+		arguments to pass on each asm assembler invocation.
 	-tags 'tag list'
 		a list of build tags to consider satisfied during the build.
 		For more information about build tags, see the description of
@@ -931,6 +934,9 @@
 - "std" is like all but expands to just the packages in the standard
 Go library.
 
+- "cmd" expands to the Go repository's commands and their
+internal libraries.
+
 An import path is a pattern if it includes one or more "..." wildcards,
 each of which can match any string, including the empty string and
 strings containing slashes.  Such a pattern expands to all package
diff --git a/src/cmd/go/env.go b/src/cmd/go/env.go
index 26d37df..863eb4d 100644
--- a/src/cmd/go/env.go
+++ b/src/cmd/go/env.go
@@ -36,7 +36,6 @@
 	env := []envVar{
 		{"GOARCH", goarch},
 		{"GOBIN", gobin},
-		{"GOCHAR", archChar},
 		{"GOEXE", exeSuffix},
 		{"GOHOSTARCH", runtime.GOARCH},
 		{"GOHOSTOS", runtime.GOOS},
@@ -50,6 +49,10 @@
 		{"TERM", "dumb"},
 	}
 
+	if archCharErr == nil {
+		env = append(env, envVar{"GOCHAR", archChar()})
+	}
+
 	if goos != "plan9" {
 		cmd := b.gccCmd(".")
 		env = append(env, envVar{"CC", cmd[0]})
diff --git a/src/cmd/go/generate.go b/src/cmd/go/generate.go
index 3c0af87..8e9ad38 100644
--- a/src/cmd/go/generate.go
+++ b/src/cmd/go/generate.go
@@ -64,6 +64,8 @@
 		The base name of the file.
 	$GOPACKAGE
 		The name of the package of the file containing the directive.
+	$DOLLAR
+		A dollar sign.
 
 Other than variable substitution and quoted-string evaluation, no
 special processing such as "globbing" is performed on the command
@@ -348,6 +350,8 @@
 			sub = g.file
 		case "GOPACKAGE":
 			sub = g.pkg
+		case "DOLLAR":
+			sub = "$"
 		default:
 			sub = os.Getenv(envVar)
 		}
diff --git a/src/cmd/go/generate_test.go b/src/cmd/go/generate_test.go
index 2ec5486..169d71c 100644
--- a/src/cmd/go/generate_test.go
+++ b/src/cmd/go/generate_test.go
@@ -26,6 +26,7 @@
 	{"$GOPACKAGE", []string{"sys"}},
 	{"a $XXNOTDEFINEDXX b", []string{"a", "", "b"}},
 	{"/$XXNOTDEFINED/", []string{"//"}},
+	{"/$DOLLAR/", []string{"/$/"}},
 	{"yacc -o $GOARCH/yacc_$GOFILE", []string{"go", "tool", "yacc", "-o", runtime.GOARCH + "/yacc_proc.go"}},
 }
 
diff --git a/src/cmd/go/get.go b/src/cmd/go/get.go
index 01ca4b2..c7399eb 100644
--- a/src/cmd/go/get.go
+++ b/src/cmd/go/get.go
@@ -155,6 +155,16 @@
 		return
 	}
 
+	// loadPackage inferred the canonical ImportPath from arg.
+	// Use that in the following to prevent hysteresis effects
+	// in e.g. downloadCache and packageCache.
+	// This allows invocations such as:
+	//   mkdir -p $GOPATH/src/github.com/user
+	//   cd $GOPATH/src/github.com/user
+	//   go get ./foo
+	// see: golang.org/issue/9767
+	arg = p.ImportPath
+
 	// There's nothing to do if this is a package in the standard library.
 	if p.Standard {
 		return
diff --git a/src/cmd/go/main.go b/src/cmd/go/main.go
index 372f089..5e0ab79 100644
--- a/src/cmd/go/main.go
+++ b/src/cmd/go/main.go
@@ -152,6 +152,17 @@
 		os.Exit(2)
 	}
 
+	// Set environment (GOOS, GOARCH, etc) explicitly.
+	// In theory all the commands we invoke should have
+	// the same default computation of these as we do,
+	// but in practice there might be skew
+	// This makes sure we all agree.
+	for _, env := range mkEnv() {
+		if os.Getenv(env.name) != env.value {
+			os.Setenv(env.name, env.value)
+		}
+	}
+
 	for _, cmd := range commands {
 		if cmd.Name() == args[0] && cmd.Runnable() {
 			cmd.Flag.Usage = func() { cmd.Usage() }
diff --git a/src/cmd/go/pkg.go b/src/cmd/go/pkg.go
index 57f997f..8bf0f56 100644
--- a/src/cmd/go/pkg.go
+++ b/src/cmd/go/pkg.go
@@ -83,6 +83,7 @@
 	allgofiles   []string             // gofiles + IgnoredGoFiles, absolute paths
 	target       string               // installed file for this package (may be executable)
 	fake         bool                 // synthesized package
+	external     bool                 // synthesized external test package
 	forceBuild   bool                 // this package must be rebuilt
 	forceLibrary bool                 // this package is a library (even if named "main")
 	cmdline      bool                 // defined by files listed on command line
@@ -176,7 +177,7 @@
 	return append([]string{}, *s...)
 }
 
-// shorterThan returns true if sp is shorter than t.
+// shorterThan reports whether sp is shorter than t.
 // We use this to record the shortest import sequence
 // that leads to a particular package.
 func (sp *importStack) shorterThan(t []string) bool {
@@ -395,6 +396,8 @@
 	"cmd/5l":                               toTool,
 	"cmd/6g":                               toTool,
 	"cmd/6l":                               toTool,
+	"cmd/7g":                               toTool,
+	"cmd/7l":                               toTool,
 	"cmd/8g":                               toTool,
 	"cmd/8l":                               toTool,
 	"cmd/9g":                               toTool,
diff --git a/src/cmd/go/test.bash b/src/cmd/go/test.bash
index 25d3c66..39071e9 100755
--- a/src/cmd/go/test.bash
+++ b/src/cmd/go/test.bash
@@ -1120,6 +1120,16 @@
 unset GOPATH
 rm -rf $d
 
+TEST go get ./rsc.io/toolstash '(golang.org/issue/9767)'
+d=$(TMPDIR=/var/tmp mktemp -d -t testgoXXX)
+export GOPATH=$d
+export testgo=$(pwd)/testgo
+mkdir -p $GOPATH/src/rsc.io
+(cd $GOPATH/src/rsc.io && $testgo get ./toolstash) || ok=false
+unset GOPATH
+unset testgo
+rm -rf $d
+
 # clean up
 if $started; then stop; fi
 rm -rf testdata/bin testdata/bin1
diff --git a/src/cmd/go/test.go b/src/cmd/go/test.go
index c44a219..e96ed22 100644
--- a/src/cmd/go/test.go
+++ b/src/cmd/go/test.go
@@ -687,10 +687,11 @@
 			build: &build.Package{
 				ImportPos: p.build.XTestImportPos,
 			},
-			imports: ximports,
-			pkgdir:  testDir,
-			fake:    true,
-			Stale:   true,
+			imports:  ximports,
+			pkgdir:   testDir,
+			fake:     true,
+			external: true,
+			Stale:    true,
 		}
 		if pxtestNeedsPtest {
 			pxtest.imports = append(pxtest.imports, ptest)
diff --git a/src/cmd/go/testflag.go b/src/cmd/go/testflag.go
index b3479e1..5652e54 100644
--- a/src/cmd/go/testflag.go
+++ b/src/cmd/go/testflag.go
@@ -16,43 +16,6 @@
 // our command line are for us, and some are for 6.out, and
 // some are for both.
 
-var usageMessage = `Usage of go test:
-  -c=false: compile but do not run the test binary
-  -file=file_test.go: specify file to use for tests;
-      use multiple times for multiple files
-  -p=n: build and test up to n packages in parallel
-  -x=false: print command lines as they are executed
-
-  // These flags can be passed with or without a "test." prefix: -v or -test.v.
-  -bench="": passes -test.bench to test
-  -benchmem=false: print memory allocation statistics for benchmarks
-  -benchtime=1s: passes -test.benchtime to test
-  -cover=false: enable coverage analysis
-  -covermode="set": specifies mode for coverage analysis
-  -coverpkg="": comma-separated list of packages for coverage analysis
-  -coverprofile="": passes -test.coverprofile to test if -cover
-  -cpu="": passes -test.cpu to test
-  -cpuprofile="": passes -test.cpuprofile to test
-  -memprofile="": passes -test.memprofile to test
-  -memprofilerate=0: passes -test.memprofilerate to test
-  -blockprofile="": pases -test.blockprofile to test
-  -blockprofilerate=0: passes -test.blockprofilerate to test
-  -outputdir=$PWD: passes -test.outputdir to test
-  -parallel=0: passes -test.parallel to test
-  -run="": passes -test.run to test
-  -short=false: passes -test.short to test
-  -timeout=0: passes -test.timeout to test
-  -trace="": passes -test.trace to test
-  -v=false: passes -test.v to test
-`
-
-// usage prints a usage message and exits.
-func testUsage() {
-	fmt.Fprint(os.Stderr, usageMessage)
-	setExitStatus(2)
-	exit()
-}
-
 // testFlagSpec defines a flag we know about.
 type testFlagSpec struct {
 	name       string
@@ -67,6 +30,7 @@
 	// local.
 	{name: "c", boolVar: &testC},
 	{name: "cover", boolVar: &testCover},
+	{name: "covermode"},
 	{name: "coverpkg"},
 	{name: "o"},
 
@@ -90,7 +54,6 @@
 	{name: "bench", passToTest: true},
 	{name: "benchmem", boolVar: new(bool), passToTest: true},
 	{name: "benchtime", passToTest: true},
-	{name: "covermode"},
 	{name: "coverprofile", passToTest: true},
 	{name: "cpu", passToTest: true},
 	{name: "cpuprofile", passToTest: true},
diff --git a/src/cmd/gofmt/gofmt.go b/src/cmd/gofmt/gofmt.go
index 81da21f..b2805ac 100644
--- a/src/cmd/gofmt/gofmt.go
+++ b/src/cmd/gofmt/gofmt.go
@@ -13,6 +13,7 @@
 	"go/printer"
 	"go/scanner"
 	"go/token"
+	"internal/format"
 	"io"
 	"io/ioutil"
 	"os"
@@ -87,7 +88,7 @@
 		return err
 	}
 
-	file, sourceAdj, indentAdj, err := parse(fileSet, filename, src, stdin)
+	file, sourceAdj, indentAdj, err := format.Parse(fileSet, filename, src, stdin)
 	if err != nil {
 		return err
 	}
@@ -106,7 +107,7 @@
 		simplify(file)
 	}
 
-	res, err := format(fileSet, file, sourceAdj, indentAdj, src, printer.Config{Mode: printerMode, Tabwidth: tabWidth})
+	res, err := format.Format(fileSet, file, sourceAdj, indentAdj, src, printer.Config{Mode: printerMode, Tabwidth: tabWidth})
 	if err != nil {
 		return err
 	}
@@ -234,154 +235,3 @@
 	return
 
 }
-
-// ----------------------------------------------------------------------------
-// Support functions
-//
-// The functions parse, format, and isSpace below are identical to the
-// respective functions in src/go/format/format.go - keep them in sync!
-//
-// TODO(gri) Factor out this functionality, eventually.
-
-// parse parses src, which was read from the named file,
-// as a Go source file, declaration, or statement list.
-func parse(fset *token.FileSet, filename string, src []byte, fragmentOk bool) (
-	file *ast.File,
-	sourceAdj func(src []byte, indent int) []byte,
-	indentAdj int,
-	err error,
-) {
-	// Try as whole source file.
-	file, err = parser.ParseFile(fset, filename, src, parserMode)
-	// If there's no error, return.  If the error is that the source file didn't begin with a
-	// package line and source fragments are ok, fall through to
-	// try as a source fragment.  Stop and return on any other error.
-	if err == nil || !fragmentOk || !strings.Contains(err.Error(), "expected 'package'") {
-		return
-	}
-
-	// If this is a declaration list, make it a source file
-	// by inserting a package clause.
-	// Insert using a ;, not a newline, so that the line numbers
-	// in psrc match the ones in src.
-	psrc := append([]byte("package p;"), src...)
-	file, err = parser.ParseFile(fset, filename, psrc, parserMode)
-	if err == nil {
-		sourceAdj = func(src []byte, indent int) []byte {
-			// Remove the package clause.
-			// Gofmt has turned the ; into a \n.
-			src = src[indent+len("package p\n"):]
-			return bytes.TrimSpace(src)
-		}
-		return
-	}
-	// If the error is that the source file didn't begin with a
-	// declaration, fall through to try as a statement list.
-	// Stop and return on any other error.
-	if !strings.Contains(err.Error(), "expected declaration") {
-		return
-	}
-
-	// If this is a statement list, make it a source file
-	// by inserting a package clause and turning the list
-	// into a function body.  This handles expressions too.
-	// Insert using a ;, not a newline, so that the line numbers
-	// in fsrc match the ones in src.
-	fsrc := append(append([]byte("package p; func _() {"), src...), '\n', '}')
-	file, err = parser.ParseFile(fset, filename, fsrc, parserMode)
-	if err == nil {
-		sourceAdj = func(src []byte, indent int) []byte {
-			// Cap adjusted indent to zero.
-			if indent < 0 {
-				indent = 0
-			}
-			// Remove the wrapping.
-			// Gofmt has turned the ; into a \n\n.
-			// There will be two non-blank lines with indent, hence 2*indent.
-			src = src[2*indent+len("package p\n\nfunc _() {"):]
-			src = src[:len(src)-(indent+len("\n}\n"))]
-			return bytes.TrimSpace(src)
-		}
-		// Gofmt has also indented the function body one level.
-		// Adjust that with indentAdj.
-		indentAdj = -1
-	}
-
-	// Succeeded, or out of options.
-	return
-}
-
-// format formats the given package file originally obtained from src
-// and adjusts the result based on the original source via sourceAdj
-// and indentAdj.
-func format(
-	fset *token.FileSet,
-	file *ast.File,
-	sourceAdj func(src []byte, indent int) []byte,
-	indentAdj int,
-	src []byte,
-	cfg printer.Config,
-) ([]byte, error) {
-	if sourceAdj == nil {
-		// Complete source file.
-		var buf bytes.Buffer
-		err := cfg.Fprint(&buf, fset, file)
-		if err != nil {
-			return nil, err
-		}
-		return buf.Bytes(), nil
-	}
-
-	// Partial source file.
-	// Determine and prepend leading space.
-	i, j := 0, 0
-	for j < len(src) && isSpace(src[j]) {
-		if src[j] == '\n' {
-			i = j + 1 // byte offset of last line in leading space
-		}
-		j++
-	}
-	var res []byte
-	res = append(res, src[:i]...)
-
-	// Determine and prepend indentation of first code line.
-	// Spaces are ignored unless there are no tabs,
-	// in which case spaces count as one tab.
-	indent := 0
-	hasSpace := false
-	for _, b := range src[i:j] {
-		switch b {
-		case ' ':
-			hasSpace = true
-		case '\t':
-			indent++
-		}
-	}
-	if indent == 0 && hasSpace {
-		indent = 1
-	}
-	for i := 0; i < indent; i++ {
-		res = append(res, '\t')
-	}
-
-	// Format the source.
-	// Write it without any leading and trailing space.
-	cfg.Indent = indent + indentAdj
-	var buf bytes.Buffer
-	err := cfg.Fprint(&buf, fset, file)
-	if err != nil {
-		return nil, err
-	}
-	res = append(res, sourceAdj(buf.Bytes(), cfg.Indent)...)
-
-	// Determine and append trailing space.
-	i = len(src)
-	for i > 0 && isSpace(src[i-1]) {
-		i--
-	}
-	return append(res, src[i:]...), nil
-}
-
-func isSpace(b byte) bool {
-	return b == ' ' || b == '\t' || b == '\n' || b == '\r'
-}
diff --git a/src/cmd/gofmt/long_test.go b/src/cmd/gofmt/long_test.go
index 237b860..df9a878 100644
--- a/src/cmd/gofmt/long_test.go
+++ b/src/cmd/gofmt/long_test.go
@@ -15,6 +15,7 @@
 	"go/ast"
 	"go/printer"
 	"go/token"
+	"internal/format"
 	"io"
 	"os"
 	"path/filepath"
@@ -32,7 +33,7 @@
 )
 
 func gofmt(fset *token.FileSet, filename string, src *bytes.Buffer) error {
-	f, _, _, err := parse(fset, filename, src.Bytes(), false)
+	f, _, _, err := format.Parse(fset, filename, src.Bytes(), false)
 	if err != nil {
 		return err
 	}
@@ -60,7 +61,7 @@
 
 	// exclude files w/ syntax errors (typically test cases)
 	fset := token.NewFileSet()
-	if _, _, _, err = parse(fset, filename, b1.Bytes(), false); err != nil {
+	if _, _, _, err = format.Parse(fset, filename, b1.Bytes(), false); err != nil {
 		if *verbose {
 			fmt.Fprintf(os.Stderr, "ignoring %s\n", err)
 		}
diff --git a/src/cmd/gofmt/rewrite.go b/src/cmd/gofmt/rewrite.go
index d267cfc..069f966 100644
--- a/src/cmd/gofmt/rewrite.go
+++ b/src/cmd/gofmt/rewrite.go
@@ -154,7 +154,7 @@
 	return size == len(s) && unicode.IsLower(rune)
 }
 
-// match returns true if pattern matches val,
+// match reports whether pattern matches val,
 // recording wildcard submatches in m.
 // If m == nil, match checks whether pattern == val.
 func match(m map[string]reflect.Value, pattern, val reflect.Value) bool {
diff --git a/src/cmd/internal/asm/asm.go b/src/cmd/internal/asm/asm.go
index 71c6b1a..b67b4d7 100644
--- a/src/cmd/internal/asm/asm.go
+++ b/src/cmd/internal/asm/asm.go
@@ -81,7 +81,6 @@
 	EOF      = -1
 	IGN      = -2
 	NHASH    = 503
-	STRINGSZ = 200
 	NMACRO   = 10
 )
 
@@ -163,11 +162,9 @@
 }
 
 func Main() {
-	var p string
-
 	// Allow GOARCH=Thestring or GOARCH=Thestringsuffix,
 	// but not other values.
-	p = obj.Getgoarch()
+	p := obj.Getgoarch()
 
 	if !strings.HasPrefix(p, Thestring) {
 		log.Fatalf("cannot use %cc with GOARCH=%s", Thechar, p)
@@ -219,8 +216,6 @@
 }
 
 func assemble(file string) int {
-	var i int
-
 	if outfile == "" {
 		outfile = strings.TrimSuffix(filepath.Base(file), ".s") + "." + string(Thechar)
 	}
@@ -235,6 +230,7 @@
 	fmt.Fprintf(&obuf, "go object %s %s %s\n", obj.Getgoos(), obj.Getgoarch(), obj.Getgoversion())
 	fmt.Fprintf(&obuf, "!\n")
 
+	var i int
 	for Pass = 1; Pass <= 2; Pass++ {
 		pinit(file)
 		for i = 0; i < len(Dlist); i++ {
diff --git a/src/cmd/internal/asm/lexbody.go b/src/cmd/internal/asm/lexbody.go
index 14a82f8..7943cba 100644
--- a/src/cmd/internal/asm/lexbody.go
+++ b/src/cmd/internal/asm/lexbody.go
@@ -45,61 +45,50 @@
  * common code for all the assemblers
  */
 func pragpack() {
-
 	for getnsc() != '\n' {
-
 	}
 }
 
 func pragvararg() {
 	for getnsc() != '\n' {
-
 	}
 }
 
 func pragcgo(name string) {
 	for getnsc() != '\n' {
-
 	}
 }
 
 func pragfpround() {
 	for getnsc() != '\n' {
-
 	}
 }
 
 func pragtextflag() {
 	for getnsc() != '\n' {
-
 	}
 }
 
 func pragdataflag() {
 	for getnsc() != '\n' {
-
 	}
 }
 
 func pragprofile() {
 	for getnsc() != '\n' {
-
 	}
 }
 
 func pragincomplete() {
 	for getnsc() != '\n' {
-
 	}
 }
 
 func setinclude(p string) {
-	var i int
-
 	if p == "" {
 		return
 	}
-	for i = 1; i < len(include); i++ {
+	for i := 1; i < len(include); i++ {
 		if p == include[i] {
 			return
 		}
@@ -117,9 +106,7 @@
 }
 
 func pushio() {
-	var i *Io
-
-	i = iostack
+	i := iostack
 	if i == nil {
 		Yyerror("botch in pushio")
 		errorexit()
@@ -129,10 +116,9 @@
 }
 
 func newio() {
-	var i *Io
 	var pushdepth int = 0
 
-	i = iofree
+	i := iofree
 	if i == nil {
 		pushdepth++
 		if pushdepth > 1000 {
@@ -149,9 +135,7 @@
 }
 
 func newfile(s string, f *os.File) {
-	var i *Io
-
-	i = ionext
+	i := ionext
 	i.Link = iostack
 	iostack = i
 	i.F = f
@@ -175,16 +159,13 @@
 }
 
 func LabelLookup(s *Sym) *Sym {
-	var p string
-	var lab *Sym
-
 	if thetext == nil {
 		s.Labelname = s.Name
 		return s
 	}
 
-	p = string(fmt.Sprintf("%s.%s", thetext.Name, s.Name))
-	lab = Lookup(p)
+	p := string(fmt.Sprintf("%s.%s", thetext.Name, s.Name))
+	lab := Lookup(p)
 
 	lab.Labelname = s.Name
 	return lab
@@ -249,11 +230,10 @@
 }
 
 func Yylex(yylval *Yylval) int {
-	var c int
 	var c1 int
 	var s *Sym
 
-	c = peekc
+	c := peekc
 	if c != IGN {
 		peekc = IGN
 		goto l1
@@ -282,7 +262,48 @@
 		goto aloop
 	}
 	if isdigit(c) {
-		goto tnum
+		yybuf.Reset()
+		if c != '0' {
+			goto dc
+		}
+		yybuf.WriteByte(byte(c))
+		c = GETC()
+		c1 = 3
+		if c == 'x' || c == 'X' {
+			c1 = 4
+			c = GETC()
+		} else if c < '0' || c > '7' {
+			goto dc
+		}
+		yylval.Lval = 0
+		for {
+			if c >= '0' && c <= '9' {
+				if c > '7' && c1 == 3 {
+					break
+				}
+				yylval.Lval = int64(uint64(yylval.Lval) << uint(c1))
+				yylval.Lval += int64(c) - '0'
+				c = GETC()
+				continue
+			}
+
+			if c1 == 3 {
+				break
+			}
+			if c >= 'A' && c <= 'F' {
+				c += 'a' - 'A'
+			}
+			if c >= 'a' && c <= 'f' {
+				yylval.Lval = int64(uint64(yylval.Lval) << uint(c1))
+				yylval.Lval += int64(c) - 'a' + 10
+				c = GETC()
+				continue
+			}
+
+			break
+		}
+
+		goto ncu
 	}
 	switch c {
 	case '\n':
@@ -458,50 +479,6 @@
 	yylval.Sval = last
 	return int(s.Type)
 
-tnum:
-	yybuf.Reset()
-	if c != '0' {
-		goto dc
-	}
-	yybuf.WriteByte(byte(c))
-	c = GETC()
-	c1 = 3
-	if c == 'x' || c == 'X' {
-		c1 = 4
-		c = GETC()
-	} else if c < '0' || c > '7' {
-		goto dc
-	}
-	yylval.Lval = 0
-	for {
-		if c >= '0' && c <= '9' {
-			if c > '7' && c1 == 3 {
-				break
-			}
-			yylval.Lval = int64(uint64(yylval.Lval) << uint(c1))
-			yylval.Lval += int64(c) - '0'
-			c = GETC()
-			continue
-		}
-
-		if c1 == 3 {
-			break
-		}
-		if c >= 'A' && c <= 'F' {
-			c += 'a' - 'A'
-		}
-		if c >= 'a' && c <= 'f' {
-			yylval.Lval = int64(uint64(yylval.Lval) << uint(c1))
-			yylval.Lval += int64(c) - 'a' + 10
-			c = GETC()
-			continue
-		}
-
-		break
-	}
-
-	goto ncu
-
 dc:
 	for {
 		if !(isdigit(c)) {
@@ -529,9 +506,7 @@
 }
 
 func getc() int {
-	var c int
-
-	c = peekc
+	c := peekc
 	if c != IGN {
 		peekc = IGN
 		if c == '\n' {
@@ -571,11 +546,10 @@
 }
 
 func escchar(e int) int {
-	var c int
 	var l int
 
 loop:
-	c = getc()
+	c := getc()
 	if c == '\n' {
 		Yyerror("newline in string")
 		return EOF
@@ -643,11 +617,10 @@
 }
 
 func filbuf() int {
-	var i *Io
 	var n int
 
 loop:
-	i = iostack
+	i := iostack
 	if i == nil {
 		return EOF
 	}
@@ -705,11 +678,10 @@
 }
 
 func GETC() int {
-	var c int
 	if len(fi.P) == 0 {
 		return filbuf()
 	}
-	c = int(fi.P[0])
+	c := int(fi.P[0])
 	fi.P = fi.P[1:]
 	return c
 }
diff --git a/src/cmd/internal/asm/macbody.go b/src/cmd/internal/asm/macbody.go
index 337692a..c488ea1 100644
--- a/src/cmd/internal/asm/macbody.go
+++ b/src/cmd/internal/asm/macbody.go
@@ -43,14 +43,11 @@
 )
 
 func getnsn() int32 {
-	var n int32
-	var c int
-
-	c = getnsc()
+	c := getnsc()
 	if c < '0' || c > '9' {
 		return -1
 	}
-	n = 0
+	n := int32(0)
 	for c >= '0' && c <= '9' {
 		n = n*10 + int32(c) - '0'
 		c = getc()
@@ -61,9 +58,7 @@
 }
 
 func getsym() *Sym {
-	var c int
-
-	c = getnsc()
+	c := getnsc()
 	if !isalpha(c) && c != '_' && c < 0x80 {
 		unget(c)
 		return nil
@@ -84,15 +79,12 @@
 }
 
 func getsymdots(dots *int) *Sym {
-	var c int
-	var s *Sym
-
-	s = getsym()
+	s := getsym()
 	if s != nil {
 		return s
 	}
 
-	c = getnsc()
+	c := getnsc()
 	if c != '.' {
 		unget(c)
 		return nil
@@ -153,10 +145,9 @@
 
 func dodefine(cp string) {
 	var s *Sym
-	var p string
 
 	if i := strings.Index(cp, "="); i >= 0 {
-		p = cp[i+1:]
+		p := cp[i+1:]
 		cp = cp[:i]
 		s = Lookup(cp)
 		s.Macro = &Macro{Text: p}
@@ -186,14 +177,11 @@
 }
 
 func domacro() {
-	var i int
-	var s *Sym
-
-	s = getsym()
+	s := getsym()
 	if s == nil {
 		s = Lookup("endif")
 	}
-	for i = 0; i < len(mactab); i++ {
+	for i := 0; i < len(mactab); i++ {
 		if s.Name == mactab[i].Macname {
 			if mactab[i].Macf != nil {
 				mactab[i].Macf()
@@ -209,9 +197,7 @@
 }
 
 func macund() {
-	var s *Sym
-
-	s = getsym()
+	s := getsym()
 	macend()
 	if s == nil {
 		Yyerror("syntax in #undef")
@@ -226,8 +212,6 @@
 )
 
 func macdef() {
-	var s *Sym
-	var a *Sym
 	var args [NARG]string
 	var n int
 	var i int
@@ -236,7 +220,7 @@
 	var ischr int
 	var base bytes.Buffer
 
-	s = getsym()
+	s := getsym()
 	if s == nil {
 		goto bad
 	}
@@ -251,6 +235,8 @@
 		c = getnsc()
 		if c != ')' {
 			unget(c)
+			var a *Sym
+			var c int
 			for {
 				a = getsymdots(&dots)
 				if a == nil {
@@ -316,7 +302,6 @@
 				ischr = 0
 			}
 		} else {
-
 			if c == '"' || c == '\'' {
 				base.WriteByte(byte(c))
 				ischr = c
@@ -417,20 +402,12 @@
 	if s == nil {
 		Yyerror("syntax in #define")
 	} else {
-
 		Yyerror("syntax in #define: %s", s.Name)
 	}
 	macend()
 }
 
 func macexpand(s *Sym) []byte {
-	var l int
-	var c int
-	var arg []string
-	var out bytes.Buffer
-	var buf bytes.Buffer
-	var cp string
-
 	if s.Macro.Narg == 0 {
 		if debug['m'] != 0 {
 			fmt.Printf("#expand %s %s\n", s.Name, s.Macro.Text)
@@ -441,14 +418,19 @@
 	nargs := s.Macro.Narg - 1
 	dots := s.Macro.Dots
 
-	c = getnsc()
+	c := getnsc()
+	var arg []string
+	var cp string
+	var out bytes.Buffer
 	if c != '(' {
 		goto bad
 	}
 	c = getc()
 	if c != ')' {
 		unget(c)
-		l = 0
+		l := 0
+		var buf bytes.Buffer
+		var c int
 		for {
 			c = getc()
 			if c == '"' {
@@ -595,16 +577,14 @@
 }
 
 func macinc() {
-	var c0 int
 	var c int
-	var i int
 	var buf bytes.Buffer
 	var f *os.File
 	var hp string
 	var str string
 	var symb string
 
-	c0 = getnsc()
+	c0 := getnsc()
 	if c0 != '"' {
 		c = c0
 		if c0 != '<' {
@@ -630,7 +610,7 @@
 		goto bad
 	}
 
-	for i = 0; i < len(include); i++ {
+	for i := 0; i < len(include); i++ {
 		if i == 0 && c0 == '>' {
 			continue
 		}
@@ -663,13 +643,11 @@
 }
 
 func maclin() {
-	var c int
-	var n int32
 	var buf bytes.Buffer
 	var symb string
 
-	n = getnsn()
-	c = getc()
+	n := getnsn()
+	c := getc()
 	if n < 0 {
 		goto bad
 	}
@@ -783,16 +761,43 @@
 }
 
 func macprag() {
-	var s *Sym
-	var c0 int
 	var c int
-	var buf bytes.Buffer
-	var symb string
 
-	s = getsym()
+	s := getsym()
 
 	if s != nil && s.Name == "lib" {
-		goto praglib
+		c0 := getnsc()
+		if c0 != '"' {
+			c = c0
+			if c0 != '<' {
+				goto bad
+			}
+			c0 = '>'
+		}
+
+		var buf bytes.Buffer
+		for {
+			c = getc()
+			if c == c0 {
+				break
+			}
+			if c == '\n' {
+				goto bad
+			}
+			buf.WriteByte(byte(c))
+		}
+		symb := buf.String()
+
+		c = getcom()
+		if c != '\n' {
+			goto bad
+		}
+
+		/*
+		 * put pragma-line in as a funny history
+		 */
+		obj.Linklinehist(Ctxt, int(Lineno), symb, -1)
+		return
 	}
 	if s != nil && s.Name == "pack" {
 		pragpack()
@@ -830,43 +835,9 @@
 	}
 
 	for getnsc() != '\n' {
-
 	}
 	return
 
-praglib:
-	c0 = getnsc()
-	if c0 != '"' {
-		c = c0
-		if c0 != '<' {
-			goto bad
-		}
-		c0 = '>'
-	}
-
-	for {
-		c = getc()
-		if c == c0 {
-			break
-		}
-		if c == '\n' {
-			goto bad
-		}
-		buf.WriteByte(byte(c))
-	}
-	symb = buf.String()
-
-	c = getcom()
-	if c != '\n' {
-		goto bad
-	}
-
-	/*
-	 * put pragma-line in as a funny history
-	 */
-	obj.Linklinehist(Ctxt, int(Lineno), symb, -1)
-	return
-
 bad:
 	unget(c)
 	Yyerror("syntax in #pragma lib")
diff --git a/src/cmd/internal/gc/align.go b/src/cmd/internal/gc/align.go
index a588ca3..9025b1a 100644
--- a/src/cmd/internal/gc/align.go
+++ b/src/cmd/internal/gc/align.go
@@ -151,10 +151,7 @@
 
 	et := int32(t.Etype)
 	switch et {
-	case TFUNC,
-		TCHAN,
-		TMAP,
-		TSTRING:
+	case TFUNC, TCHAN, TMAP, TSTRING:
 		break
 
 		/* simtype == 0 during bootstrap */
@@ -170,25 +167,17 @@
 		Fatal("dowidth: unknown type: %v", Tconv(t, 0))
 
 		/* compiler-specific stuff */
-	case TINT8,
-		TUINT8,
-		TBOOL:
+	case TINT8, TUINT8, TBOOL:
 		// bool is int8
 		w = 1
 
-	case TINT16,
-		TUINT16:
+	case TINT16, TUINT16:
 		w = 2
 
-	case TINT32,
-		TUINT32,
-		TFLOAT32:
+	case TINT32, TUINT32, TFLOAT32:
 		w = 4
 
-	case TINT64,
-		TUINT64,
-		TFLOAT64,
-		TCOMPLEX64:
+	case TINT64, TUINT64, TFLOAT64, TCOMPLEX64:
 		w = 8
 		t.Align = uint8(Widthreg)
 
@@ -450,95 +439,95 @@
 	}
 
 	for i := TINT8; i <= TUINT64; i++ {
-		Isint[i] = 1
+		Isint[i] = true
 	}
-	Isint[TINT] = 1
-	Isint[TUINT] = 1
-	Isint[TUINTPTR] = 1
+	Isint[TINT] = true
+	Isint[TUINT] = true
+	Isint[TUINTPTR] = true
 
-	Isfloat[TFLOAT32] = 1
-	Isfloat[TFLOAT64] = 1
+	Isfloat[TFLOAT32] = true
+	Isfloat[TFLOAT64] = true
 
-	Iscomplex[TCOMPLEX64] = 1
-	Iscomplex[TCOMPLEX128] = 1
+	Iscomplex[TCOMPLEX64] = true
+	Iscomplex[TCOMPLEX128] = true
 
-	Isptr[TPTR32] = 1
-	Isptr[TPTR64] = 1
+	Isptr[TPTR32] = true
+	Isptr[TPTR64] = true
 
-	isforw[TFORW] = 1
+	isforw[TFORW] = true
 
-	Issigned[TINT] = 1
-	Issigned[TINT8] = 1
-	Issigned[TINT16] = 1
-	Issigned[TINT32] = 1
-	Issigned[TINT64] = 1
+	Issigned[TINT] = true
+	Issigned[TINT8] = true
+	Issigned[TINT16] = true
+	Issigned[TINT32] = true
+	Issigned[TINT64] = true
 
 	/*
 	 * initialize okfor
 	 */
 	for i := 0; i < NTYPE; i++ {
-		if Isint[i] != 0 || i == TIDEAL {
-			okforeq[i] = 1
-			okforcmp[i] = 1
-			okforarith[i] = 1
-			okforadd[i] = 1
-			okforand[i] = 1
-			okforconst[i] = 1
-			issimple[i] = 1
+		if Isint[i] || i == TIDEAL {
+			okforeq[i] = true
+			okforcmp[i] = true
+			okforarith[i] = true
+			okforadd[i] = true
+			okforand[i] = true
+			okforconst[i] = true
+			issimple[i] = true
 			Minintval[i] = new(Mpint)
 			Maxintval[i] = new(Mpint)
 		}
 
-		if Isfloat[i] != 0 {
-			okforeq[i] = 1
-			okforcmp[i] = 1
-			okforadd[i] = 1
-			okforarith[i] = 1
-			okforconst[i] = 1
-			issimple[i] = 1
+		if Isfloat[i] {
+			okforeq[i] = true
+			okforcmp[i] = true
+			okforadd[i] = true
+			okforarith[i] = true
+			okforconst[i] = true
+			issimple[i] = true
 			minfltval[i] = new(Mpflt)
 			maxfltval[i] = new(Mpflt)
 		}
 
-		if Iscomplex[i] != 0 {
-			okforeq[i] = 1
-			okforadd[i] = 1
-			okforarith[i] = 1
-			okforconst[i] = 1
-			issimple[i] = 1
+		if Iscomplex[i] {
+			okforeq[i] = true
+			okforadd[i] = true
+			okforarith[i] = true
+			okforconst[i] = true
+			issimple[i] = true
 		}
 	}
 
-	issimple[TBOOL] = 1
+	issimple[TBOOL] = true
 
-	okforadd[TSTRING] = 1
+	okforadd[TSTRING] = true
 
-	okforbool[TBOOL] = 1
+	okforbool[TBOOL] = true
 
-	okforcap[TARRAY] = 1
-	okforcap[TCHAN] = 1
+	okforcap[TARRAY] = true
+	okforcap[TCHAN] = true
 
-	okforconst[TBOOL] = 1
-	okforconst[TSTRING] = 1
+	okforconst[TBOOL] = true
+	okforconst[TSTRING] = true
 
-	okforlen[TARRAY] = 1
-	okforlen[TCHAN] = 1
-	okforlen[TMAP] = 1
-	okforlen[TSTRING] = 1
+	okforlen[TARRAY] = true
+	okforlen[TCHAN] = true
+	okforlen[TMAP] = true
+	okforlen[TSTRING] = true
 
-	okforeq[TPTR32] = 1
-	okforeq[TPTR64] = 1
-	okforeq[TUNSAFEPTR] = 1
-	okforeq[TINTER] = 1
-	okforeq[TCHAN] = 1
-	okforeq[TSTRING] = 1
-	okforeq[TBOOL] = 1
-	okforeq[TMAP] = 1    // nil only; refined in typecheck
-	okforeq[TFUNC] = 1   // nil only; refined in typecheck
-	okforeq[TARRAY] = 1  // nil slice only; refined in typecheck
-	okforeq[TSTRUCT] = 1 // it's complicated; refined in typecheck
+	okforeq[TPTR32] = true
+	okforeq[TPTR64] = true
+	okforeq[TUNSAFEPTR] = true
+	okforeq[TINTER] = true
+	okforeq[TCHAN] = true
+	okforeq[TSTRING] = true
+	okforeq[TBOOL] = true
+	okforeq[TMAP] = true    // nil only; refined in typecheck
+	okforeq[TFUNC] = true   // nil only; refined in typecheck
+	okforeq[TARRAY] = true  // nil slice only; refined in typecheck
+	okforeq[TSTRUCT] = true // it's complicated; refined in typecheck
 
-	okforcmp[TSTRING] = 1
+	okforcmp[TSTRING] = true
 
 	var i int
 	for i = 0; i < len(okfor); i++ {
@@ -580,13 +569,13 @@
 	okfor[OLEN] = okforlen[:]
 
 	// comparison
-	iscmp[OLT] = 1
+	iscmp[OLT] = true
 
-	iscmp[OGT] = 1
-	iscmp[OGE] = 1
-	iscmp[OLE] = 1
-	iscmp[OEQ] = 1
-	iscmp[ONE] = 1
+	iscmp[OGT] = true
+	iscmp[OGE] = true
+	iscmp[OLE] = true
+	iscmp[OEQ] = true
+	iscmp[ONE] = true
 
 	mpatofix(Maxintval[TINT8], "0x7f")
 	mpatofix(Minintval[TINT8], "-0x80")
diff --git a/src/cmd/internal/gc/array.go b/src/cmd/internal/gc/array.go
deleted file mode 100644
index 0408613..0000000
--- a/src/cmd/internal/gc/array.go
+++ /dev/null
@@ -1,9 +0,0 @@
-// Copyright 2013 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
-
-const (
-	DEFAULTCAPACITY = 16
-)
diff --git a/src/cmd/internal/gc/bits.go b/src/cmd/internal/gc/bits.go
deleted file mode 100644
index 6e6ffe9..0000000
--- a/src/cmd/internal/gc/bits.go
+++ /dev/null
@@ -1,159 +0,0 @@
-// Inferno utils/cc/bits.c
-// http://code.google.com/p/inferno-os/source/browse/utils/cc/bits.c
-//
-//	Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
-//	Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
-//	Portions Copyright © 1997-1999 Vita Nuova Limited
-//	Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
-//	Portions Copyright © 2004,2006 Bruce Ellis
-//	Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
-//	Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
-//	Portions Copyright © 2009 The Go Authors.  All rights reserved.
-//
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files (the "Software"), to deal
-// in the Software without restriction, including without limitation the rights
-// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-// copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-// THE SOFTWARE.
-
-package gc
-
-import "fmt"
-
-/*
-Bits
-bor(Bits a, Bits b)
-{
-	Bits c;
-	int i;
-
-	for(i=0; i<BITS; i++)
-		c.b[i] = a.b[i] | b.b[i];
-	return c;
-}
-
-Bits
-band(Bits a, Bits b)
-{
-	Bits c;
-	int i;
-
-	for(i=0; i<BITS; i++)
-		c.b[i] = a.b[i] & b.b[i];
-	return c;
-}
-
-Bits
-bnot(Bits a)
-{
-	Bits c;
-	int i;
-
-	for(i=0; i<BITS; i++)
-		c.b[i] = ~a.b[i];
-	return c;
-}
-*/
-func bany(a *Bits) bool {
-	for i := 0; i < BITS; i++ {
-		if a.b[i] != 0 {
-			return true
-		}
-	}
-	return false
-}
-
-/*
-int
-beq(Bits a, Bits b)
-{
-	int i;
-
-	for(i=0; i<BITS; i++)
-		if(a.b[i] != b.b[i])
-			return 0;
-	return 1;
-}
-*/
-func bnum(a Bits) int {
-	var b uint64
-
-	for i := 0; i < BITS; i++ {
-		b = a.b[i]
-		if b != 0 {
-			return 64*i + Bitno(b)
-		}
-	}
-
-	Fatal("bad in bnum")
-	return 0
-}
-
-func blsh(n uint) Bits {
-	c := zbits
-	c.b[n/64] = 1 << (n % 64)
-	return c
-}
-
-func btest(a *Bits, n uint) bool {
-	return a.b[n/64]&(1<<(n%64)) != 0
-}
-
-func biset(a *Bits, n uint) {
-	a.b[n/64] |= 1 << (n % 64)
-}
-
-func biclr(a *Bits, n uint) {
-	a.b[n/64] &^= (1 << (n % 64))
-}
-
-func Bitno(b uint64) int {
-	for i := 0; i < 64; i++ {
-		if b&(1<<uint(i)) != 0 {
-			return i
-		}
-	}
-	Fatal("bad in bitno")
-	return 0
-}
-
-func Qconv(bits Bits, flag int) string {
-	var fp string
-
-	var i int
-
-	first := 1
-
-	for bany(&bits) {
-		i = bnum(bits)
-		if first != 0 {
-			first = 0
-		} else {
-			fp += " "
-		}
-		if var_[i].node == nil || var_[i].node.Sym == nil {
-			fp += fmt.Sprintf("$%d", i)
-		} else {
-			fp += fmt.Sprintf("%s(%d)", var_[i].node.Sym.Name, i)
-			if var_[i].offset != 0 {
-				fp += fmt.Sprintf("%+d", int64(var_[i].offset))
-			}
-		}
-
-		biclr(&bits, uint(i))
-	}
-
-	return fp
-}
diff --git a/src/cmd/internal/gc/builtin.go b/src/cmd/internal/gc/builtin.go
index a5d27bd..13ee7d7 100644
--- a/src/cmd/internal/gc/builtin.go
+++ b/src/cmd/internal/gc/builtin.go
@@ -50,8 +50,8 @@
 	"func @\"\".typ2Itab (@\"\".typ·2 *byte, @\"\".typ2·3 *byte, @\"\".cache·4 **byte) (@\"\".ret·1 *byte)\n" +
 	"func @\"\".convI2E (@\"\".elem·2 any) (@\"\".ret·1 any)\n" +
 	"func @\"\".convI2I (@\"\".typ·2 *byte, @\"\".elem·3 any) (@\"\".ret·1 any)\n" +
-	"func @\"\".convT2E (@\"\".typ·2 *byte, @\"\".elem·3 *any) (@\"\".ret·1 any)\n" +
-	"func @\"\".convT2I (@\"\".typ·2 *byte, @\"\".typ2·3 *byte, @\"\".cache·4 **byte, @\"\".elem·5 *any) (@\"\".ret·1 any)\n" +
+	"func @\"\".convT2E (@\"\".typ·2 *byte, @\"\".elem·3 *any, @\"\".buf·4 *any) (@\"\".ret·1 any)\n" +
+	"func @\"\".convT2I (@\"\".typ·2 *byte, @\"\".typ2·3 *byte, @\"\".cache·4 **byte, @\"\".elem·5 *any, @\"\".buf·6 *any) (@\"\".ret·1 any)\n" +
 	"func @\"\".assertE2E (@\"\".typ·1 *byte, @\"\".iface·2 any, @\"\".ret·3 *any)\n" +
 	"func @\"\".assertE2E2 (@\"\".typ·2 *byte, @\"\".iface·3 any, @\"\".ret·4 *any) (? bool)\n" +
 	"func @\"\".assertE2I (@\"\".typ·1 *byte, @\"\".iface·2 any, @\"\".ret·3 *any)\n" +
@@ -64,6 +64,7 @@
 	"func @\"\".assertI2I2 (@\"\".typ·2 *byte, @\"\".iface·3 any, @\"\".ret·4 *any) (? bool)\n" +
 	"func @\"\".assertI2T (@\"\".typ·1 *byte, @\"\".iface·2 any, @\"\".ret·3 *any)\n" +
 	"func @\"\".assertI2T2 (@\"\".typ·2 *byte, @\"\".iface·3 any, @\"\".ret·4 *any) (? bool)\n" +
+	"func @\"\".panicdottype (@\"\".have·1 *byte, @\"\".want·2 *byte, @\"\".iface·3 *byte)\n" +
 	"func @\"\".ifaceeq (@\"\".i1·2 any, @\"\".i2·3 any) (@\"\".ret·1 bool)\n" +
 	"func @\"\".efaceeq (@\"\".i1·2 any, @\"\".i2·3 any) (@\"\".ret·1 bool)\n" +
 	"func @\"\".ifacethash (@\"\".i1·2 any) (@\"\".ret·1 uint32)\n" +
@@ -128,7 +129,7 @@
 	"func @\"\".selectgo (@\"\".sel·1 *byte)\n" +
 	"func @\"\".block ()\n" +
 	"func @\"\".makeslice (@\"\".typ·2 *byte, @\"\".nel·3 int64, @\"\".cap·4 int64) (@\"\".ary·1 []any)\n" +
-	"func @\"\".growslice (@\"\".typ·2 *byte, @\"\".old·3 []any, @\"\".n·4 int64) (@\"\".ary·1 []any)\n" +
+	"func @\"\".growslice (@\"\".typ·2 *byte, @\"\".old·3 []any, @\"\".n·4 int) (@\"\".ary·1 []any)\n" +
 	"func @\"\".memmove (@\"\".to·1 *any, @\"\".frm·2 *any, @\"\".length·3 uintptr)\n" +
 	"func @\"\".memclr (@\"\".ptr·1 *byte, @\"\".length·2 uintptr)\n" +
 	"func @\"\".memequal (@\"\".x·2 *any, @\"\".y·3 *any, @\"\".size·4 uintptr) (? bool)\n" +
diff --git a/src/cmd/internal/gc/builtins/runtime.go b/src/cmd/internal/gc/builtin/runtime.go
similarity index 96%
rename from src/cmd/internal/gc/builtins/runtime.go
rename to src/cmd/internal/gc/builtin/runtime.go
index 144d8af..0cf1fb2 100644
--- a/src/cmd/internal/gc/builtins/runtime.go
+++ b/src/cmd/internal/gc/builtin/runtime.go
@@ -63,8 +63,8 @@
 func typ2Itab(typ *byte, typ2 *byte, cache **byte) (ret *byte)
 func convI2E(elem any) (ret any)
 func convI2I(typ *byte, elem any) (ret any)
-func convT2E(typ *byte, elem *any) (ret any)
-func convT2I(typ *byte, typ2 *byte, cache **byte, elem *any) (ret any)
+func convT2E(typ *byte, elem, buf *any) (ret any)
+func convT2I(typ *byte, typ2 *byte, cache **byte, elem, buf *any) (ret any)
 
 // interface type assertions  x.(T)
 func assertE2E(typ *byte, iface any, ret *any)
@@ -79,6 +79,7 @@
 func assertI2I2(typ *byte, iface any, ret *any) bool
 func assertI2T(typ *byte, iface any, ret *any)
 func assertI2T2(typ *byte, iface any, ret *any) bool
+func panicdottype(have, want, iface *byte)
 
 func ifaceeq(i1 any, i2 any) (ret bool)
 func efaceeq(i1 any, i2 any) (ret bool)
@@ -159,7 +160,7 @@
 func block()
 
 func makeslice(typ *byte, nel int64, cap int64) (ary []any)
-func growslice(typ *byte, old []any, n int64) (ary []any)
+func growslice(typ *byte, old []any, n int) (ary []any)
 func memmove(to *any, frm *any, length uintptr)
 func memclr(ptr *byte, length uintptr)
 
diff --git a/src/cmd/internal/gc/builtins/unsafe.go b/src/cmd/internal/gc/builtin/unsafe.go
similarity index 100%
rename from src/cmd/internal/gc/builtins/unsafe.go
rename to src/cmd/internal/gc/builtin/unsafe.go
diff --git a/src/cmd/internal/gc/bv.go b/src/cmd/internal/gc/bv.go
index e7fdd70..2b988e6 100644
--- a/src/cmd/internal/gc/bv.go
+++ b/src/cmd/internal/gc/bv.go
@@ -13,38 +13,57 @@
 	WORDSHIFT = 5
 )
 
+// A Bvec is a bit vector.
+type Bvec struct {
+	n int32    // number of bits in vector
+	b []uint32 // words holding bits
+}
+
 func bvsize(n uint32) uint32 {
 	return ((n + WORDBITS - 1) / WORDBITS) * WORDSIZE
 }
 
-func bvbits(bv *Bvec) int32 {
+func bvbits(bv Bvec) int32 {
 	return bv.n
 }
 
-func bvwords(bv *Bvec) int32 {
+func bvwords(bv Bvec) int32 {
 	return (bv.n + WORDBITS - 1) / WORDBITS
 }
 
-func bvalloc(n int32) *Bvec {
-	return &Bvec{n, make([]uint32, bvsize(uint32(n))/4)}
+func bvalloc(n int32) Bvec {
+	return Bvec{n, make([]uint32, bvsize(uint32(n))/4)}
+}
+
+type bulkBvec struct {
+	words []uint32
+	nbit  int32
+	nword int32
+}
+
+func bvbulkalloc(nbit int32, count int32) bulkBvec {
+	nword := (nbit + WORDBITS - 1) / WORDBITS
+	return bulkBvec{
+		words: make([]uint32, nword*count),
+		nbit:  nbit,
+		nword: nword,
+	}
+}
+
+func (b *bulkBvec) next() Bvec {
+	out := Bvec{b.nbit, b.words[:b.nword]}
+	b.words = b.words[b.nword:]
+	return out
 }
 
 /* difference */
-func bvandnot(dst *Bvec, src1 *Bvec, src2 *Bvec) {
-	var i int32
-	var w int32
-
-	if dst.n != src1.n || dst.n != src2.n {
-		Fatal("bvand: lengths %d, %d, and %d are not equal", dst.n, src1.n, src2.n)
-	}
-	i = 0
-	w = 0
-	for ; i < dst.n; (func() { i += WORDBITS; w++ })() {
-		dst.b[w] = src1.b[w] &^ src2.b[w]
+func bvandnot(dst Bvec, src1 Bvec, src2 Bvec) {
+	for i, x := range src1.b {
+		dst.b[i] = x &^ src2.b[i]
 	}
 }
 
-func bvcmp(bv1 *Bvec, bv2 *Bvec) int {
+func bvcmp(bv1 Bvec, bv2 Bvec) int {
 	if bv1.n != bv2.n {
 		Fatal("bvequal: lengths %d and %d are not equal", bv1.n, bv2.n)
 	}
@@ -56,13 +75,13 @@
 	return 0
 }
 
-func bvcopy(dst *Bvec, src *Bvec) {
+func bvcopy(dst Bvec, src Bvec) {
 	for i, x := range src.b {
 		dst.b[i] = x
 	}
 }
 
-func bvconcat(src1 *Bvec, src2 *Bvec) *Bvec {
+func bvconcat(src1 Bvec, src2 Bvec) Bvec {
 	dst := bvalloc(src1.n + src2.n)
 	for i := int32(0); i < src1.n; i++ {
 		if bvget(src1, i) != 0 {
@@ -77,7 +96,7 @@
 	return dst
 }
 
-func bvget(bv *Bvec, i int32) int {
+func bvget(bv Bvec, i int32) int {
 	if i < 0 || i >= bv.n {
 		Fatal("bvget: index %d is out of bounds with length %d\n", i, bv.n)
 	}
@@ -86,7 +105,7 @@
 
 // bvnext returns the smallest index >= i for which bvget(bv, i) == 1.
 // If there is no such index, bvnext returns -1.
-func bvnext(bv *Bvec, i int32) int {
+func bvnext(bv Bvec, i int32) int {
 	if i >= bv.n {
 		return -1
 	}
@@ -115,7 +134,7 @@
 	return int(i)
 }
 
-func bvisempty(bv *Bvec) bool {
+func bvisempty(bv Bvec) bool {
 	for i := int32(0); i < bv.n; i += WORDBITS {
 		if bv.b[i>>WORDSHIFT] != 0 {
 			return false
@@ -124,55 +143,36 @@
 	return true
 }
 
-func bvnot(bv *Bvec) {
-	var i int32
-	var w int32
-
-	i = 0
-	w = 0
-	for ; i < bv.n; (func() { i += WORDBITS; w++ })() {
+func bvnot(bv Bvec) {
+	i := int32(0)
+	w := int32(0)
+	for ; i < bv.n; i, w = i+WORDBITS, w+1 {
 		bv.b[w] = ^bv.b[w]
 	}
 }
 
 /* union */
-func bvor(dst *Bvec, src1 *Bvec, src2 *Bvec) {
-	var i int32
-	var w int32
-
-	if dst.n != src1.n || dst.n != src2.n {
-		Fatal("bvor: lengths %d, %d, and %d are not equal", dst.n, src1.n, src2.n)
-	}
-	i = 0
-	w = 0
-	for ; i < dst.n; (func() { i += WORDBITS; w++ })() {
-		dst.b[w] = src1.b[w] | src2.b[w]
+func bvor(dst Bvec, src1 Bvec, src2 Bvec) {
+	for i, x := range src1.b {
+		dst.b[i] = x | src2.b[i]
 	}
 }
 
 /* intersection */
-func bvand(dst *Bvec, src1 *Bvec, src2 *Bvec) {
-	var i int32
-	var w int32
-
-	if dst.n != src1.n || dst.n != src2.n {
-		Fatal("bvor: lengths %d, %d, and %d are not equal", dst.n, src1.n, src2.n)
-	}
-	i = 0
-	w = 0
-	for ; i < dst.n; (func() { i += WORDBITS; w++ })() {
-		dst.b[w] = src1.b[w] & src2.b[w]
+func bvand(dst Bvec, src1 Bvec, src2 Bvec) {
+	for i, x := range src1.b {
+		dst.b[i] = x & src2.b[i]
 	}
 }
 
-func bvprint(bv *Bvec) {
+func bvprint(bv Bvec) {
 	fmt.Printf("#*")
 	for i := int32(0); i < bv.n; i++ {
 		fmt.Printf("%d", bvget(bv, i))
 	}
 }
 
-func bvreset(bv *Bvec, i int32) {
+func bvreset(bv Bvec, i int32) {
 	if i < 0 || i >= bv.n {
 		Fatal("bvreset: index %d is out of bounds with length %d\n", i, bv.n)
 	}
@@ -180,13 +180,13 @@
 	bv.b[i/WORDBITS] &= mask
 }
 
-func bvresetall(bv *Bvec) {
+func bvresetall(bv Bvec) {
 	for i := range bv.b {
 		bv.b[i] = 0
 	}
 }
 
-func bvset(bv *Bvec, i int32) {
+func bvset(bv Bvec, i int32) {
 	if i < 0 || i >= bv.n {
 		Fatal("bvset: index %d is out of bounds with length %d\n", i, bv.n)
 	}
diff --git a/src/cmd/internal/gc/cgen.go b/src/cmd/internal/gc/cgen.go
new file mode 100644
index 0000000..b3524c2
--- /dev/null
+++ b/src/cmd/internal/gc/cgen.go
@@ -0,0 +1,2564 @@
+// 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
+
+	case ODOTTYPE:
+		cgen_dottype(n, res, nil)
+		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 {
+					if res != nil && res.Op == OREGISTER { // give up res, which we don't need yet.
+						Regfree(res)
+					}
+
+					// igen will need an addressable node.
+					var tmp2 Node
+					Tempname(&tmp2, nl.Type)
+					Cgen(nl, &tmp2)
+					nl = &tmp2
+
+					if res != nil && res.Op == OREGISTER { // reacquire res
+						Regrealloc(res)
+					}
+				}
+
+				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 OEFACE, ODOTTYPE, OSLICE, OSLICEARR, OSLICESTR, OSLICE3, OSLICE3ARR:
+		var n1 Node
+		Tempname(&n1, n.Type)
+		Cgen(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)
+}
+
+// Igen computes the address &n, stores it in a register r,
+// and rewrites a to refer to *r. The chosen r may be the
+// stack pointer, it may be borrowed from res, or it may
+// be a newly allocated register. The caller must call Regfree(a)
+// to free r when the address is no longer needed.
+// The generated code ensures that &n 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.Func.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.Func.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/closure.go b/src/cmd/internal/gc/closure.go
index 20a0349..a5364fc 100644
--- a/src/cmd/internal/gc/closure.go
+++ b/src/cmd/internal/gc/closure.go
@@ -19,7 +19,7 @@
 	n := Nod(OCLOSURE, nil, nil)
 	n.Ntype = ntype
 	n.Funcdepth = Funcdepth
-	n.Outerfunc = Curfn
+	n.Func.Outerfunc = Curfn
 
 	funchdr(n)
 
@@ -62,7 +62,7 @@
 
 	func_ := Curfn
 	func_.Nbody = body
-	func_.Endlineno = lineno
+	func_.Func.Endlineno = lineno
 	funcbody(func_)
 
 	// closure-specific variables are hanging off the
@@ -70,7 +70,7 @@
 	// unhook them.
 	// make the list of pointers for the closure call.
 	var v *Node
-	for l := func_.Cvars; l != nil; l = l.Next {
+	for l := func_.Func.Cvars; l != nil; l = l.Next {
 		v = l.N
 		v.Closure.Closure = v.Outer
 		v.Outerexpr = oldname(v.Sym)
@@ -82,10 +82,10 @@
 func typecheckclosure(func_ *Node, top int) {
 	var n *Node
 
-	for l := func_.Cvars; l != nil; l = l.Next {
+	for l := func_.Func.Cvars; l != nil; l = l.Next {
 		n = l.N.Closure
-		if n.Captured == 0 {
-			n.Captured = 1
+		if !n.Captured {
+			n.Captured = true
 			if n.Decldepth == 0 {
 				Fatal("typecheckclosure: var %v does not have decldepth assigned", Nconv(n, obj.FmtShort))
 			}
@@ -93,12 +93,12 @@
 			// Ignore assignments to the variable in straightline code
 			// preceding the first capturing by a closure.
 			if n.Decldepth == decldepth {
-				n.Assigned = 0
+				n.Assigned = false
 			}
 		}
 	}
 
-	for l := func_.Dcl; l != nil; l = l.Next {
+	for l := func_.Func.Dcl; l != nil; l = l.Next {
 		if l.N.Op == ONAME && (l.N.Class == PPARAM || l.N.Class == PPARAMOUT) {
 			l.N.Decldepth = 1
 		}
@@ -141,41 +141,40 @@
 	gen := 0
 	outer := ""
 	prefix := ""
-	if n.Outerfunc == nil {
+	if n.Func.Outerfunc == nil {
 		// Global closure.
 		outer = "glob"
 
 		prefix = "func"
 		closurename_closgen++
 		gen = closurename_closgen
-	} else if n.Outerfunc.Op == ODCLFUNC {
+	} else if n.Func.Outerfunc.Op == ODCLFUNC {
 		// The outermost closure inside of a named function.
-		outer = n.Outerfunc.Nname.Sym.Name
+		outer = n.Func.Outerfunc.Nname.Sym.Name
 
 		prefix = "func"
 
 		// Yes, functions can be named _.
 		// Can't use function closgen in such case,
 		// because it would lead to name clashes.
-		if !isblank(n.Outerfunc.Nname) {
-			n.Outerfunc.Closgen++
-			gen = n.Outerfunc.Closgen
+		if !isblank(n.Func.Outerfunc.Nname) {
+			n.Func.Outerfunc.Func.Closgen++
+			gen = n.Func.Outerfunc.Func.Closgen
 		} else {
 			closurename_closgen++
 			gen = closurename_closgen
 		}
-	} else if n.Outerfunc.Op == OCLOSURE {
+	} else if n.Func.Outerfunc.Op == OCLOSURE {
 		// Nested closure, recurse.
-		outer = closurename(n.Outerfunc).Name
+		outer = closurename(n.Func.Outerfunc).Name
 
 		prefix = ""
-		n.Outerfunc.Closgen++
-		gen = n.Outerfunc.Closgen
+		n.Func.Outerfunc.Func.Closgen++
+		gen = n.Func.Outerfunc.Func.Closgen
 	} else {
 		Fatal("closurename called for %v", Nconv(n, obj.FmtShort))
 	}
-	namebuf = fmt.Sprintf("%s.%s%d", outer, prefix, gen)
-	n.Sym = Lookup(namebuf)
+	n.Sym = Lookupf("%s.%s%d", outer, prefix, gen)
 	return n.Sym
 }
 
@@ -192,17 +191,17 @@
 	// create the function
 	xfunc := Nod(ODCLFUNC, nil, nil)
 
-	xfunc.Nname = newname(closurename(func_))
+	xfunc.Nname = newfuncname(closurename(func_))
 	xfunc.Nname.Sym.Flags |= SymExported // disable export
 	xfunc.Nname.Ntype = xtype
 	xfunc.Nname.Defn = xfunc
 	declare(xfunc.Nname, PFUNC)
 	xfunc.Nname.Funcdepth = func_.Funcdepth
 	xfunc.Funcdepth = func_.Funcdepth
-	xfunc.Endlineno = func_.Endlineno
+	xfunc.Func.Endlineno = func_.Func.Endlineno
 
 	xfunc.Nbody = func_.Nbody
-	xfunc.Dcl = concat(func_.Dcl, xfunc.Dcl)
+	xfunc.Func.Dcl = concat(func_.Func.Dcl, xfunc.Func.Dcl)
 	if xfunc.Nbody == nil {
 		Fatal("empty body - won't generate any code")
 	}
@@ -231,8 +230,8 @@
 	lineno = xfunc.Lineno
 
 	func_ := xfunc.Closure
-	func_.Enter = nil
-	for l := func_.Cvars; l != nil; l = l.Next {
+	func_.Func.Enter = nil
+	for l := func_.Func.Cvars; l != nil; l = l.Next {
 		v = l.N
 		if v.Type == nil {
 			// if v->type is nil, it means v looked like it was
@@ -254,27 +253,27 @@
 		v.Outerexpr = nil
 
 		// out parameters will be assigned to implicitly upon return.
-		if outer.Class != PPARAMOUT && v.Closure.Addrtaken == 0 && v.Closure.Assigned == 0 && v.Type.Width <= 128 {
-			v.Byval = 1
+		if outer.Class != PPARAMOUT && !v.Closure.Addrtaken && !v.Closure.Assigned && v.Type.Width <= 128 {
+			v.Byval = true
 		} else {
-			v.Closure.Addrtaken = 1
+			v.Closure.Addrtaken = true
 			outer = Nod(OADDR, outer, nil)
 		}
 
 		if Debug['m'] > 1 {
-			name := (*Sym)(nil)
+			var name *Sym
 			if v.Curfn != nil && v.Curfn.Nname != nil {
 				name = v.Curfn.Nname.Sym
 			}
 			how := "ref"
-			if v.Byval != 0 {
+			if v.Byval {
 				how = "value"
 			}
-			Warnl(int(v.Lineno), "%v capturing by %s: %v (addr=%d assign=%d width=%d)", Sconv(name, 0), how, Sconv(v.Sym, 0), v.Closure.Addrtaken, v.Closure.Assigned, int32(v.Type.Width))
+			Warnl(int(v.Lineno), "%v capturing by %s: %v (addr=%v assign=%v width=%d)", Sconv(name, 0), how, Sconv(v.Sym, 0), v.Closure.Addrtaken, v.Closure.Assigned, int32(v.Type.Width))
 		}
 
 		typecheck(&outer, Erv)
-		func_.Enter = list(func_.Enter, outer)
+		func_.Func.Enter = list(func_.Func.Enter, outer)
 	}
 
 	lineno = int32(lno)
@@ -315,14 +314,14 @@
 		var v *Node
 		var addr *Node
 		var fld *Type
-		for l := func_.Cvars; l != nil; l = l.Next {
+		for l := func_.Func.Cvars; l != nil; l = l.Next {
 			v = l.N
 			if v.Op == OXXX {
 				continue
 			}
 			fld = typ(TFIELD)
 			fld.Funarg = 1
-			if v.Byval != 0 {
+			if v.Byval {
 				// If v is captured by value, we merely downgrade it to PPARAM.
 				v.Class = PPARAM
 
@@ -333,9 +332,7 @@
 				// we introduce function param &v *T
 				// and v remains PPARAMREF with &v heapaddr
 				// (accesses will implicitly deref &v).
-				namebuf = fmt.Sprintf("&%s", v.Sym.Name)
-
-				addr = newname(Lookup(namebuf))
+				addr = newname(Lookupf("&%s", v.Sym.Name))
 				addr.Type = Ptrto(v.Type)
 				addr.Class = PPARAM
 				v.Heapaddr = addr
@@ -346,7 +343,7 @@
 			fld.Sym = fld.Nname.Sym
 
 			// Declare the new param and append it to input arguments.
-			xfunc.Dcl = list(xfunc.Dcl, fld.Nname)
+			xfunc.Func.Dcl = list(xfunc.Func.Dcl, fld.Nname)
 
 			*param = fld
 			param = &fld.Down
@@ -362,12 +359,12 @@
 		// The closure is not called, so it is going to stay as closure.
 		nvar := 0
 
-		body := (*NodeList)(nil)
+		var body *NodeList
 		offset := int64(Widthptr)
 		var addr *Node
 		var v *Node
 		var cv *Node
-		for l := func_.Cvars; l != nil; l = l.Next {
+		for l := func_.Func.Cvars; l != nil; l = l.Next {
 			v = l.N
 			if v.Op == OXXX {
 				continue
@@ -378,35 +375,33 @@
 			cv = Nod(OCLOSUREVAR, nil, nil)
 
 			cv.Type = v.Type
-			if v.Byval == 0 {
+			if !v.Byval {
 				cv.Type = Ptrto(v.Type)
 			}
 			offset = Rnd(offset, int64(cv.Type.Align))
 			cv.Xoffset = offset
 			offset += cv.Type.Width
 
-			if v.Byval != 0 && v.Type.Width <= int64(2*Widthptr) && Thearch.Thechar == '6' {
+			if v.Byval && v.Type.Width <= int64(2*Widthptr) && Thearch.Thechar == '6' {
 				//  If it is a small variable captured by value, downgrade it to PAUTO.
 				// This optimization is currently enabled only for amd64, see:
 				// https://github.com/golang/go/issues/9865
 				v.Class = PAUTO
 
 				v.Ullman = 1
-				xfunc.Dcl = list(xfunc.Dcl, v)
+				xfunc.Func.Dcl = list(xfunc.Func.Dcl, v)
 				body = list(body, Nod(OAS, v, cv))
 			} else {
 				// Declare variable holding addresses taken from closure
 				// and initialize in entry prologue.
-				namebuf = fmt.Sprintf("&%s", v.Sym.Name)
-
-				addr = newname(Lookup(namebuf))
+				addr = newname(Lookupf("&%s", v.Sym.Name))
 				addr.Ntype = Nod(OIND, typenod(v.Type), nil)
 				addr.Class = PAUTO
-				addr.Used = 1
+				addr.Used = true
 				addr.Curfn = xfunc
-				xfunc.Dcl = list(xfunc.Dcl, addr)
+				xfunc.Func.Dcl = list(xfunc.Func.Dcl, addr)
 				v.Heapaddr = addr
-				if v.Byval != 0 {
+				if v.Byval {
 					cv = Nod(OADDR, cv, nil)
 				}
 				body = list(body, Nod(OAS, addr, cv))
@@ -415,8 +410,8 @@
 
 		typechecklist(body, Etop)
 		walkstmtlist(body)
-		xfunc.Enter = body
-		xfunc.Needctxt = nvar > 0
+		xfunc.Func.Enter = body
+		xfunc.Func.Needctxt = nvar > 0
 	}
 
 	lineno = int32(lno)
@@ -424,7 +419,7 @@
 
 func walkclosure(func_ *Node, init **NodeList) *Node {
 	// If no closure vars, don't bother wrapping.
-	if func_.Cvars == nil {
+	if func_.Func.Cvars == nil {
 		return func_.Closure.Nname
 	}
 
@@ -447,13 +442,13 @@
 	typ.List = list1(Nod(ODCLFIELD, newname(Lookup(".F")), typenod(Types[TUINTPTR])))
 	var typ1 *Node
 	var v *Node
-	for l := func_.Cvars; l != nil; l = l.Next {
+	for l := func_.Func.Cvars; l != nil; l = l.Next {
 		v = l.N
 		if v.Op == OXXX {
 			continue
 		}
 		typ1 = typenod(v.Type)
-		if v.Byval == 0 {
+		if !v.Byval {
 			typ1 = Nod(OIND, typ1, nil)
 		}
 		typ.List = list(typ.List, Nod(ODCLFIELD, newname(v.Sym), typ1))
@@ -461,8 +456,8 @@
 
 	clos := Nod(OCOMPLIT, nil, Nod(OIND, typ, nil))
 	clos.Esc = func_.Esc
-	clos.Right.Implicit = 1
-	clos.List = concat(list1(Nod(OCFUNC, func_.Closure.Nname, nil)), func_.Enter)
+	clos.Right.Implicit = true
+	clos.List = concat(list1(Nod(OCFUNC, func_.Closure.Nname, nil)), func_.Func.Enter)
 
 	// Force type conversion from *struct to the func type.
 	clos = Nod(OCONVNOP, clos, nil)
@@ -491,8 +486,7 @@
 
 func typecheckpartialcall(fn *Node, sym *Node) {
 	switch fn.Op {
-	case ODOTINTER,
-		ODOTMETH:
+	case ODOTINTER, ODOTMETH:
 		break
 
 	default:
@@ -519,20 +513,20 @@
 		p = fmt.Sprintf("(%v).(%v)-fm", Tconv(rcvrtype, obj.FmtLeft|obj.FmtShort), Sconv(meth.Sym, obj.FmtLeft))
 	}
 	basetype := rcvrtype
-	if Isptr[rcvrtype.Etype] != 0 {
+	if Isptr[rcvrtype.Etype] {
 		basetype = basetype.Type
 	}
 	if basetype.Etype != TINTER && basetype.Sym == nil {
 		Fatal("missing base type for %v", Tconv(rcvrtype, 0))
 	}
 
-	spkg := (*Pkg)(nil)
+	var spkg *Pkg
 	if basetype.Sym != nil {
 		spkg = basetype.Sym.Pkg
 	}
 	if spkg == nil {
 		if makepartialcall_gopkg == nil {
-			makepartialcall_gopkg = mkpkg(newstrlit("go"))
+			makepartialcall_gopkg = mkpkg("go")
 		}
 		spkg = makepartialcall_gopkg
 	}
@@ -549,24 +543,23 @@
 
 	xtype := Nod(OTFUNC, nil, nil)
 	i := 0
-	l := (*NodeList)(nil)
-	callargs := (*NodeList)(nil)
-	ddd := 0
+	var l *NodeList
+	var callargs *NodeList
+	ddd := false
 	xfunc := Nod(ODCLFUNC, nil, nil)
 	Curfn = xfunc
 	var fld *Node
 	var n *Node
 	for t := getinargx(t0).Type; t != nil; t = t.Down {
-		namebuf = fmt.Sprintf("a%d", i)
+		n = newname(Lookupf("a%d", i))
 		i++
-		n = newname(Lookup(namebuf))
 		n.Class = PPARAM
-		xfunc.Dcl = list(xfunc.Dcl, n)
+		xfunc.Func.Dcl = list(xfunc.Func.Dcl, n)
 		callargs = list(callargs, n)
 		fld = Nod(ODCLFIELD, n, typenod(t.Type))
-		if t.Isddd != 0 {
-			fld.Isddd = 1
-			ddd = 1
+		if t.Isddd {
+			fld.Isddd = true
+			ddd = true
 		}
 
 		l = list(l, fld)
@@ -575,30 +568,28 @@
 	xtype.List = l
 	i = 0
 	l = nil
-	retargs := (*NodeList)(nil)
+	var retargs *NodeList
 	for t := getoutargx(t0).Type; t != nil; t = t.Down {
-		namebuf = fmt.Sprintf("r%d", i)
+		n = newname(Lookupf("r%d", i))
 		i++
-		n = newname(Lookup(namebuf))
 		n.Class = PPARAMOUT
-		xfunc.Dcl = list(xfunc.Dcl, n)
+		xfunc.Func.Dcl = list(xfunc.Func.Dcl, n)
 		retargs = list(retargs, n)
 		l = list(l, Nod(ODCLFIELD, n, typenod(t.Type)))
 	}
 
 	xtype.Rlist = l
 
-	xfunc.Dupok = 1
-	xfunc.Nname = newname(sym)
+	xfunc.Func.Dupok = true
+	xfunc.Nname = newfuncname(sym)
 	xfunc.Nname.Sym.Flags |= SymExported // disable export
 	xfunc.Nname.Ntype = xtype
 	xfunc.Nname.Defn = xfunc
 	declare(xfunc.Nname, PFUNC)
 
 	// Declare and initialize variable holding receiver.
-	body := (*NodeList)(nil)
 
-	xfunc.Needctxt = true
+	xfunc.Func.Needctxt = true
 	cv := Nod(OCLOSUREVAR, nil, nil)
 	cv.Xoffset = int64(Widthptr)
 	cv.Type = rcvrtype
@@ -610,10 +601,11 @@
 	ptr.Class = PAUTO
 	ptr.Addable = 1
 	ptr.Ullman = 1
-	ptr.Used = 1
+	ptr.Used = true
 	ptr.Curfn = xfunc
-	xfunc.Dcl = list(xfunc.Dcl, ptr)
-	if Isptr[rcvrtype.Etype] != 0 || Isinter(rcvrtype) {
+	xfunc.Func.Dcl = list(xfunc.Func.Dcl, ptr)
+	var body *NodeList
+	if Isptr[rcvrtype.Etype] || Isinter(rcvrtype) {
 		ptr.Ntype = typenod(rcvrtype)
 		body = list(body, Nod(OAS, ptr, cv))
 	} else {
@@ -623,7 +615,7 @@
 
 	call := Nod(OCALL, Nod(OXDOT, ptr, meth), nil)
 	call.List = callargs
-	call.Isddd = uint8(ddd)
+	call.Isddd = ddd
 	if t0.Outtuple == 0 {
 		body = list(body, call)
 	} else {
@@ -667,7 +659,7 @@
 
 	clos := Nod(OCOMPLIT, nil, Nod(OIND, typ, nil))
 	clos.Esc = n.Esc
-	clos.Right.Implicit = 1
+	clos.Right.Implicit = true
 	clos.List = list1(Nod(OCFUNC, n.Nname.Nname, nil))
 	clos.List = list(clos.List, n.Left)
 
diff --git a/src/cmd/internal/gc/const.go b/src/cmd/internal/gc/const.go
index 43c8809..6842c84 100644
--- a/src/cmd/internal/gc/const.go
+++ b/src/cmd/internal/gc/const.go
@@ -4,7 +4,10 @@
 
 package gc
 
-import "cmd/internal/obj"
+import (
+	"cmd/internal/obj"
+	"strings"
+)
 
 /*
  * truncate float literal fv to 32-bit or 64-bit precision
@@ -15,7 +18,7 @@
 		return oldv
 	}
 
-	v := Val{}
+	var v Val
 	v.Ctype = CTFLT
 	v.U.Fval = oldv
 	overflow(v, t)
@@ -87,20 +90,19 @@
 
 		// target is invalid type for a constant?  leave alone.
 	case OLITERAL:
-		if okforconst[t.Etype] == 0 && n.Type.Etype != TNIL {
+		if !okforconst[t.Etype] && n.Type.Etype != TNIL {
 			defaultlit(&n, nil)
 			*np = n
 			return
 		}
 
-	case OLSH,
-		ORSH:
+	case OLSH, ORSH:
 		convlit1(&n.Left, t, explicit && isideal(n.Left.Type))
 		t = n.Left.Type
 		if t != nil && t.Etype == TIDEAL && n.Val.Ctype != CTINT {
 			n.Val = toint(n.Val)
 		}
-		if t != nil && Isint[t.Etype] == 0 {
+		if t != nil && !Isint[t.Etype] {
 			Yyerror("invalid operation: %v (shift of type %v)", Nconv(n, 0), Tconv(t, 0))
 			t = nil
 		}
@@ -196,25 +198,19 @@
 			}
 		}
 
-	case CTSTR,
-		CTBOOL:
+	case CTSTR, CTBOOL:
 		if et != int(n.Type.Etype) {
 			goto bad
 		}
 
-	case CTINT,
-		CTRUNE,
-		CTFLT,
-		CTCPLX:
+	case CTINT, CTRUNE, CTFLT, CTCPLX:
 		ct := int(n.Val.Ctype)
-		if Isint[et] != 0 {
+		if Isint[et] {
 			switch ct {
 			default:
 				goto bad
 
-			case CTCPLX,
-				CTFLT,
-				CTRUNE:
+			case CTCPLX, CTFLT, CTRUNE:
 				n.Val = toint(n.Val)
 				fallthrough
 
@@ -222,14 +218,12 @@
 			case CTINT:
 				overflow(n.Val, t)
 			}
-		} else if Isfloat[et] != 0 {
+		} else if Isfloat[et] {
 			switch ct {
 			default:
 				goto bad
 
-			case CTCPLX,
-				CTINT,
-				CTRUNE:
+			case CTCPLX, CTINT, CTRUNE:
 				n.Val = toflt(n.Val)
 				fallthrough
 
@@ -237,14 +231,12 @@
 			case CTFLT:
 				n.Val.U.Fval = truncfltlit(n.Val.U.Fval, t)
 			}
-		} else if Iscomplex[et] != 0 {
+		} else if Iscomplex[et] {
 			switch ct {
 			default:
 				goto bad
 
-			case CTFLT,
-				CTINT,
-				CTRUNE:
+			case CTFLT, CTINT, CTRUNE:
 				n.Val = tocplx(n.Val)
 
 			case CTCPLX:
@@ -278,8 +270,7 @@
 
 func copyval(v Val) Val {
 	switch v.Ctype {
-	case CTINT,
-		CTRUNE:
+	case CTINT, CTRUNE:
 		i := new(Mpint)
 		mpmovefixfix(i, v.U.Xval)
 		v.U.Xval = i
@@ -301,8 +292,7 @@
 
 func tocplx(v Val) Val {
 	switch v.Ctype {
-	case CTINT,
-		CTRUNE:
+	case CTINT, CTRUNE:
 		c := new(Mpcplx)
 		Mpmovefixflt(&c.Real, v.U.Xval)
 		Mpmovecflt(&c.Imag, 0.0)
@@ -322,8 +312,7 @@
 
 func toflt(v Val) Val {
 	switch v.Ctype {
-	case CTINT,
-		CTRUNE:
+	case CTINT, CTRUNE:
 		f := new(Mpflt)
 		Mpmovefixflt(f, v.U.Xval)
 		v.Ctype = CTFLT
@@ -372,9 +361,8 @@
 
 func doesoverflow(v Val, t *Type) bool {
 	switch v.Ctype {
-	case CTINT,
-		CTRUNE:
-		if Isint[t.Etype] == 0 {
+	case CTINT, CTRUNE:
+		if !Isint[t.Etype] {
 			Fatal("overflow: %v integer constant", Tconv(t, 0))
 		}
 		if Mpcmpfixfix(v.U.Xval, Minintval[t.Etype]) < 0 || Mpcmpfixfix(v.U.Xval, Maxintval[t.Etype]) > 0 {
@@ -382,7 +370,7 @@
 		}
 
 	case CTFLT:
-		if Isfloat[t.Etype] == 0 {
+		if !Isfloat[t.Etype] {
 			Fatal("overflow: %v floating-point constant", Tconv(t, 0))
 		}
 		if mpcmpfltflt(v.U.Fval, minfltval[t.Etype]) <= 0 || mpcmpfltflt(v.U.Fval, maxfltval[t.Etype]) >= 0 {
@@ -390,7 +378,7 @@
 		}
 
 	case CTCPLX:
-		if Iscomplex[t.Etype] == 0 {
+		if !Iscomplex[t.Etype] {
 			Fatal("overflow: %v complex constant", Tconv(t, 0))
 		}
 		if mpcmpfltflt(&v.U.Cval.Real, minfltval[t.Etype]) <= 0 || mpcmpfltflt(&v.U.Cval.Real, maxfltval[t.Etype]) >= 0 || mpcmpfltflt(&v.U.Cval.Imag, minfltval[t.Etype]) <= 0 || mpcmpfltflt(&v.U.Cval.Imag, maxfltval[t.Etype]) >= 0 {
@@ -413,8 +401,7 @@
 	}
 
 	switch v.Ctype {
-	case CTINT,
-		CTRUNE:
+	case CTINT, CTRUNE:
 		Yyerror("constant %v overflows %v", Bconv(v.U.Xval, 0), Tconv(t, 0))
 
 	case CTFLT:
@@ -427,16 +414,14 @@
 
 func tostr(v Val) Val {
 	switch v.Ctype {
-	case CTINT,
-		CTRUNE:
+	case CTINT, CTRUNE:
 		if Mpcmpfixfix(v.U.Xval, Minintval[TINT]) < 0 || Mpcmpfixfix(v.U.Xval, Maxintval[TINT]) > 0 {
 			Yyerror("overflow in int -> string")
 		}
-		rune_ := uint(Mpgetfix(v.U.Xval))
-		s := &Strlit{S: string(rune_)}
+		r := uint(Mpgetfix(v.U.Xval))
 		v = Val{}
 		v.Ctype = CTSTR
-		v.U.Sval = s
+		v.U.Sval = string(r)
 
 	case CTFLT:
 		Yyerror("no float -> string")
@@ -445,7 +430,7 @@
 	case CTNIL:
 		v = Val{}
 		v.Ctype = CTSTR
-		v.U.Sval = new(Strlit)
+		v.U.Sval = ""
 	}
 
 	return v
@@ -518,7 +503,7 @@
 		if n.Type == nil {
 			return
 		}
-		if okforconst[n.Type.Etype] == 0 && n.Type.Etype != TNIL {
+		if !okforconst[n.Type.Etype] && n.Type.Etype != TNIL {
 			return
 		}
 
@@ -526,16 +511,15 @@
 	case OADDSTR:
 		var nr *Node
 		var nl *Node
-		var str *Strlit
 		var l2 *NodeList
 		for l1 := n.List; l1 != nil; l1 = l1.Next {
 			if Isconst(l1.N, CTSTR) && l1.Next != nil && Isconst(l1.Next.N, CTSTR) {
 				// merge from l1 up to but not including l2
-				str = new(Strlit)
+				var strs []string
 				l2 = l1
 				for l2 != nil && Isconst(l2.N, CTSTR) {
 					nr = l2.N
-					str.S += nr.Val.U.Sval.S
+					strs = append(strs, nr.Val.U.Sval)
 					l2 = l2.Next
 				}
 
@@ -543,7 +527,7 @@
 				*nl = *l1.N
 				nl.Orig = nl
 				nl.Val.Ctype = CTSTR
-				nl.Val.U.Sval = str
+				nl.Val.U.Sval = strings.Join(strs, "")
 				l1.N = nl
 				l1.Next = l2
 			}
@@ -571,7 +555,7 @@
 		return
 	}
 	wl := int(nl.Type.Etype)
-	if Isint[wl] != 0 || Isfloat[wl] != 0 || Iscomplex[wl] != 0 {
+	if Isint[wl] || Isfloat[wl] || Iscomplex[wl] {
 		wl = TIDEAL
 	}
 
@@ -582,7 +566,96 @@
 	var v Val
 	var norig *Node
 	if nr == nil {
-		goto unary
+		// copy numeric value to avoid modifying
+		// nl, in case someone still refers to it (e.g. iota).
+		v = nl.Val
+
+		if wl == TIDEAL {
+			v = copyval(v)
+		}
+
+		switch uint32(n.Op)<<16 | uint32(v.Ctype) {
+		default:
+			if n.Diag == 0 {
+				Yyerror("illegal constant expression %v %v", Oconv(int(n.Op), 0), Tconv(nl.Type, 0))
+				n.Diag = 1
+			}
+
+			return
+
+		case OCONV<<16 | CTNIL,
+			OARRAYBYTESTR<<16 | CTNIL:
+			if n.Type.Etype == TSTRING {
+				v = tostr(v)
+				nl.Type = n.Type
+				break
+			}
+			fallthrough
+
+			// fall through
+		case OCONV<<16 | CTINT,
+			OCONV<<16 | CTRUNE,
+			OCONV<<16 | CTFLT,
+			OCONV<<16 | CTSTR:
+			convlit1(&nl, n.Type, true)
+
+			v = nl.Val
+
+		case OPLUS<<16 | CTINT,
+			OPLUS<<16 | CTRUNE:
+			break
+
+		case OMINUS<<16 | CTINT,
+			OMINUS<<16 | CTRUNE:
+			mpnegfix(v.U.Xval)
+
+		case OCOM<<16 | CTINT,
+			OCOM<<16 | CTRUNE:
+			et := Txxx
+			if nl.Type != nil {
+				et = int(nl.Type.Etype)
+			}
+
+			// calculate the mask in b
+			// result will be (a ^ mask)
+			var b Mpint
+			switch et {
+			// signed guys change sign
+			default:
+				Mpmovecfix(&b, -1)
+
+				// unsigned guys invert their bits
+			case TUINT8,
+				TUINT16,
+				TUINT32,
+				TUINT64,
+				TUINT,
+				TUINTPTR:
+				mpmovefixfix(&b, Maxintval[et])
+			}
+
+			mpxorfixfix(v.U.Xval, &b)
+
+		case OPLUS<<16 | CTFLT:
+			break
+
+		case OMINUS<<16 | CTFLT:
+			mpnegflt(v.U.Fval)
+
+		case OPLUS<<16 | CTCPLX:
+			break
+
+		case OMINUS<<16 | CTCPLX:
+			mpnegflt(&v.U.Cval.Real)
+			mpnegflt(&v.U.Cval.Imag)
+
+		case ONOT<<16 | CTBOOL:
+			if v.U.Bval == 0 {
+				goto settrue
+			}
+			goto setfalse
+		}
+		goto ret
 	}
 	if nr.Type == nil {
 		return
@@ -591,7 +664,7 @@
 		return
 	}
 	wr = int(nr.Type.Etype)
-	if Isint[wr] != 0 || Isfloat[wr] != 0 || Iscomplex[wr] != 0 {
+	if Isint[wr] || Isfloat[wr] || Iscomplex[wr] {
 		wr = TIDEAL
 	}
 
@@ -620,12 +693,11 @@
 
 		// right must be unsigned.
 	// left can be ideal.
-	case OLSH,
-		ORSH:
+	case OLSH, ORSH:
 		defaultlit(&nr, Types[TUINT])
 
 		n.Right = nr
-		if nr.Type != nil && (Issigned[nr.Type.Etype] != 0 || Isint[nr.Type.Etype] == 0) {
+		if nr.Type != nil && (Issigned[nr.Type.Etype] || !Isint[nr.Type.Etype]) {
 			goto illegal
 		}
 		if nl.Val.Ctype != CTRUNE {
@@ -944,97 +1016,6 @@
 
 	goto ret
 
-	// copy numeric value to avoid modifying
-	// nl, in case someone still refers to it (e.g. iota).
-unary:
-	v = nl.Val
-
-	if wl == TIDEAL {
-		v = copyval(v)
-	}
-
-	switch uint32(n.Op)<<16 | uint32(v.Ctype) {
-	default:
-		if n.Diag == 0 {
-			Yyerror("illegal constant expression %v %v", Oconv(int(n.Op), 0), Tconv(nl.Type, 0))
-			n.Diag = 1
-		}
-
-		return
-
-	case OCONV<<16 | CTNIL,
-		OARRAYBYTESTR<<16 | CTNIL:
-		if n.Type.Etype == TSTRING {
-			v = tostr(v)
-			nl.Type = n.Type
-			break
-		}
-		fallthrough
-
-		// fall through
-	case OCONV<<16 | CTINT,
-		OCONV<<16 | CTRUNE,
-		OCONV<<16 | CTFLT,
-		OCONV<<16 | CTSTR:
-		convlit1(&nl, n.Type, true)
-
-		v = nl.Val
-
-	case OPLUS<<16 | CTINT,
-		OPLUS<<16 | CTRUNE:
-		break
-
-	case OMINUS<<16 | CTINT,
-		OMINUS<<16 | CTRUNE:
-		mpnegfix(v.U.Xval)
-
-	case OCOM<<16 | CTINT,
-		OCOM<<16 | CTRUNE:
-		et := Txxx
-		if nl.Type != nil {
-			et = int(nl.Type.Etype)
-		}
-
-		// calculate the mask in b
-		// result will be (a ^ mask)
-		var b Mpint
-		switch et {
-		// signed guys change sign
-		default:
-			Mpmovecfix(&b, -1)
-
-			// unsigned guys invert their bits
-		case TUINT8,
-			TUINT16,
-			TUINT32,
-			TUINT64,
-			TUINT,
-			TUINTPTR:
-			mpmovefixfix(&b, Maxintval[et])
-		}
-
-		mpxorfixfix(v.U.Xval, &b)
-
-	case OPLUS<<16 | CTFLT:
-		break
-
-	case OMINUS<<16 | CTFLT:
-		mpnegflt(v.U.Fval)
-
-	case OPLUS<<16 | CTCPLX:
-		break
-
-	case OMINUS<<16 | CTCPLX:
-		mpnegflt(&v.U.Cval.Real)
-		mpnegflt(&v.U.Cval.Imag)
-
-	case ONOT<<16 | CTBOOL:
-		if v.U.Bval == 0 {
-			goto settrue
-		}
-		goto setfalse
-	}
-
 ret:
 	norig = saveorig(n)
 	*n = *nl
@@ -1090,10 +1071,7 @@
 	case CTBOOL:
 		n.Type = idealbool
 
-	case CTINT,
-		CTRUNE,
-		CTFLT,
-		CTCPLX:
+	case CTINT, CTRUNE, CTFLT, CTCPLX:
 		n.Type = Types[TIDEAL]
 
 	case CTNIL:
@@ -1159,8 +1137,7 @@
 		}
 		fallthrough
 
-	case OREAL,
-		OIMAG:
+	case OREAL, OIMAG:
 		return CTFLT
 
 	case OCOMPLEX:
@@ -1183,8 +1160,7 @@
 		return CTBOOL
 
 		// shifts (beware!).
-	case OLSH,
-		ORSH:
+	case OLSH, ORSH:
 		return idealkind(n.Left)
 	}
 }
@@ -1263,13 +1239,13 @@
 
 num:
 	if t != nil {
-		if Isint[t.Etype] != 0 {
+		if Isint[t.Etype] {
 			t1 = t
 			n.Val = toint(n.Val)
-		} else if Isfloat[t.Etype] != 0 {
+		} else if Isfloat[t.Etype] {
 			t1 = t
 			n.Val = toflt(n.Val)
-		} else if Iscomplex[t.Etype] != 0 {
+		} else if Iscomplex[t.Etype] {
 			t1 = t
 			n.Val = tocplx(n.Val)
 		}
@@ -1336,7 +1312,7 @@
 }
 
 func cmpslit(l, r *Node) int {
-	return stringsCompare(l.Val.U.Sval.S, r.Val.U.Sval.S)
+	return stringsCompare(l.Val.U.Sval, r.Val.U.Sval)
 }
 
 func Smallintconst(n *Node) bool {
@@ -1352,10 +1328,7 @@
 			TPTR32:
 			return true
 
-		case TIDEAL,
-			TINT64,
-			TUINT64,
-			TPTR64:
+		case TIDEAL, TINT64, TUINT64, TPTR64:
 			if Mpcmpfixfix(n.Val.U.Xval, Minintval[TINT32]) < 0 || Mpcmpfixfix(n.Val.U.Xval, Maxintval[TINT32]) > 0 {
 				break
 			}
@@ -1413,8 +1386,7 @@
 	case TUINT32:
 		x = int64(uint32(x))
 
-	case TINT64,
-		TUINT64:
+	case TINT64, TUINT64:
 		break
 	}
 
@@ -1434,7 +1406,7 @@
 	con.Type = t
 	con.Val = *val
 
-	if Isint[tt] != 0 {
+	if Isint[tt] {
 		con.Val.Ctype = CTINT
 		con.Val.U.Xval = new(Mpint)
 		var i int64
@@ -1442,8 +1414,7 @@
 		default:
 			Fatal("convconst ctype=%d %v", val.Ctype, Tconv(t, obj.FmtLong))
 
-		case CTINT,
-			CTRUNE:
+		case CTINT, CTRUNE:
 			i = Mpgetfix(val.U.Xval)
 
 		case CTBOOL:
@@ -1458,7 +1429,7 @@
 		return
 	}
 
-	if Isfloat[tt] != 0 {
+	if Isfloat[tt] {
 		con.Val = toflt(con.Val)
 		if con.Val.Ctype != CTFLT {
 			Fatal("convconst ctype=%d %v", con.Val.Ctype, Tconv(t, 0))
@@ -1469,7 +1440,7 @@
 		return
 	}
 
-	if Iscomplex[tt] != 0 {
+	if Iscomplex[tt] {
 		con.Val = tocplx(con.Val)
 		if tt == TCOMPLEX64 {
 			con.Val.U.Cval.Real = *truncfltlit(&con.Val.U.Cval.Real, Types[TFLOAT32])
@@ -1603,12 +1574,11 @@
 		}
 
 	case OCONV:
-		if okforconst[n.Type.Etype] != 0 && isgoconst(n.Left) {
+		if okforconst[n.Type.Etype] && isgoconst(n.Left) {
 			return true
 		}
 
-	case OLEN,
-		OCAP:
+	case OLEN, OCAP:
 		l := n.Left
 		if isgoconst(l) {
 			return true
@@ -1619,7 +1589,7 @@
 		// function calls or channel receive operations.
 		t := l.Type
 
-		if t != nil && Isptr[t.Etype] != 0 {
+		if t != nil && Isptr[t.Etype] {
 			t = t.Type
 		}
 		if Isfixedarray(t) && !hascallchan(l) {
diff --git a/src/cmd/internal/gc/cplx.go b/src/cmd/internal/gc/cplx.go
index c07ba34..fe4c38c 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
 	}
 
@@ -54,7 +54,7 @@
 	var n4 Node
 	subnode(&n3, &n4, nr)
 
-	na := Node{}
+	var na Node
 	na.Op = OANDAND
 	var nb Node
 	na.Left = &nb
@@ -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
@@ -107,11 +107,11 @@
 
 // generate code res = -nl
 func minus(nl *Node, res *Node) {
-	ra := Node{}
+	var ra Node
 	ra.Op = OMINUS
 	ra.Left = nl
 	ra.Type = nl.Type
-	Thearch.Cgen(&ra, res)
+	Cgen(&ra, res)
 }
 
 // build and execute tree
@@ -145,19 +145,19 @@
 	subnode(&n3, &n4, nr)
 	subnode(&n5, &n6, res)
 
-	ra := Node{}
+	var ra Node
 	ra.Op = uint8(op)
 	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
@@ -179,25 +179,25 @@
 	Tempname(&tmp, n5.Type)
 
 	// real part -> tmp
-	rm1 := Node{}
+	var rm1 Node
 
 	rm1.Op = OMUL
 	rm1.Left = &n1
 	rm1.Right = &n3
 	rm1.Type = n1.Type
 
-	rm2 := Node{}
+	var rm2 Node
 	rm2.Op = OMUL
 	rm2.Left = &n2
 	rm2.Right = &n4
 	rm2.Type = n2.Type
 
-	ra := Node{}
+	var ra Node
 	ra.Op = OSUB
 	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) {
@@ -233,32 +233,31 @@
 	n.Val.Ctype = CTFLT
 	n.Type = t
 
-	if Isfloat[t.Etype] == 0 {
+	if !Isfloat[t.Etype] {
 		Fatal("nodfconst: bad type %v", Tconv(t, 0))
 	}
 }
 
-/*
- * cplx.c
- */
 func Complexop(n *Node, res *Node) bool {
 	if n != nil && n.Type != nil {
-		if Iscomplex[n.Type.Etype] != 0 {
+		if Iscomplex[n.Type.Etype] {
 			goto maybe
 		}
 	}
 
 	if res != nil && res.Type != nil {
-		if Iscomplex[res.Type.Etype] != 0 {
+		if Iscomplex[res.Type.Etype] {
 			goto maybe
 		}
 	}
 
 	if n.Op == OREAL || n.Op == OIMAG {
-		goto yes
+		//dump("\ncomplex-yes", n);
+		return true
 	}
 
-	goto no
+	//dump("\ncomplex-no", n);
+	return false
 
 maybe:
 	switch n.Op {
@@ -270,23 +269,20 @@
 		OCOMPLEX,
 		OREAL,
 		OIMAG:
-		goto yes
+		//dump("\ncomplex-yes", n);
+		return true
 
 	case ODOT,
 		ODOTPTR,
 		OINDEX,
 		OIND,
 		ONAME:
-		goto yes
+		//dump("\ncomplex-yes", n);
+		return true
 	}
 
 	//dump("\ncomplex-no", n);
-no:
 	return false
-
-	//dump("\ncomplex-yes", n);
-yes:
-	return true
 }
 
 func Complexmove(f *Node, t *Node) {
@@ -326,8 +322,8 @@
 		var n3 Node
 		subnode(&n3, &n4, t)
 
-		Thearch.Cgen(&n1, &n3)
-		Thearch.Cgen(&n2, &n4)
+		Cgen(&n1, &n3)
+		Cgen(&n2, &n4)
 	}
 }
 
@@ -350,14 +346,13 @@
 			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
 		}
 
-	case OREAL,
-		OIMAG:
+	case OREAL, OIMAG:
 		nl := n.Left
 		if nl.Addable == 0 {
 			var tmp Node
@@ -370,11 +365,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
 	}
 
@@ -398,9 +393,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
 	}
 
@@ -423,10 +418,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,
@@ -451,21 +446,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
 	}
 
@@ -479,8 +474,7 @@
 	case OMINUS:
 		complexminus(nl, res)
 
-	case OADD,
-		OSUB:
+	case OADD, OSUB:
 		complexadd(int(n.Op), nl, nr, res)
 
 	case OMUL:
diff --git a/src/cmd/internal/gc/dcl.go b/src/cmd/internal/gc/dcl.go
index ceececd..846ec7d 100644
--- a/src/cmd/internal/gc/dcl.go
+++ b/src/cmd/internal/gc/dcl.go
@@ -132,14 +132,14 @@
 
 func redeclare(s *Sym, where string) {
 	if s.Lastlineno == 0 {
-		var tmp *Strlit
+		var tmp string
 		if s.Origpkg != nil {
 			tmp = s.Origpkg.Path
 		} else {
 			tmp = s.Pkg.Path
 		}
 		pkgstr := tmp
-		Yyerror("%v redeclared %s\n"+"\tprevious declaration during import \"%v\"", Sconv(s, 0), where, Zconv(pkgstr, 0))
+		Yyerror("%v redeclared %s\n"+"\tprevious declaration during import %q", Sconv(s, 0), where, pkgstr)
 	} else {
 		line1 := parserline()
 		line2 := int(s.Lastlineno)
@@ -197,7 +197,7 @@
 			Fatal("automatic outside function")
 		}
 		if Curfn != nil {
-			Curfn.Dcl = list(Curfn.Dcl, n)
+			Curfn.Func.Dcl = list(Curfn.Func.Dcl, n)
 		}
 		if n.Op == OTYPE {
 			declare_typegen++
@@ -247,7 +247,7 @@
  * new_name_list (type | [type] = expr_list)
  */
 func variter(vl *NodeList, t *Node, el *NodeList) *NodeList {
-	init := (*NodeList)(nil)
+	var init *NodeList
 	doexpr := el != nil
 
 	if count(el) == 1 && count(vl) > 1 {
@@ -313,7 +313,6 @@
  * new_name_list [[type] = expr_list]
  */
 func constiter(vl *NodeList, t *Node, cl *NodeList) *NodeList {
-	vv := (*NodeList)(nil)
 	if cl == nil {
 		if t != nil {
 			Yyerror("const declaration cannot have type without expression")
@@ -329,6 +328,7 @@
 
 	var v *Node
 	var c *Node
+	var vv *NodeList
 	for ; vl != nil; vl = vl.Next {
 		if cl == nil {
 			Yyerror("missing value in const declaration")
@@ -373,6 +373,14 @@
 	return n
 }
 
+// newfuncname generates a new name node for a function or method.
+// TODO(rsc): Use an ODCLFUNC node instead. See comment in CL 7360.
+func newfuncname(s *Sym) *Node {
+	n := newname(s)
+	n.Func = new(Func)
+	return n
+}
+
 /*
  * this generates a new name node for a name
  * being declared.
@@ -437,7 +445,7 @@
 			n.Closure = c
 			c.Closure = n
 			c.Xoffset = 0
-			Curfn.Cvars = list(Curfn.Cvars, c)
+			Curfn.Func.Cvars = list(Curfn.Func.Cvars, c)
 		}
 
 		// return ref to closure var, not original
@@ -542,6 +550,7 @@
 		Yyerror("methods must have a unique non-blank name")
 	}
 
+	n.Func = new(Func)
 	dclcontext = PPARAM
 	markdcl()
 	Funcdepth++
@@ -645,10 +654,8 @@
 
 		if n.Left == nil {
 			// Name so that escape analysis can track it. ~r stands for 'result'.
-			namebuf = fmt.Sprintf("~r%d", gen)
+			n.Left = newname(Lookupf("~r%d", gen))
 			gen++
-
-			n.Left = newname(Lookup(namebuf))
 		}
 
 		// TODO: n->left->missing = 1;
@@ -667,9 +674,8 @@
 
 			*nn = *n.Left
 			nn.Orig = nn
-			namebuf = fmt.Sprintf("~b%d", gen)
+			nn.Sym = Lookupf("~b%d", gen)
 			gen++
-			nn.Sym = Lookup(namebuf)
 			n.Left = nn
 		}
 
@@ -763,9 +769,9 @@
  * is being declared to have uncompiled type t.
  * return the ODCLTYPE node to use.
  */
-func typedcl1(n *Node, t *Node, local int) *Node {
+func typedcl1(n *Node, t *Node, local bool) *Node {
 	n.Ntype = t
-	n.Local = uint8(local)
+	n.Local = local
 	return Nod(ODCLTYPE, n, nil)
 }
 
@@ -778,14 +784,14 @@
 		return
 	}
 
-	if t.Sym == nil && Isptr[t.Etype] != 0 {
+	if t.Sym == nil && Isptr[t.Etype] {
 		t = t.Type
 		if t.Etype == TINTER {
 			Yyerror("embedded type cannot be a pointer to interface")
 		}
 	}
 
-	if Isptr[t.Etype] != 0 {
+	if Isptr[t.Etype] {
 		Yyerror("embedded type cannot be a pointer")
 	} else if t.Etype == TFORW && t.Embedlineno == 0 {
 		t.Embedlineno = lineno
@@ -823,7 +829,8 @@
 
 	switch n.Val.Ctype {
 	case CTSTR:
-		f.Note = n.Val.U.Sval
+		f.Note = new(string)
+		*f.Note = n.Val.U.Sval
 
 	default:
 		Yyerror("field annotation must be string")
@@ -1081,7 +1088,7 @@
 	}
 
 	if named != 0 {
-		n := (*Node)(nil)
+		var n *Node
 		var l *NodeList
 		for l = all; l != nil; l = l.Next {
 			n = l.N
@@ -1096,7 +1103,7 @@
 		}
 	}
 
-	nextt := (*Node)(nil)
+	var nextt *Node
 	var t *Node
 	var n *Node
 	for l := all; l != nil; l = l.Next {
@@ -1149,9 +1156,9 @@
 			n.Right.Op = OTARRAY
 			n.Right.Right = n.Right.Left
 			n.Right.Left = nil
-			n.Isddd = 1
+			n.Isddd = true
 			if n.Left != nil {
-				n.Left.Isddd = 1
+				n.Left.Isddd = true
 			}
 		}
 
@@ -1178,7 +1185,7 @@
 		return false
 	}
 	t := rcvr.Type
-	if Isptr[t.Etype] == 0 {
+	if !Isptr[t.Etype] {
 		return false
 	}
 	t = t.Type
@@ -1195,7 +1202,7 @@
 func functype(this *Node, in *NodeList, out *NodeList) *Type {
 	t := typ(TFUNC)
 
-	rcvr := (*NodeList)(nil)
+	var rcvr *NodeList
 	if this != nil {
 		rcvr = list1(this)
 	}
@@ -1241,7 +1248,7 @@
 		goto bad
 	}
 	s = t.Sym
-	if s == nil && Isptr[t.Etype] != 0 {
+	if s == nil && Isptr[t.Etype] {
 		t = t.Type
 		if t == nil {
 			goto bad
@@ -1269,13 +1276,13 @@
 	}
 
 	if (spkg == nil || nsym.Pkg != spkg) && !exportname(nsym.Name) {
-		if t0.Sym == nil && Isptr[t0.Etype] != 0 {
+		if t0.Sym == nil && Isptr[t0.Etype] {
 			p = fmt.Sprintf("(%v).%s.%s%s", Tconv(t0, obj.FmtLeft|obj.FmtShort), nsym.Pkg.Prefix, nsym.Name, suffix)
 		} else {
 			p = fmt.Sprintf("%v.%s.%s%s", Tconv(t0, obj.FmtLeft|obj.FmtShort), nsym.Pkg.Prefix, nsym.Name, suffix)
 		}
 	} else {
-		if t0.Sym == nil && Isptr[t0.Etype] != 0 {
+		if t0.Sym == nil && Isptr[t0.Etype] {
 			p = fmt.Sprintf("(%v).%s%s", Tconv(t0, obj.FmtLeft|obj.FmtShort), nsym.Name, suffix)
 		} else {
 			p = fmt.Sprintf("%v.%s%s", Tconv(t0, obj.FmtLeft|obj.FmtShort), nsym.Name, suffix)
@@ -1284,7 +1291,7 @@
 
 	if spkg == nil {
 		if methodsym_toppkg == nil {
-			methodsym_toppkg = mkpkg(newstrlit("go"))
+			methodsym_toppkg = mkpkg("go")
 		}
 		spkg = methodsym_toppkg
 	}
@@ -1314,7 +1321,7 @@
 	}
 
 	if t.Sym == nil || isblank(n) {
-		return newname(n.Sym)
+		return newfuncname(n.Sym)
 	}
 
 	var p string
@@ -1325,9 +1332,9 @@
 	}
 
 	if exportname(t.Sym.Name) {
-		n = newname(Lookup(p))
+		n = newfuncname(Lookup(p))
 	} else {
-		n = newname(Pkglookup(p, t.Sym.Pkg))
+		n = newfuncname(Pkglookup(p, t.Sym.Pkg))
 	}
 
 	return n
@@ -1358,7 +1365,7 @@
 			return
 		}
 		if t != nil {
-			if Isptr[t.Etype] != 0 {
+			if Isptr[t.Etype] {
 				if t.Sym != nil {
 					Yyerror("invalid receiver type %v (%v is a pointer type)", Tconv(pa, 0), Tconv(t, 0))
 					return
@@ -1375,7 +1382,7 @@
 				return
 			}
 
-			if Isptr[t.Etype] != 0 {
+			if Isptr[t.Etype] {
 				Yyerror("invalid receiver type %v (%v is a pointer type)", Tconv(pa, 0), Tconv(t, 0))
 				return
 			}
@@ -1403,7 +1410,7 @@
 		}
 	}
 
-	if local && pa.Local == 0 {
+	if local && !pa.Local {
 		// defining method on non-local type.
 		Yyerror("cannot define new methods on non-local type %v", Tconv(pa, 0))
 
@@ -1413,7 +1420,7 @@
 	n := Nod(ODCLFIELD, newname(sf), nil)
 	n.Type = t
 
-	d := (*Type)(nil) // last found
+	var d *Type // last found
 	for f := pa.Method; f != nil; f = f.Down {
 		d = f
 		if f.Etype != TFIELD {
@@ -1472,14 +1479,17 @@
 }
 
 func funcsym(s *Sym) *Sym {
-	p := fmt.Sprintf("%s·f", s.Name)
-	s1 := Pkglookup(p, s.Pkg)
+	if s.Fsym != nil {
+		return s.Fsym
+	}
 
+	s1 := Pkglookup(s.Name+"·f", s.Pkg)
 	if s1.Def == nil {
-		s1.Def = newname(s1)
-		s1.Def.Shortname = newname(s)
+		s1.Def = newfuncname(s1)
+		s1.Def.Func.Shortname = newname(s)
 		funcsyms = list(funcsyms, s1.Def)
 	}
+	s.Fsym = s1
 
 	return s1
 }
diff --git a/src/cmd/internal/gc/esc.go b/src/cmd/internal/gc/esc.go
index d1f45b6..bcd3a83 100644
--- a/src/cmd/internal/gc/esc.go
+++ b/src/cmd/internal/gc/esc.go
@@ -206,23 +206,35 @@
 )
 
 type EscState struct {
-	theSink   Node
+	// Fake node that all
+	//   - return values and output variables
+	//   - parameters on imported functions not marked 'safe'
+	//   - assignments to global variables
+	// flow to.
+	theSink Node
+
+	// If an analyzed function is recorded to return
+	// pieces obtained via indirection from a parameter,
+	// and later there is a call f(x) to that function,
+	// we create a link funcParam <- x to record that fact.
+	// The funcParam node is handled specially in escflood.
 	funcParam Node
-	dsts      *NodeList
-	loopdepth int
-	pdepth    int
-	dstcount  int
-	edgecount int
-	noesc     *NodeList
-	recursive bool
+
+	dsts      *NodeList // all dst nodes
+	loopdepth int       // for detecting nested loop scopes
+	pdepth    int       // for debug printing in recursions.
+	dstcount  int       // diagnostic
+	edgecount int       // diagnostic
+	noesc     *NodeList // list of possible non-escaping nodes, for printing
+	recursive bool      // recursive function or group of mutually recursive functions.
 }
 
-var tags [16]*Strlit
+var tags [16]*string
 
-func mktag(mask int) *Strlit {
+// mktag returns the string representation for an escape analysis tag.
+func mktag(mask int) *string {
 	switch mask & EscMask {
-	case EscNone,
-		EscReturn:
+	case EscNone, EscReturn:
 		break
 
 	default:
@@ -235,22 +247,18 @@
 		return tags[mask]
 	}
 
-	buf := fmt.Sprintf("esc:0x%x", mask)
-	s := newstrlit(buf)
+	s := fmt.Sprintf("esc:0x%x", mask)
 	if mask < len(tags) {
-		tags[mask] = s
+		tags[mask] = &s
 	}
-	return s
+	return &s
 }
 
-func parsetag(note *Strlit) int {
-	if note == nil {
+func parsetag(note *string) int {
+	if note == nil || !strings.HasPrefix(*note, "esc:") {
 		return EscUnknown
 	}
-	if !strings.HasPrefix(note.S, "esc:") {
-		return EscUnknown
-	}
-	em := atoi(note.S[4:])
+	em := atoi((*note)[4:])
 	if em == 0 {
 		return EscNone
 	}
@@ -258,7 +266,7 @@
 }
 
 func escAnalyze(all *NodeList, recursive bool) {
-	es := EscState{}
+	var es EscState
 	e := &es
 	e.theSink.Op = ONAME
 	e.theSink.Orig = &e.theSink
@@ -329,7 +337,7 @@
 	savefn := Curfn
 	Curfn = func_
 
-	for ll := Curfn.Dcl; ll != nil; ll = ll.Next {
+	for ll := Curfn.Func.Dcl; ll != nil; ll = ll.Next {
 		if ll.N.Op != ONAME {
 			continue
 		}
@@ -354,7 +362,7 @@
 
 	// in a mutually recursive group we lose track of the return values
 	if e.recursive {
-		for ll := Curfn.Dcl; ll != nil; ll = ll.Next {
+		for ll := Curfn.Func.Dcl; ll != nil; ll = ll.Next {
 			if ll.N.Op == ONAME && ll.N.Class == PPARAMOUT {
 				escflows(e, &e.theSink, ll.N)
 			}
@@ -428,9 +436,6 @@
 }
 
 func esc(e *EscState, n *Node, up *Node) {
-	var ll *NodeList
-	var lr *NodeList
-
 	if n == nil {
 		return
 	}
@@ -449,7 +454,7 @@
 	// must happen before processing of switch body,
 	// so before recursion.
 	if n.Op == OSWITCH && n.Ntest != nil && n.Ntest.Op == OTYPESW {
-		for ll = n.List; ll != nil; ll = ll.Next { // cases
+		for ll := n.List; ll != nil; ll = ll.Next { // cases
 
 			// ll->n->nname is the variable per case
 			if ll.N.Nname != nil {
@@ -514,7 +519,7 @@
 
 	case OSWITCH:
 		if n.Ntest != nil && n.Ntest.Op == OTYPESW {
-			for ll = n.List; ll != nil; ll = ll.Next { // cases
+			for ll := n.List; ll != nil; ll = ll.Next { // cases
 
 				// ntest->right is the argument of the .(type),
 				// ll->n->nname is the variable per case
@@ -532,9 +537,11 @@
 	// This assignment is a no-op for escape analysis,
 	// it does not store any new pointers into b that were not already there.
 	// However, without this special case b will escape, because we assign to OIND/ODOTPTR.
-	case OAS,
-		OASOP:
-		if (n.Left.Op == OIND || n.Left.Op == ODOTPTR) && n.Left.Left.Op == ONAME && (n.Right.Op == OSLICE || n.Right.Op == OSLICE3 || n.Right.Op == OSLICESTR) && (n.Right.Left.Op == OIND || n.Right.Left.Op == ODOTPTR) && n.Right.Left.Left.Op == ONAME && n.Left.Left == n.Right.Left.Left { // dst is ONAME dereference // src is slice operation // slice is applied to ONAME dereference // dst and src reference the same base ONAME
+	case OAS, OASOP:
+		if (n.Left.Op == OIND || n.Left.Op == ODOTPTR) && n.Left.Left.Op == ONAME && // dst is ONAME dereference
+			(n.Right.Op == OSLICE || n.Right.Op == OSLICE3 || n.Right.Op == OSLICESTR) && // src is slice operation
+			(n.Right.Left.Op == OIND || n.Right.Left.Op == ODOTPTR) && n.Right.Left.Left.Op == ONAME && // slice is applied to ONAME dereference
+			n.Left.Left == n.Right.Left.Left { // dst and src reference the same base ONAME
 
 			// Here we also assume that the statement will not contain calls,
 			// that is, that order will move any calls to init.
@@ -563,9 +570,9 @@
 
 	case OAS2: // x,y = a,b
 		if count(n.List) == count(n.Rlist) {
-			ll = n.List
-			lr = n.Rlist
-			for ; ll != nil; (func() { ll = ll.Next; lr = lr.Next })() {
+			ll := n.List
+			lr := n.Rlist
+			for ; ll != nil; ll, lr = ll.Next, lr.Next {
 				escassign(e, ll.N, lr.N)
 			}
 		}
@@ -582,30 +589,28 @@
 		if e.loopdepth == 1 { // top level
 			break
 		}
+		// arguments leak out of scope
+		// TODO: leak to a dummy node instead
 		fallthrough
 
-		// go f(x) - f and x escape
-	// arguments leak out of scope
-	// TODO: leak to a dummy node instead
-	// fallthrough
 	case OPROC:
+		// go f(x) - f and x escape
 		escassign(e, &e.theSink, n.Left.Left)
 
 		escassign(e, &e.theSink, n.Left.Right) // ODDDARG for call
-		for ll = n.Left.List; ll != nil; ll = ll.Next {
+		for ll := n.Left.List; ll != nil; ll = ll.Next {
 			escassign(e, &e.theSink, ll.N)
 		}
 
-	case OCALLMETH,
-		OCALLFUNC,
-		OCALLINTER:
+	case OCALLMETH, OCALLFUNC, OCALLINTER:
 		esccall(e, n, up)
 
 		// esccall already done on n->rlist->n. tie it's escretval to n->list
 	case OAS2FUNC: // x,y = f()
-		lr = n.Rlist.N.Escretval
+		lr := n.Rlist.N.Escretval
 
-		for ll = n.List; lr != nil && ll != nil; (func() { lr = lr.Next; ll = ll.Next })() {
+		var ll *NodeList
+		for ll = n.List; lr != nil && ll != nil; lr, ll = lr.Next, ll.Next {
 			escassign(e, ll.N, lr.N)
 		}
 		if lr != nil || ll != nil {
@@ -613,7 +618,7 @@
 		}
 
 	case ORETURN:
-		ll = n.List
+		ll := n.List
 		if count(n.List) == 1 && Curfn.Type.Outtuple > 1 {
 			// OAS2FUNC in disguise
 			// esccall already done on n->list->n
@@ -621,7 +626,7 @@
 			ll = n.List.N.Escretval
 		}
 
-		for lr = Curfn.Dcl; lr != nil && ll != nil; lr = lr.Next {
+		for lr := Curfn.Func.Dcl; lr != nil && ll != nil; lr = lr.Next {
 			if lr.N.Op != ONAME || lr.N.Class != PPARAMOUT {
 				continue
 			}
@@ -638,15 +643,19 @@
 		escassign(e, &e.theSink, n.Left)
 
 	case OAPPEND:
-		if n.Isddd == 0 {
-			for ll = n.List.Next; ll != nil; ll = ll.Next {
+		if !n.Isddd {
+			for ll := n.List.Next; ll != nil; ll = ll.Next {
 				escassign(e, &e.theSink, ll.N) // lose track of assign to dereference
 			}
 		}
 
-	case OCONV,
-		OCONVNOP,
-		OCONVIFACE:
+	case OCONV, OCONVNOP:
+		escassign(e, n, n.Left)
+
+	case OCONVIFACE:
+		n.Esc = EscNone // until proven otherwise
+		e.noesc = list(e.noesc, n)
+		n.Escloopdepth = e.loopdepth
 		escassign(e, n, n.Left)
 
 	case OARRAYLIT:
@@ -656,19 +665,19 @@
 			n.Escloopdepth = e.loopdepth
 
 			// Values make it to memory, lose track.
-			for ll = n.List; ll != nil; ll = ll.Next {
+			for ll := n.List; ll != nil; ll = ll.Next {
 				escassign(e, &e.theSink, ll.N.Right)
 			}
 		} else {
 			// Link values to array.
-			for ll = n.List; ll != nil; ll = ll.Next {
+			for ll := n.List; ll != nil; ll = ll.Next {
 				escassign(e, n, ll.N.Right)
 			}
 		}
 
 		// Link values to struct.
 	case OSTRUCTLIT:
-		for ll = n.List; ll != nil; ll = ll.Next {
+		for ll := n.List; ll != nil; ll = ll.Next {
 			escassign(e, n, ll.N.Right)
 		}
 
@@ -694,7 +703,7 @@
 		n.Escloopdepth = e.loopdepth
 
 		// Keys and values make it to memory, lose track.
-		for ll = n.List; ll != nil; ll = ll.Next {
+		for ll := n.List; ll != nil; ll = ll.Next {
 			escassign(e, &e.theSink, ll.N.Left)
 			escassign(e, &e.theSink, ll.N.Right)
 		}
@@ -703,13 +712,13 @@
 	case OCLOSURE:
 		var a *Node
 		var v *Node
-		for ll = n.Cvars; ll != nil; ll = ll.Next {
+		for ll := n.Func.Cvars; ll != nil; ll = ll.Next {
 			v = ll.N
 			if v.Op == OXXX { // unnamed out argument; see dcl.c:/^funcargs
 				continue
 			}
 			a = v.Closure
-			if v.Byval == 0 {
+			if !v.Byval {
 				a = Nod(OADDR, a, nil)
 				a.Lineno = v.Lineno
 				a.Escloopdepth = e.loopdepth
@@ -766,8 +775,7 @@
 			// so that writing the address of one result
 			// to another (or the same) result makes the
 			// first result move to the heap.
-			case PPARAM,
-				PPARAMOUT:
+			case PPARAM, PPARAMOUT:
 				n.Escloopdepth = 1
 			}
 		}
@@ -833,8 +841,7 @@
 
 		dst = &e.theSink // lose track of dereference
 
-	case OIND,
-		ODOTPTR:
+	case OIND, ODOTPTR:
 		dst = &e.theSink // lose track of dereference
 
 		// lose track of key and value
@@ -869,14 +876,13 @@
 		ONEW,
 		OCLOSURE,
 		OCALLPART,
-		ORUNESTR:
+		ORUNESTR,
+		OCONVIFACE:
 		escflows(e, dst, src)
 
 		// Flowing multiple returns to a single dst happens when
 	// analyzing "go f(g())": here g() flows to sink (issue 4529).
-	case OCALLMETH,
-		OCALLFUNC,
-		OCALLINTER:
+	case OCALLMETH, OCALLFUNC, OCALLINTER:
 		for ll := src.Escretval; ll != nil; ll = ll.Next {
 			escflows(e, dst, ll.N)
 		}
@@ -891,7 +897,6 @@
 		// Conversions, field access, slice all preserve the input value.
 	// fallthrough
 	case OCONV,
-		OCONVIFACE,
 		OCONVNOP,
 		ODOTMETH,
 		// treat recv.meth as a value with recv in it, only happens in ODEFER and OPROC
@@ -903,14 +908,15 @@
 		OSLICEARR,
 		OSLICE3ARR,
 		OSLICESTR:
+		// Conversions, field access, slice all preserve the input value.
 		escassign(e, dst, src.Left)
 
-		// Append returns first argument.
 	case OAPPEND:
+		// Append returns first argument.
 		escassign(e, dst, src.List.N)
 
-		// Index of array preserves input value.
 	case OINDEX:
+		// Index of array preserves input value.
 		if Isfixedarray(src.Left.Type) {
 			escassign(e, dst, src.Left)
 		}
@@ -941,10 +947,8 @@
 	lineno = int32(lno)
 }
 
-func escassignfromtag(e *EscState, note *Strlit, dsts *NodeList, src *Node) int {
-	var em int
-
-	em = parsetag(note)
+func escassignfromtag(e *EscState, note *string, dsts *NodeList, src *Node) int {
+	em := parsetag(note)
 
 	if em == EscUnknown {
 		escassign(e, &e.theSink, src)
@@ -962,14 +966,14 @@
 	}
 
 	em0 := em
-	for em >>= EscReturnBits; em != 0 && dsts != nil; (func() { em >>= 1; dsts = dsts.Next })() {
+	for em >>= EscReturnBits; em != 0 && dsts != nil; em, dsts = em>>1, dsts.Next {
 		if em&1 != 0 {
 			escassign(e, dsts.N, src)
 		}
 	}
 
 	if em != 0 && dsts == nil {
-		Fatal("corrupt esc tag %v or messed up escretval list\n", Zconv(note, 0))
+		Fatal("corrupt esc tag %q or messed up escretval list\n", note)
 	}
 	return em0
 }
@@ -981,11 +985,9 @@
 // different for methods vs plain functions and for imported vs
 // this-package
 func esccall(e *EscState, n *Node, up *Node) {
-	var ll *NodeList
-	var lr *NodeList
 	var fntype *Type
 
-	fn := (*Node)(nil)
+	var fn *Node
 	switch n.Op {
 	default:
 		Fatal("esccall")
@@ -1006,7 +1008,7 @@
 		fntype = n.Left.Type
 	}
 
-	ll = n.List
+	ll := n.List
 	if n.List != nil && n.List.Next == nil {
 		a := n.List.N
 		if a.Type.Etype == TSTRUCT && a.Type.Funarg != 0 { // f(g()).
@@ -1022,7 +1024,7 @@
 		}
 
 		// set up out list on this call node
-		for lr = fn.Ntype.Rlist; lr != nil; lr = lr.Next {
+		for lr := fn.Ntype.Rlist; lr != nil; lr = lr.Next {
 			n.Escretval = list(n.Escretval, lr.N.Left) // type.rlist ->  dclfield -> ONAME (PPARAMOUT)
 		}
 
@@ -1032,9 +1034,9 @@
 		}
 
 		var src *Node
-		for lr = fn.Ntype.List; ll != nil && lr != nil; (func() { ll = ll.Next; lr = lr.Next })() {
+		for lr := fn.Ntype.List; ll != nil && lr != nil; ll, lr = ll.Next, lr.Next {
 			src = ll.N
-			if lr.N.Isddd != 0 && n.Isddd == 0 {
+			if lr.N.Isddd && !n.Isddd {
 				// Introduce ODDDARG node to represent ... allocation.
 				src = Nod(ODDDARG, nil, nil)
 
@@ -1084,7 +1086,7 @@
 		src.Class = PAUTO
 		src.Curfn = Curfn
 		src.Escloopdepth = e.loopdepth
-		src.Used = 1
+		src.Used = true
 		src.Lineno = n.Lineno
 		n.Escretval = list(n.Escretval, src)
 	}
@@ -1103,7 +1105,7 @@
 	var a *Node
 	for t := getinargx(fntype).Type; ll != nil; ll = ll.Next {
 		src = ll.N
-		if t.Isddd != 0 && n.Isddd == 0 {
+		if t.Isddd && !n.Isddd {
 			// Introduce ODDDARG node to represent ... allocation.
 			src = Nod(ODDDARG, nil, nil)
 
@@ -1193,8 +1195,7 @@
 // escaping to the global scope.
 func escflood(e *EscState, dst *Node) {
 	switch dst.Op {
-	case ONAME,
-		OCLOSURE:
+	case ONAME, OCLOSURE:
 		break
 
 	default:
@@ -1300,8 +1301,7 @@
 			escwalk(e, level, dst, src.Closure)
 		}
 
-	case OPTRLIT,
-		OADDR:
+	case OPTRLIT, OADDR:
 		if leaks {
 			src.Esc = EscHeap
 			addrescapes(src.Left)
@@ -1336,7 +1336,8 @@
 		ONEW,
 		OCLOSURE,
 		OCALLPART,
-		ORUNESTR:
+		ORUNESTR,
+		OCONVIFACE:
 		if leaks {
 			src.Esc = EscHeap
 			if Debug['m'] != 0 {
@@ -1360,9 +1361,7 @@
 		fallthrough
 
 		// fall through
-	case ODOTPTR,
-		OINDEXMAP,
-		OIND:
+	case ODOTPTR, OINDEXMAP, OIND:
 		newlevel := level
 
 		if level > MinLevel {
@@ -1399,7 +1398,7 @@
 	savefn := Curfn
 	Curfn = func_
 
-	for ll := Curfn.Dcl; ll != nil; ll = ll.Next {
+	for ll := Curfn.Func.Dcl; ll != nil; ll = ll.Next {
 		if ll.N.Op != ONAME || ll.N.Class != PPARAM {
 			continue
 		}
diff --git a/src/cmd/internal/gc/export.go b/src/cmd/internal/gc/export.go
index 2467086..f950889 100644
--- a/src/cmd/internal/gc/export.go
+++ b/src/cmd/internal/gc/export.go
@@ -87,7 +87,7 @@
 	if p.Direct == 0 {
 		suffix = " // indirect"
 	}
-	fmt.Fprintf(bout, "\timport %s \"%v\"%s\n", p.Name, Zconv(p.Path, 0), suffix)
+	fmt.Fprintf(bout, "\timport %s %q%s\n", p.Name, p.Path, suffix)
 }
 
 // Look for anything we need for the inline body
@@ -134,7 +134,7 @@
 		t := n.Left.Type
 
 		if t != Types[t.Etype] && t != idealbool && t != idealstring {
-			if Isptr[t.Etype] != 0 {
+			if Isptr[t.Etype] {
 				t = t.Type
 			}
 			if t != nil && t.Sym != nil && t.Sym.Def != nil && !exportedsym(t.Sym) {
@@ -148,7 +148,7 @@
 	case OLITERAL:
 		t := n.Type
 		if t != Types[n.Type.Etype] && t != idealbool && t != idealstring {
-			if Isptr[t.Etype] != 0 {
+			if Isptr[t.Etype] {
 				t = t.Type
 			}
 			if t != nil && t.Sym != nil && t.Sym.Def != nil && !exportedsym(t.Sym) {
@@ -239,7 +239,7 @@
 	dumpexporttype(t)
 
 	if t.Etype == TFUNC && n.Class == PFUNC {
-		if n.Inl != nil {
+		if n.Func != nil && n.Func.Inl != nil {
 			// when lazily typechecking inlined bodies, some re-exported ones may not have been typechecked yet.
 			// currently that can leave unresolved ONONAMEs in import-dot-ed packages in the wrong package
 			if Debug['l'] < 2 {
@@ -247,9 +247,9 @@
 			}
 
 			// NOTE: The space after %#S here is necessary for ld's export data parser.
-			fmt.Fprintf(bout, "\tfunc %v %v { %v }\n", Sconv(s, obj.FmtSharp), Tconv(t, obj.FmtShort|obj.FmtSharp), Hconv(n.Inl, obj.FmtSharp))
+			fmt.Fprintf(bout, "\tfunc %v %v { %v }\n", Sconv(s, obj.FmtSharp), Tconv(t, obj.FmtShort|obj.FmtSharp), Hconv(n.Func.Inl, obj.FmtSharp))
 
-			reexportdeplist(n.Inl)
+			reexportdeplist(n.Func.Inl)
 		} else {
 			fmt.Fprintf(bout, "\tfunc %v %v\n", Sconv(s, obj.FmtSharp), Tconv(t, obj.FmtShort|obj.FmtSharp))
 		}
@@ -315,15 +315,15 @@
 		if f.Nointerface {
 			fmt.Fprintf(bout, "\t//go:nointerface\n")
 		}
-		if f.Type.Nname != nil && f.Type.Nname.Inl != nil { // nname was set by caninl
+		if f.Type.Nname != nil && f.Type.Nname.Func.Inl != nil { // nname was set by caninl
 
 			// when lazily typechecking inlined bodies, some re-exported ones may not have been typechecked yet.
 			// currently that can leave unresolved ONONAMEs in import-dot-ed packages in the wrong package
 			if Debug['l'] < 2 {
 				typecheckinl(f.Type.Nname)
 			}
-			fmt.Fprintf(bout, "\tfunc (%v) %v %v { %v }\n", Tconv(getthisx(f.Type).Type, obj.FmtSharp), Sconv(f.Sym, obj.FmtShort|obj.FmtByte|obj.FmtSharp), Tconv(f.Type, obj.FmtShort|obj.FmtSharp), Hconv(f.Type.Nname.Inl, obj.FmtSharp))
-			reexportdeplist(f.Type.Nname.Inl)
+			fmt.Fprintf(bout, "\tfunc (%v) %v %v { %v }\n", Tconv(getthisx(f.Type).Type, obj.FmtSharp), Sconv(f.Sym, obj.FmtShort|obj.FmtByte|obj.FmtSharp), Tconv(f.Type, obj.FmtShort|obj.FmtSharp), Hconv(f.Type.Nname.Func.Inl, obj.FmtSharp))
+			reexportdeplist(f.Type.Nname.Func.Inl)
 		} else {
 			fmt.Fprintf(bout, "\tfunc (%v) %v %v\n", Tconv(getthisx(f.Type).Type, obj.FmtSharp), Sconv(f.Sym, obj.FmtShort|obj.FmtByte|obj.FmtSharp), Tconv(f.Type, obj.FmtShort|obj.FmtSharp))
 		}
@@ -372,12 +372,9 @@
 	}
 	fmt.Fprintf(bout, "\n")
 
-	var p *Pkg
-	for i := int32(0); i < int32(len(phash)); i++ {
-		for p = phash[i]; p != nil; p = p.Link {
-			if p.Direct != 0 {
-				dumppkg(p)
-			}
+	for _, p := range pkgs {
+		if p.Direct != 0 {
+			dumppkg(p)
 		}
 	}
 
@@ -399,7 +396,7 @@
  */
 func importsym(s *Sym, op int) *Sym {
 	if s.Def != nil && int(s.Def.Op) != op {
-		pkgstr := fmt.Sprintf("during import \"%v\"", Zconv(importpkg.Path, 0))
+		pkgstr := fmt.Sprintf("during import %q", importpkg.Path)
 		redeclare(s, pkgstr)
 	}
 
@@ -432,24 +429,26 @@
 	return s.Def.Type
 }
 
-func importimport(s *Sym, z *Strlit) {
+var numImport = make(map[string]int)
+
+func importimport(s *Sym, path string) {
 	// Informational: record package name
 	// associated with import path, for use in
 	// human-readable messages.
 
-	if isbadimport(z) {
+	if isbadimport(path) {
 		errorexit()
 	}
-	p := mkpkg(z)
+	p := mkpkg(path)
 	if p.Name == "" {
 		p.Name = s.Name
-		Pkglookup(s.Name, nil).Npkg++
+		numImport[s.Name]++
 	} else if p.Name != s.Name {
-		Yyerror("conflicting names %s and %s for package \"%v\"", p.Name, s.Name, Zconv(p.Path, 0))
+		Yyerror("conflicting names %s and %s for package %q", p.Name, s.Name, p.Path)
 	}
 
-	if incannedimport == 0 && myimportpath != "" && z.S == myimportpath {
-		Yyerror("import \"%v\": package depends on \"%v\" (import cycle)", Zconv(importpkg.Path, 0), Zconv(z, 0))
+	if incannedimport == 0 && myimportpath != "" && path == myimportpath {
+		Yyerror("import %q: package depends on %q (import cycle)", importpkg.Path, path)
 		errorexit()
 	}
 }
@@ -488,7 +487,7 @@
 		if Eqtype(t, s.Def.Type) {
 			return
 		}
-		Yyerror("inconsistent definition for var %v during import\n\t%v (in \"%v\")\n\t%v (in \"%v\")", Sconv(s, 0), Tconv(s.Def.Type, 0), Zconv(s.Importdef.Path, 0), Tconv(t, 0), Zconv(importpkg.Path, 0))
+		Yyerror("inconsistent definition for var %v during import\n\t%v (in %q)\n\t%v (in %q)", Sconv(s, 0), Tconv(s.Def.Type, 0), s.Importdef.Path, Tconv(t, 0), importpkg.Path)
 	}
 
 	n := newname(s)
@@ -518,7 +517,7 @@
 		declare(n, PEXTERN)
 		checkwidth(pt)
 	} else if !Eqtype(pt.Orig, t) {
-		Yyerror("inconsistent definition for type %v during import\n\t%v (in \"%v\")\n\t%v (in \"%v\")", Sconv(pt.Sym, 0), Tconv(pt, obj.FmtLong), Zconv(pt.Sym.Importdef.Path, 0), Tconv(t, obj.FmtLong), Zconv(importpkg.Path, 0))
+		Yyerror("inconsistent definition for type %v during import\n\t%v (in %q)\n\t%v (in %q)", Sconv(pt.Sym, 0), Tconv(pt, obj.FmtLong), pt.Sym.Importdef.Path, Tconv(t, obj.FmtLong), importpkg.Path)
 	}
 
 	if Debug['E'] != 0 {
diff --git a/src/cmd/internal/gc/fmt.go b/src/cmd/internal/gc/fmt.go
index 869aaa0..e5b9e56 100644
--- a/src/cmd/internal/gc/fmt.go
+++ b/src/cmd/internal/gc/fmt.go
@@ -5,8 +5,10 @@
 package gc
 
 import (
+	"bytes"
 	"cmd/internal/obj"
 	"fmt"
+	"strconv"
 	"strings"
 	"unicode/utf8"
 )
@@ -45,8 +47,6 @@
 //		Flags: those of %N
 //			','  separate items with ',' instead of ';'
 //
-//	%Z Strlit*	String literals
-//
 //   In mparith1.c:
 //      %B Mpint*	Big integers
 //	%F Mpflt*	Big floats
@@ -193,28 +193,28 @@
 
 // Fmt "%J": Node details.
 func Jconv(n *Node, flag int) string {
-	var fp string
+	var buf bytes.Buffer
 
 	c := flag & obj.FmtShort
 
 	if c == 0 && n.Ullman != 0 {
-		fp += fmt.Sprintf(" u(%d)", n.Ullman)
+		fmt.Fprintf(&buf, " u(%d)", n.Ullman)
 	}
 
 	if c == 0 && n.Addable != 0 {
-		fp += fmt.Sprintf(" a(%d)", n.Addable)
+		fmt.Fprintf(&buf, " a(%d)", n.Addable)
 	}
 
 	if c == 0 && n.Vargen != 0 {
-		fp += fmt.Sprintf(" g(%d)", n.Vargen)
+		fmt.Fprintf(&buf, " g(%d)", n.Vargen)
 	}
 
 	if n.Lineno != 0 {
-		fp += fmt.Sprintf(" l(%d)", n.Lineno)
+		fmt.Fprintf(&buf, " l(%d)", n.Lineno)
 	}
 
 	if c == 0 && n.Xoffset != BADWIDTH {
-		fp += fmt.Sprintf(" x(%d%+d)", n.Xoffset, n.Stkdelta)
+		fmt.Fprintf(&buf, " x(%d%+d)", n.Xoffset, n.Stkdelta)
 	}
 
 	if n.Class != 0 {
@@ -223,18 +223,18 @@
 			s = ",heap"
 		}
 		if int(n.Class&^PHEAP) < len(classnames) {
-			fp += fmt.Sprintf(" class(%s%s)", classnames[n.Class&^PHEAP], s)
+			fmt.Fprintf(&buf, " class(%s%s)", classnames[n.Class&^PHEAP], s)
 		} else {
-			fp += fmt.Sprintf(" class(%d?%s)", n.Class&^PHEAP, s)
+			fmt.Fprintf(&buf, " class(%d?%s)", n.Class&^PHEAP, s)
 		}
 	}
 
 	if n.Colas != 0 {
-		fp += fmt.Sprintf(" colas(%d)", n.Colas)
+		fmt.Fprintf(&buf, " colas(%d)", n.Colas)
 	}
 
 	if n.Funcdepth != 0 {
-		fp += fmt.Sprintf(" f(%d)", n.Funcdepth)
+		fmt.Fprintf(&buf, " f(%d)", n.Funcdepth)
 	}
 
 	switch n.Esc {
@@ -242,59 +242,59 @@
 		break
 
 	case EscHeap:
-		fp += " esc(h)"
+		buf.WriteString(" esc(h)")
 
 	case EscScope:
-		fp += " esc(s)"
+		buf.WriteString(" esc(s)")
 
 	case EscNone:
-		fp += " esc(no)"
+		buf.WriteString(" esc(no)")
 
 	case EscNever:
 		if c == 0 {
-			fp += " esc(N)"
+			buf.WriteString(" esc(N)")
 		}
 
 	default:
-		fp += fmt.Sprintf(" esc(%d)", n.Esc)
+		fmt.Fprintf(&buf, " esc(%d)", n.Esc)
 	}
 
 	if n.Escloopdepth != 0 {
-		fp += fmt.Sprintf(" ld(%d)", n.Escloopdepth)
+		fmt.Fprintf(&buf, " ld(%d)", n.Escloopdepth)
 	}
 
 	if c == 0 && n.Typecheck != 0 {
-		fp += fmt.Sprintf(" tc(%d)", n.Typecheck)
+		fmt.Fprintf(&buf, " tc(%d)", n.Typecheck)
 	}
 
 	if c == 0 && n.Dodata != 0 {
-		fp += fmt.Sprintf(" dd(%d)", n.Dodata)
+		fmt.Fprintf(&buf, " dd(%d)", n.Dodata)
 	}
 
-	if n.Isddd != 0 {
-		fp += fmt.Sprintf(" isddd(%d)", n.Isddd)
+	if n.Isddd {
+		fmt.Fprintf(&buf, " isddd(%v)", n.Isddd)
 	}
 
-	if n.Implicit != 0 {
-		fp += fmt.Sprintf(" implicit(%d)", n.Implicit)
+	if n.Implicit {
+		fmt.Fprintf(&buf, " implicit(%v)", n.Implicit)
 	}
 
 	if n.Embedded != 0 {
-		fp += fmt.Sprintf(" embedded(%d)", n.Embedded)
+		fmt.Fprintf(&buf, " embedded(%d)", n.Embedded)
 	}
 
-	if n.Addrtaken != 0 {
-		fp += " addrtaken"
+	if n.Addrtaken {
+		buf.WriteString(" addrtaken")
 	}
 
-	if n.Assigned != 0 {
-		fp += " assigned"
+	if n.Assigned {
+		buf.WriteString(" assigned")
 	}
 
-	if c == 0 && n.Used != 0 {
-		fp += fmt.Sprintf(" used(%d)", n.Used)
+	if c == 0 && n.Used {
+		fmt.Fprintf(&buf, " used(%v)", n.Used)
 	}
-	return fp
+	return buf.String()
 }
 
 // Fmt "%V": Values
@@ -302,11 +302,9 @@
 	switch v.Ctype {
 	case CTINT:
 		if (flag&obj.FmtSharp != 0 /*untyped*/) || fmtmode == FExp {
-			return fmt.Sprintf("%v", Bconv(v.U.Xval, obj.FmtSharp))
+			return Bconv(v.U.Xval, obj.FmtSharp)
 		}
-		var fp string
-		fp += fmt.Sprintf("%v", Bconv(v.U.Xval, 0))
-		return fp
+		return Bconv(v.U.Xval, 0)
 
 	case CTRUNE:
 		x := Mpgetfix(v.U.Xval)
@@ -319,17 +317,13 @@
 		if 0 <= x && x <= utf8.MaxRune {
 			return fmt.Sprintf("'\\U%08x'", uint64(x))
 		}
-		var fp string
-		fp += fmt.Sprintf("('\\x00' + %v)", Bconv(v.U.Xval, 0))
-		return fp
+		return fmt.Sprintf("('\\x00' + %v)", Bconv(v.U.Xval, 0))
 
 	case CTFLT:
 		if (flag&obj.FmtSharp != 0 /*untyped*/) || fmtmode == FExp {
-			return fmt.Sprintf("%v", Fconv(v.U.Fval, 0))
+			return Fconv(v.U.Fval, 0)
 		}
-		var fp string
-		fp += fmt.Sprintf("%v", Fconv(v.U.Fval, obj.FmtSharp))
-		return fp
+		return Fconv(v.U.Fval, obj.FmtSharp)
 
 	case CTCPLX:
 		if (flag&obj.FmtSharp != 0 /*untyped*/) || fmtmode == FExp {
@@ -339,85 +333,29 @@
 			return fmt.Sprintf("%vi", Fconv(&v.U.Cval.Imag, obj.FmtSharp))
 		}
 		if mpcmpfltc(&v.U.Cval.Imag, 0) == 0 {
-			return fmt.Sprintf("%v", Fconv(&v.U.Cval.Real, obj.FmtSharp))
+			return Fconv(&v.U.Cval.Real, obj.FmtSharp)
 		}
 		if mpcmpfltc(&v.U.Cval.Imag, 0) < 0 {
 			return fmt.Sprintf("(%v%vi)", Fconv(&v.U.Cval.Real, obj.FmtSharp), Fconv(&v.U.Cval.Imag, obj.FmtSharp))
 		}
-		var fp string
-		fp += fmt.Sprintf("(%v+%vi)", Fconv(&v.U.Cval.Real, obj.FmtSharp), Fconv(&v.U.Cval.Imag, obj.FmtSharp))
-		return fp
+		return fmt.Sprintf("(%v+%vi)", Fconv(&v.U.Cval.Real, obj.FmtSharp), Fconv(&v.U.Cval.Imag, obj.FmtSharp))
 
 	case CTSTR:
-		var fp string
-		fp += fmt.Sprintf("\"%v\"", Zconv(v.U.Sval, 0))
-		return fp
+		return strconv.Quote(v.U.Sval)
 
 	case CTBOOL:
 		if v.U.Bval != 0 {
 			return "true"
 		}
-		var fp string
-		fp += "false"
-		return fp
+		return "false"
 
 	case CTNIL:
-		var fp string
-		fp += "nil"
-		return fp
+		return "nil"
 	}
 
 	return fmt.Sprintf("<ctype=%d>", v.Ctype)
 }
 
-// Fmt "%Z": escaped string literals
-func Zconv(sp *Strlit, flag int) string {
-	if sp == nil {
-		return "<nil>"
-	}
-
-	// NOTE: Keep in sync with ../ld/go.c:/^Zconv.
-	s := sp.S
-	var n int
-	var fp string
-	for i := 0; i < len(s); i += n {
-		var r rune
-		r, n = utf8.DecodeRuneInString(s[i:])
-		switch r {
-		case utf8.RuneError:
-			if n == 1 {
-				fp += fmt.Sprintf("\\x%02x", s[i])
-				break
-			}
-			fallthrough
-
-			// fall through
-		default:
-			if r < ' ' {
-				fp += fmt.Sprintf("\\x%02x", r)
-				break
-			}
-
-			fp += string(r)
-
-		case '\t':
-			fp += "\\t"
-
-		case '\n':
-			fp += "\\n"
-
-		case '"',
-			'\\':
-			fp += `\` + string(r)
-
-		case 0xFEFF: // BOM, basically disallowed in source code
-			fp += "\\uFEFF"
-		}
-	}
-
-	return fp
-}
-
 /*
 s%,%,\n%g
 s%\n+%\n%g
@@ -476,32 +414,26 @@
 			}
 
 			// If the name was used by multiple packages, display the full path,
-			if s.Pkg.Name != "" && Pkglookup(s.Pkg.Name, nil).Npkg > 1 {
-				return fmt.Sprintf("\"%v\".%s", Zconv(s.Pkg.Path, 0), s.Name)
+			if s.Pkg.Name != "" && numImport[s.Pkg.Name] > 1 {
+				return fmt.Sprintf("%q.%s", s.Pkg.Path, s.Name)
 			}
-			var fp string
-			fp += fmt.Sprintf("%s.%s", s.Pkg.Name, s.Name)
-			return fp
+			return fmt.Sprintf("%s.%s", s.Pkg.Name, s.Name)
 
 		case FDbg:
-			var fp string
-			fp += fmt.Sprintf("%s.%s", s.Pkg.Name, s.Name)
-			return fp
+			return fmt.Sprintf("%s.%s", s.Pkg.Name, s.Name)
 
 		case FTypeId:
-			if flag&obj.FmtUnsigned != 0 /*untyped*/ {
+			if flag&obj.FmtUnsigned != 0 {
 				return fmt.Sprintf("%s.%s", s.Pkg.Name, s.Name) // dcommontype, typehash
 			}
-			var fp string
-			fp += fmt.Sprintf("%s.%s", s.Pkg.Prefix, s.Name)
-			return fp // (methodsym), typesym, weaksym
+			return fmt.Sprintf("%s.%s", s.Pkg.Prefix, s.Name) // (methodsym), typesym, weaksym
 
 		case FExp:
 			if s.Name != "" && s.Name[0] == '.' {
 				Fatal("exporting synthetic symbol %s", s.Name)
 			}
 			if s.Pkg != builtinpkg {
-				return fmt.Sprintf("@\"%v\".%s", Zconv(s.Pkg.Path, 0), s.Name)
+				return fmt.Sprintf("@%q.%s", s.Pkg.Path, s.Name)
 			}
 		}
 	}
@@ -516,7 +448,7 @@
 
 		// exportname needs to see the name without the prefix too.
 		if (fmtmode == FExp && !exportname(p)) || fmtmode == FDbg {
-			return fmt.Sprintf("@\"%v\".%s", Zconv(s.Pkg.Path, 0), p)
+			return fmt.Sprintf("@%q.%s", s.Pkg.Path, p)
 		}
 
 		return p
@@ -557,7 +489,7 @@
 	if t == bytetype || t == runetype {
 		// in %-T mode collapse rune and byte with their originals.
 		if fmtmode != FTypeId {
-			return fmt.Sprintf("%v", Sconv(t.Sym, obj.FmtShort))
+			return Sconv(t.Sym, obj.FmtShort)
 		}
 		t = Types[t.Etype]
 	}
@@ -574,11 +506,11 @@
 				if t.Vargen != 0 {
 					return fmt.Sprintf("%v·%d", Sconv(t.Sym, obj.FmtShort), t.Vargen)
 				}
-				return fmt.Sprintf("%v", Sconv(t.Sym, obj.FmtShort))
+				return Sconv(t.Sym, obj.FmtShort)
 			}
 
 			if flag&obj.FmtUnsigned != 0 /*untyped*/ {
-				return fmt.Sprintf("%v", Sconv(t.Sym, obj.FmtUnsigned))
+				return Sconv(t.Sym, obj.FmtUnsigned)
 			}
 			fallthrough
 
@@ -589,98 +521,91 @@
 			}
 		}
 
-		return fmt.Sprintf("%v", Sconv(t.Sym, 0))
+		return Sconv(t.Sym, 0)
 	}
 
-	var fp string
 	if int(t.Etype) < len(basicnames) && basicnames[t.Etype] != "" {
+		prefix := ""
 		if fmtmode == FErr && (t == idealbool || t == idealstring) {
-			fp += "untyped "
+			prefix = "untyped "
 		}
-		fp += basicnames[t.Etype]
-		return fp
+		return prefix + basicnames[t.Etype]
 	}
 
 	if fmtmode == FDbg {
-		fp += fmt.Sprintf("%v-", Econv(int(t.Etype), 0))
+		fmtmode = 0
+		str := Econv(int(t.Etype), 0) + "-" + typefmt(t, flag)
+		fmtmode = FDbg
+		return str
 	}
 
 	switch t.Etype {
-	case TPTR32,
-		TPTR64:
+	case TPTR32, TPTR64:
 		if fmtmode == FTypeId && (flag&obj.FmtShort != 0 /*untyped*/) {
-			fp += fmt.Sprintf("*%v", Tconv(t.Type, obj.FmtShort))
-			return fp
+			return fmt.Sprintf("*%v", Tconv(t.Type, obj.FmtShort))
 		}
-		fp += fmt.Sprintf("*%v", Tconv(t.Type, 0))
-		return fp
+		return fmt.Sprintf("*%v", Tconv(t.Type, 0))
 
 	case TARRAY:
 		if t.Bound >= 0 {
-			fp += fmt.Sprintf("[%d]%v", t.Bound, Tconv(t.Type, 0))
-			return fp
+			return fmt.Sprintf("[%d]%v", t.Bound, Tconv(t.Type, 0))
 		}
 		if t.Bound == -100 {
-			fp += fmt.Sprintf("[...]%v", Tconv(t.Type, 0))
-			return fp
+			return fmt.Sprintf("[...]%v", Tconv(t.Type, 0))
 		}
-		fp += fmt.Sprintf("[]%v", Tconv(t.Type, 0))
-		return fp
+		return fmt.Sprintf("[]%v", Tconv(t.Type, 0))
 
 	case TCHAN:
 		switch t.Chan {
 		case Crecv:
-			fp += fmt.Sprintf("<-chan %v", Tconv(t.Type, 0))
-			return fp
+			return fmt.Sprintf("<-chan %v", Tconv(t.Type, 0))
 
 		case Csend:
-			fp += fmt.Sprintf("chan<- %v", Tconv(t.Type, 0))
-			return fp
+			return fmt.Sprintf("chan<- %v", Tconv(t.Type, 0))
 		}
 
 		if t.Type != nil && t.Type.Etype == TCHAN && t.Type.Sym == nil && t.Type.Chan == Crecv {
-			fp += fmt.Sprintf("chan (%v)", Tconv(t.Type, 0))
-			return fp
+			return fmt.Sprintf("chan (%v)", Tconv(t.Type, 0))
 		}
-		fp += fmt.Sprintf("chan %v", Tconv(t.Type, 0))
-		return fp
+		return fmt.Sprintf("chan %v", Tconv(t.Type, 0))
 
 	case TMAP:
-		fp += fmt.Sprintf("map[%v]%v", Tconv(t.Down, 0), Tconv(t.Type, 0))
-		return fp
+		return fmt.Sprintf("map[%v]%v", Tconv(t.Down, 0), Tconv(t.Type, 0))
 
 	case TINTER:
-		fp += "interface {"
+		var buf bytes.Buffer
+		buf.WriteString("interface {")
 		for t1 := t.Type; t1 != nil; t1 = t1.Down {
+			buf.WriteString(" ")
 			if exportname(t1.Sym.Name) {
-				if t1.Down != nil {
-					fp += fmt.Sprintf(" %v%v;", Sconv(t1.Sym, obj.FmtShort), Tconv(t1.Type, obj.FmtShort))
-				} else {
-					fp += fmt.Sprintf(" %v%v ", Sconv(t1.Sym, obj.FmtShort), Tconv(t1.Type, obj.FmtShort))
-				}
+				buf.WriteString(Sconv(t1.Sym, obj.FmtShort))
 			} else {
-				// non-exported method names must be qualified
-				if t1.Down != nil {
-					fp += fmt.Sprintf(" %v%v;", Sconv(t1.Sym, obj.FmtUnsigned), Tconv(t1.Type, obj.FmtShort))
-				} else {
-					fp += fmt.Sprintf(" %v%v ", Sconv(t1.Sym, obj.FmtUnsigned), Tconv(t1.Type, obj.FmtShort))
-				}
+				buf.WriteString(Sconv(t1.Sym, obj.FmtUnsigned))
+			}
+			buf.WriteString(Tconv(t1.Type, obj.FmtShort))
+			if t1.Down != nil {
+				buf.WriteString(";")
 			}
 		}
-
-		fp += "}"
-		return fp
+		if t.Type != nil {
+			buf.WriteString(" ")
+		}
+		buf.WriteString("}")
+		return buf.String()
 
 	case TFUNC:
-		if flag&obj.FmtShort != 0 /*untyped*/ {
-			fp += fmt.Sprintf("%v", Tconv(getinargx(t), 0))
+		var buf bytes.Buffer
+		if flag&obj.FmtShort != 0 {
+			// no leading func
 		} else {
 			if t.Thistuple != 0 {
-				fp += fmt.Sprintf("method%v func%v", Tconv(getthisx(t), 0), Tconv(getinargx(t), 0))
-			} else {
-				fp += fmt.Sprintf("func%v", Tconv(getinargx(t), 0))
+				buf.WriteString("method")
+				buf.WriteString(Tconv(getthisx(t), 0))
+				buf.WriteString(" ")
 			}
+			buf.WriteString("func")
 		}
+		buf.WriteString(Tconv(getinargx(t), 0))
 
 		switch t.Outtuple {
 		case 0:
@@ -688,75 +613,74 @@
 
 		case 1:
 			if fmtmode != FExp {
-				fp += fmt.Sprintf(" %v", Tconv(getoutargx(t).Type.Type, 0)) // struct->field->field's type
+				buf.WriteString(" ")
+				buf.WriteString(Tconv(getoutargx(t).Type.Type, 0)) // struct->field->field's type
 				break
 			}
 			fallthrough
 
 		default:
-			fp += fmt.Sprintf(" %v", Tconv(getoutargx(t), 0))
+			buf.WriteString(" ")
+			buf.WriteString(Tconv(getoutargx(t), 0))
 		}
+		return buf.String()
 
-		return fp
-
-		// Format the bucket struct for map[x]y as map.bucket[x]y.
-	// This avoids a recursive print that generates very long names.
 	case TSTRUCT:
 		if t.Map != nil {
+			// Format the bucket struct for map[x]y as map.bucket[x]y.
+			// This avoids a recursive print that generates very long names.
 			if t.Map.Bucket == t {
-				fp += fmt.Sprintf("map.bucket[%v]%v", Tconv(t.Map.Down, 0), Tconv(t.Map.Type, 0))
-				return fp
+				return fmt.Sprintf("map.bucket[%v]%v", Tconv(t.Map.Down, 0), Tconv(t.Map.Type, 0))
 			}
 
 			if t.Map.Hmap == t {
-				fp += fmt.Sprintf("map.hdr[%v]%v", Tconv(t.Map.Down, 0), Tconv(t.Map.Type, 0))
-				return fp
+				return fmt.Sprintf("map.hdr[%v]%v", Tconv(t.Map.Down, 0), Tconv(t.Map.Type, 0))
 			}
 
 			if t.Map.Hiter == t {
-				fp += fmt.Sprintf("map.iter[%v]%v", Tconv(t.Map.Down, 0), Tconv(t.Map.Type, 0))
-				return fp
+				return fmt.Sprintf("map.iter[%v]%v", Tconv(t.Map.Down, 0), Tconv(t.Map.Type, 0))
 			}
 
 			Yyerror("unknown internal map type")
 		}
 
+		var buf bytes.Buffer
 		if t.Funarg != 0 {
-			fp += "("
+			buf.WriteString("(")
 			if fmtmode == FTypeId || fmtmode == FErr { // no argument names on function signature, and no "noescape"/"nosplit" tags
 				for t1 := t.Type; t1 != nil; t1 = t1.Down {
+					buf.WriteString(Tconv(t1, obj.FmtShort))
 					if t1.Down != nil {
-						fp += fmt.Sprintf("%v, ", Tconv(t1, obj.FmtShort))
-					} else {
-						fp += fmt.Sprintf("%v", Tconv(t1, obj.FmtShort))
+						buf.WriteString(", ")
 					}
 				}
 			} else {
 				for t1 := t.Type; t1 != nil; t1 = t1.Down {
+					buf.WriteString(Tconv(t1, 0))
 					if t1.Down != nil {
-						fp += fmt.Sprintf("%v, ", Tconv(t1, 0))
-					} else {
-						fp += fmt.Sprintf("%v", Tconv(t1, 0))
+						buf.WriteString(", ")
 					}
 				}
 			}
-
-			fp += ")"
+			buf.WriteString(")")
 		} else {
-			fp += "struct {"
+			buf.WriteString("struct {")
 			for t1 := t.Type; t1 != nil; t1 = t1.Down {
+				buf.WriteString(" ")
+				buf.WriteString(Tconv(t1, obj.FmtLong))
 				if t1.Down != nil {
-					fp += fmt.Sprintf(" %v;", Tconv(t1, obj.FmtLong))
-				} else {
-					fp += fmt.Sprintf(" %v ", Tconv(t1, obj.FmtLong))
+					buf.WriteString(";")
 				}
 			}
-			fp += "}"
+			if t.Type != nil {
+				buf.WriteString(" ")
+			}
+			buf.WriteString("}")
 		}
-
-		return fp
+		return buf.String()
 
 	case TFIELD:
+		var name string
 		if flag&obj.FmtShort == 0 /*untyped*/ {
 			s := t.Sym
 
@@ -779,11 +703,11 @@
 
 			if s != nil && t.Embedded == 0 {
 				if t.Funarg != 0 {
-					fp += fmt.Sprintf("%v ", Nconv(t.Nname, 0))
-				} else if flag&obj.FmtLong != 0 /*untyped*/ {
-					fp += fmt.Sprintf("%v ", Sconv(s, obj.FmtShort|obj.FmtByte)) // qualify non-exported names (used on structs, not on funarg)
+					name = Nconv(t.Nname, 0)
+				} else if flag&obj.FmtLong != 0 {
+					name = Sconv(s, obj.FmtShort|obj.FmtByte) // qualify non-exported names (used on structs, not on funarg)
 				} else {
-					fp += fmt.Sprintf("%v ", Sconv(s, 0))
+					name = Sconv(s, 0)
 				}
 			} else if fmtmode == FExp {
 				// TODO(rsc) this breaks on the eliding of unused arguments in the backend
@@ -791,40 +715,41 @@
 				//if(t->funarg)
 				//	fmtstrcpy(fp, "_ ");
 				//else
-				if t.Embedded != 0 && s.Pkg != nil && len(s.Pkg.Path.S) > 0 {
-					fp += fmt.Sprintf("@\"%v\".? ", Zconv(s.Pkg.Path, 0))
+				if t.Embedded != 0 && s.Pkg != nil && len(s.Pkg.Path) > 0 {
+					name = fmt.Sprintf("@%q.?", s.Pkg.Path)
 				} else {
-					fp += "? "
+					name = "?"
 				}
 			}
 		}
 
-		if t.Isddd != 0 {
-			fp += fmt.Sprintf("...%v", Tconv(t.Type.Type, 0))
+		var typ string
+		if t.Isddd {
+			typ = "..." + Tconv(t.Type.Type, 0)
 		} else {
-			fp += fmt.Sprintf("%v", Tconv(t.Type, 0))
+			typ = Tconv(t.Type, 0)
 		}
 
-		if flag&obj.FmtShort == 0 /*untyped*/ && t.Note != nil {
-			fp += fmt.Sprintf(" \"%v\"", Zconv(t.Note, 0))
+		str := typ
+		if name != "" {
+			str = name + " " + typ
 		}
-		return fp
+		if flag&obj.FmtShort == 0 && t.Note != nil {
+			str += " " + strconv.Quote(*t.Note)
+		}
+		return str
 
 	case TFORW:
 		if t.Sym != nil {
-			fp += fmt.Sprintf("undefined %v", Sconv(t.Sym, 0))
-			return fp
+			return fmt.Sprintf("undefined %v", Sconv(t.Sym, 0))
 		}
-		fp += "undefined"
-		return fp
+		return "undefined"
 
 	case TUNSAFEPTR:
 		if fmtmode == FExp {
-			fp += "@\"unsafe\".Pointer"
-			return fp
+			return "@\"unsafe\".Pointer"
 		}
-		fp += "unsafe.Pointer"
-		return fp
+		return "unsafe.Pointer"
 	}
 
 	if fmtmode == FExp {
@@ -832,16 +757,13 @@
 	}
 
 	// Don't know how to handle - fall back to detailed prints.
-	fp += fmt.Sprintf("%v <%v> %v", Econv(int(t.Etype), 0), Sconv(t.Sym, 0), Tconv(t.Type, 0))
-	return fp
+	return fmt.Sprintf("%v <%v> %v", Econv(int(t.Etype), 0), Sconv(t.Sym, 0), Tconv(t.Type, 0))
 }
 
 // Statements which may be rendered with a simplestmt as init.
 func stmtwithinit(op int) bool {
 	switch op {
-	case OIF,
-		OFOR,
-		OSWITCH:
+	case OIF, OFOR, OSWITCH:
 		return true
 	}
 
@@ -877,9 +799,7 @@
 	case ODCL:
 		if fmtmode == FExp {
 			switch n.Left.Class &^ PHEAP {
-			case PPARAM,
-				PPARAMOUT,
-				PAUTO:
+			case PPARAM, PPARAMOUT, PAUTO:
 				f += fmt.Sprintf("var %v %v", Nconv(n.Left, 0), Tconv(n.Left.Type, 0))
 				goto ret
 			}
@@ -891,7 +811,7 @@
 		if n.Left != nil {
 			f += fmt.Sprintf("%v %v", Nconv(n.Left, 0), Nconv(n.Right, 0))
 		} else {
-			f += fmt.Sprintf("%v", Nconv(n.Right, 0))
+			f += Nconv(n.Right, 0)
 		}
 
 		// Don't export "v = <N>" initializing statements, hope they're always
@@ -909,7 +829,7 @@
 		}
 
 	case OASOP:
-		if n.Implicit != 0 {
+		if n.Implicit {
 			if n.Etype == OADD {
 				f += fmt.Sprintf("%v++", Nconv(n.Left, 0))
 			} else {
@@ -928,10 +848,7 @@
 		fallthrough
 
 		// fallthrough
-	case OAS2DOTTYPE,
-		OAS2FUNC,
-		OAS2MAPR,
-		OAS2RECV:
+	case OAS2DOTTYPE, OAS2FUNC, OAS2MAPR, OAS2RECV:
 		f += fmt.Sprintf("%v = %v", Hconv(n.List, obj.FmtComma), Hconv(n.Rlist, obj.FmtComma))
 
 	case ORETURN:
@@ -994,25 +911,23 @@
 
 		f += fmt.Sprintf("for %v = range %v { %v }", Hconv(n.List, obj.FmtComma), Nconv(n.Right, 0), Hconv(n.Nbody, 0))
 
-	case OSELECT,
-		OSWITCH:
+	case OSELECT, OSWITCH:
 		if fmtmode == FErr {
 			f += fmt.Sprintf("%v statement", Oconv(int(n.Op), 0))
 			break
 		}
 
-		f += fmt.Sprintf("%v", Oconv(int(n.Op), obj.FmtSharp))
+		f += Oconv(int(n.Op), obj.FmtSharp)
 		if simpleinit {
 			f += fmt.Sprintf(" %v;", Nconv(n.Ninit.N, 0))
 		}
 		if n.Ntest != nil {
-			f += fmt.Sprintf("%v", Nconv(n.Ntest, 0))
+			f += Nconv(n.Ntest, 0)
 		}
 
 		f += fmt.Sprintf(" { %v }", Hconv(n.List, 0))
 
-	case OCASE,
-		OXCASE:
+	case OCASE, OXCASE:
 		if n.List != nil {
 			f += fmt.Sprintf("case %v: %v", Hconv(n.List, obj.FmtComma), Hconv(n.Nbody, 0))
 		} else {
@@ -1027,7 +942,7 @@
 		if n.Left != nil {
 			f += fmt.Sprintf("%v %v", Oconv(int(n.Op), obj.FmtSharp), Nconv(n.Left, 0))
 		} else {
-			f += fmt.Sprintf("%v", Oconv(int(n.Op), obj.FmtSharp))
+			f += Oconv(int(n.Op), obj.FmtSharp)
 		}
 
 	case OEMPTY:
@@ -1159,7 +1074,7 @@
 }
 
 func exprfmt(n *Node, prec int) string {
-	for n != nil && n.Implicit != 0 && (n.Op == OIND || n.Op == OADDR) {
+	for n != nil && n.Implicit && (n.Op == OIND || n.Op == OADDR) {
 		n = n.Left
 	}
 
@@ -1178,40 +1093,37 @@
 
 	switch n.Op {
 	case OPAREN:
-		var f string
-		f += fmt.Sprintf("(%v)", Nconv(n.Left, 0))
-		return f
+		return fmt.Sprintf("(%v)", Nconv(n.Left, 0))
 
 	case ODDDARG:
-		var f string
-		f += "... argument"
-		return f
+		return "... argument"
 
 	case OREGISTER:
-		var f string
-		f += fmt.Sprintf("%v", obj.Rconv(int(n.Val.U.Reg)))
-		return f
+		return obj.Rconv(int(n.Val.U.Reg))
 
 	case OLITERAL: // this is a bit of a mess
-		if n.Orig != nil && n.Orig != n {
-			return exprfmt(n.Orig, prec)
+		if fmtmode == FErr {
+			if n.Orig != nil && n.Orig != n {
+				return exprfmt(n.Orig, prec)
+			}
+			if n.Sym != nil {
+				return Sconv(n.Sym, 0)
+			}
 		}
-		if fmtmode == FErr && n.Sym != nil {
-			return fmt.Sprintf("%v", Sconv(n.Sym, 0))
+		if n.Val.Ctype == CTNIL && n.Orig != nil && n.Orig != n {
+			return exprfmt(n.Orig, prec)
 		}
 		if n.Type != nil && n.Type != Types[n.Type.Etype] && n.Type != idealbool && n.Type != idealstring {
 			// Need parens when type begins with what might
 			// be misinterpreted as a unary operator: * or <-.
-			if Isptr[n.Type.Etype] != 0 || (n.Type.Etype == TCHAN && n.Type.Chan == Crecv) {
+			if Isptr[n.Type.Etype] || (n.Type.Etype == TCHAN && n.Type.Chan == Crecv) {
 				return fmt.Sprintf("(%v)(%v)", Tconv(n.Type, 0), Vconv(&n.Val, 0))
 			} else {
 				return fmt.Sprintf("%v(%v)", Tconv(n.Type, 0), Vconv(&n.Val, 0))
 			}
 		}
 
-		var f string
-		f += fmt.Sprintf("%v", Vconv(&n.Val, 0))
-		return f
+		return Vconv(&n.Val, 0)
 
 		// Special case: name used as local variable in export.
 	// _ becomes ~b%d internally; print as _ for export
@@ -1227,7 +1139,7 @@
 		// but for export, this should be rendered as (*pkg.T).meth.
 		// These nodes have the special property that they are names with a left OTYPE and a right ONAME.
 		if fmtmode == FExp && n.Left != nil && n.Left.Op == OTYPE && n.Right != nil && n.Right.Op == ONAME {
-			if Isptr[n.Left.Type.Etype] != 0 {
+			if Isptr[n.Left.Type.Etype] {
 				return fmt.Sprintf("(%v).%v", Tconv(n.Left.Type, 0), Sconv(n.Right.Sym, obj.FmtShort|obj.FmtByte))
 			} else {
 				return fmt.Sprintf("%v.%v", Tconv(n.Left.Type, 0), Sconv(n.Right.Sym, obj.FmtShort|obj.FmtByte))
@@ -1236,19 +1148,14 @@
 		fallthrough
 
 		//fallthrough
-	case OPACK,
-		ONONAME:
-		var f string
-		f += fmt.Sprintf("%v", Sconv(n.Sym, 0))
-		return f
+	case OPACK, ONONAME:
+		return Sconv(n.Sym, 0)
 
 	case OTYPE:
 		if n.Type == nil && n.Sym != nil {
-			return fmt.Sprintf("%v", Sconv(n.Sym, 0))
+			return Sconv(n.Sym, 0)
 		}
-		var f string
-		f += fmt.Sprintf("%v", Tconv(n.Type, 0))
-		return f
+		return Tconv(n.Type, 0)
 
 	case OTARRAY:
 		if n.Left != nil {
@@ -1259,21 +1166,15 @@
 		return f // happens before typecheck
 
 	case OTMAP:
-		var f string
-		f += fmt.Sprintf("map[%v]%v", Nconv(n.Left, 0), Nconv(n.Right, 0))
-		return f
+		return fmt.Sprintf("map[%v]%v", Nconv(n.Left, 0), Nconv(n.Right, 0))
 
 	case OTCHAN:
 		switch n.Etype {
 		case Crecv:
-			var f string
-			f += fmt.Sprintf("<-chan %v", Nconv(n.Left, 0))
-			return f
+			return fmt.Sprintf("<-chan %v", Nconv(n.Left, 0))
 
 		case Csend:
-			var f string
-			f += fmt.Sprintf("chan<- %v", Nconv(n.Left, 0))
-			return f
+			return fmt.Sprintf("chan<- %v", Nconv(n.Left, 0))
 
 		default:
 			if n.Left != nil && n.Left.Op == OTCHAN && n.Left.Sym == nil && n.Left.Etype == Crecv {
@@ -1285,19 +1186,13 @@
 		fallthrough
 
 	case OTSTRUCT:
-		var f string
-		f += "<struct>"
-		return f
+		return "<struct>"
 
 	case OTINTER:
-		var f string
-		f += "<inter>"
-		return f
+		return "<inter>"
 
 	case OTFUNC:
-		var f string
-		f += "<func>"
-		return f
+		return "<func>"
 
 	case OCLOSURE:
 		if fmtmode == FErr {
@@ -1306,14 +1201,12 @@
 		if n.Nbody != nil {
 			return fmt.Sprintf("%v { %v }", Tconv(n.Type, 0), Hconv(n.Nbody, 0))
 		}
-		var f string
-		f += fmt.Sprintf("%v { %v }", Tconv(n.Type, 0), Hconv(n.Closure.Nbody, 0))
-		return f
+		return fmt.Sprintf("%v { %v }", Tconv(n.Type, 0), Hconv(n.Closure.Nbody, 0))
 
 	case OCOMPLIT:
-		ptrlit := n.Right != nil && n.Right.Implicit != 0 && n.Right.Type != nil && Isptr[n.Right.Type.Etype] != 0
+		ptrlit := n.Right != nil && n.Right.Implicit && n.Right.Type != nil && Isptr[n.Right.Type.Etype]
 		if fmtmode == FErr {
-			if n.Right != nil && n.Right.Type != nil && n.Implicit == 0 {
+			if n.Right != nil && n.Right.Type != nil && !n.Implicit {
 				if ptrlit {
 					return fmt.Sprintf("&%v literal", Tconv(n.Right.Type.Type, 0))
 				} else {
@@ -1329,22 +1222,18 @@
 			return fmt.Sprintf("(&%v{ %v })", Tconv(n.Right.Type.Type, 0), Hconv(n.List, obj.FmtComma))
 		}
 
-		var f string
-		f += fmt.Sprintf("(%v{ %v })", Nconv(n.Right, 0), Hconv(n.List, obj.FmtComma))
-		return f
+		return fmt.Sprintf("(%v{ %v })", Nconv(n.Right, 0), Hconv(n.List, obj.FmtComma))
 
 	case OPTRLIT:
-		if fmtmode == FExp && n.Left.Implicit != 0 {
-			return fmt.Sprintf("%v", Nconv(n.Left, 0))
+		if fmtmode == FExp && n.Left.Implicit {
+			return Nconv(n.Left, 0)
 		}
-		var f string
-		f += fmt.Sprintf("&%v", Nconv(n.Left, 0))
-		return f
+		return fmt.Sprintf("&%v", Nconv(n.Left, 0))
 
 	case OSTRUCTLIT:
 		if fmtmode == FExp { // requires special handling of field names
 			var f string
-			if n.Implicit != 0 {
+			if n.Implicit {
 				f += "{"
 			} else {
 				f += fmt.Sprintf("(%v{", Tconv(n.Type, 0))
@@ -1359,7 +1248,7 @@
 				}
 			}
 
-			if n.Implicit == 0 {
+			if !n.Implicit {
 				f += "})"
 				return f
 			}
@@ -1370,17 +1259,14 @@
 
 		// fallthrough
 
-	case OARRAYLIT,
-		OMAPLIT:
+	case OARRAYLIT, OMAPLIT:
 		if fmtmode == FErr {
 			return fmt.Sprintf("%v literal", Tconv(n.Type, 0))
 		}
-		if fmtmode == FExp && n.Implicit != 0 {
+		if fmtmode == FExp && n.Implicit {
 			return fmt.Sprintf("{ %v }", Hconv(n.List, obj.FmtComma))
 		}
-		var f string
-		f += fmt.Sprintf("(%v{ %v })", Tconv(n.Type, 0), Hconv(n.List, obj.FmtComma))
-		return f
+		return fmt.Sprintf("(%v{ %v })", Tconv(n.Type, 0), Hconv(n.List, obj.FmtComma))
 
 	case OKEY:
 		if n.Left != nil && n.Right != nil {
@@ -1398,9 +1284,7 @@
 		if n.Left != nil && n.Right == nil {
 			return fmt.Sprintf("%v:", Nconv(n.Left, 0))
 		}
-		var f string
-		f += ":"
-		return f
+		return ":"
 
 	case OXDOT,
 		ODOT,
@@ -1417,8 +1301,7 @@
 		f += fmt.Sprintf(".%v", Sconv(n.Right.Sym, obj.FmtShort|obj.FmtByte))
 		return f
 
-	case ODOTTYPE,
-		ODOTTYPE2:
+	case ODOTTYPE, ODOTTYPE2:
 		var f string
 		f += exprfmt(n.Left, nprec)
 		if n.Right != nil {
@@ -1440,11 +1323,8 @@
 		f += fmt.Sprintf("[%v]", Nconv(n.Right, 0))
 		return f
 
-	case OCOPY,
-		OCOMPLEX:
-		var f string
-		f += fmt.Sprintf("%v(%v, %v)", Oconv(int(n.Op), obj.FmtSharp), Nconv(n.Left, 0), Nconv(n.Right, 0))
-		return f
+	case OCOPY, OCOMPLEX:
+		return fmt.Sprintf("%v(%v, %v)", Oconv(int(n.Op), obj.FmtSharp), Nconv(n.Left, 0), Nconv(n.Right, 0))
 
 	case OCONV,
 		OCONVIFACE,
@@ -1460,9 +1340,7 @@
 		if n.Left != nil {
 			return fmt.Sprintf("%v(%v)", Tconv(n.Type, 0), Nconv(n.Left, 0))
 		}
-		var f string
-		f += fmt.Sprintf("%v(%v)", Tconv(n.Type, 0), Hconv(n.List, obj.FmtComma))
-		return f
+		return fmt.Sprintf("%v(%v)", Tconv(n.Type, 0), Hconv(n.List, obj.FmtComma))
 
 	case OREAL,
 		OIMAG,
@@ -1480,29 +1358,22 @@
 		if n.Left != nil {
 			return fmt.Sprintf("%v(%v)", Oconv(int(n.Op), obj.FmtSharp), Nconv(n.Left, 0))
 		}
-		if n.Isddd != 0 {
+		if n.Isddd {
 			return fmt.Sprintf("%v(%v...)", Oconv(int(n.Op), obj.FmtSharp), Hconv(n.List, obj.FmtComma))
 		}
-		var f string
-		f += fmt.Sprintf("%v(%v)", Oconv(int(n.Op), obj.FmtSharp), Hconv(n.List, obj.FmtComma))
-		return f
+		return fmt.Sprintf("%v(%v)", Oconv(int(n.Op), obj.FmtSharp), Hconv(n.List, obj.FmtComma))
 
-	case OCALL,
-		OCALLFUNC,
-		OCALLINTER,
-		OCALLMETH:
+	case OCALL, OCALLFUNC, OCALLINTER, OCALLMETH:
 		var f string
 		f += exprfmt(n.Left, nprec)
-		if n.Isddd != 0 {
+		if n.Isddd {
 			f += fmt.Sprintf("(%v...)", Hconv(n.List, obj.FmtComma))
 			return f
 		}
 		f += fmt.Sprintf("(%v)", Hconv(n.List, obj.FmtComma))
 		return f
 
-	case OMAKEMAP,
-		OMAKECHAN,
-		OMAKESLICE:
+	case OMAKEMAP, OMAKECHAN, OMAKESLICE:
 		if n.List != nil { // pre-typecheck
 			return fmt.Sprintf("make(%v, %v)", Tconv(n.Type, 0), Hconv(n.List, obj.FmtComma))
 		}
@@ -1512,9 +1383,7 @@
 		if n.Left != nil && (n.Op == OMAKESLICE || !isideal(n.Left.Type)) {
 			return fmt.Sprintf("make(%v, %v)", Tconv(n.Type, 0), Nconv(n.Left, 0))
 		}
-		var f string
-		f += fmt.Sprintf("make(%v)", Tconv(n.Type, 0))
-		return f
+		return fmt.Sprintf("make(%v)", Tconv(n.Type, 0))
 
 		// Unary
 	case OPLUS,
@@ -1528,7 +1397,7 @@
 		if n.Left.Op == n.Op {
 			f += fmt.Sprintf("%v ", Oconv(int(n.Op), obj.FmtSharp))
 		} else {
-			f += fmt.Sprintf("%v", Oconv(int(n.Op), obj.FmtSharp))
+			f += Oconv(int(n.Op), obj.FmtSharp)
 		}
 		f += exprfmt(n.Left, nprec+1)
 		return f
@@ -1572,8 +1441,7 @@
 
 		return f
 
-	case OCMPSTR,
-		OCMPIFACE:
+	case OCMPSTR, OCMPIFACE:
 		var f string
 		f += exprfmt(n.Left, nprec)
 		f += fmt.Sprintf(" %v ", Oconv(int(n.Etype), obj.FmtSharp))
@@ -1613,115 +1481,113 @@
 
 var dumpdepth int
 
-func indent(s string) string {
-	return s + "\n" + strings.Repeat(".   ", dumpdepth)
+func indent(buf *bytes.Buffer) {
+	buf.WriteString("\n")
+	for i := 0; i < dumpdepth; i++ {
+		buf.WriteString(".   ")
+	}
 }
 
 func nodedump(n *Node, flag int) string {
 	if n == nil {
-		var fp string
-		return fp
+		return ""
 	}
 
 	recur := flag&obj.FmtShort == 0 /*untyped*/
 
-	var fp string
+	var buf bytes.Buffer
 	if recur {
-		fp = indent(fp)
+		indent(&buf)
 		if dumpdepth > 10 {
-			fp += "..."
-			return fp
+			buf.WriteString("...")
+			return buf.String()
 		}
 
 		if n.Ninit != nil {
-			fp += fmt.Sprintf("%v-init%v", Oconv(int(n.Op), 0), Hconv(n.Ninit, 0))
-			fp = indent(fp)
+			fmt.Fprintf(&buf, "%v-init%v", Oconv(int(n.Op), 0), Hconv(n.Ninit, 0))
+			indent(&buf)
 		}
 	}
 
-	//	fmtprint(fp, "[%p]", n);
-
 	switch n.Op {
 	default:
-		fp += fmt.Sprintf("%v%v", Oconv(int(n.Op), 0), Jconv(n, 0))
+		fmt.Fprintf(&buf, "%v%v", Oconv(int(n.Op), 0), Jconv(n, 0))
 
-	case OREGISTER,
-		OINDREG:
-		fp += fmt.Sprintf("%v-%v%v", Oconv(int(n.Op), 0), obj.Rconv(int(n.Val.U.Reg)), Jconv(n, 0))
+	case OREGISTER, OINDREG:
+		fmt.Fprintf(&buf, "%v-%v%v", Oconv(int(n.Op), 0), obj.Rconv(int(n.Val.U.Reg)), Jconv(n, 0))
 
 	case OLITERAL:
-		fp += fmt.Sprintf("%v-%v%v", Oconv(int(n.Op), 0), Vconv(&n.Val, 0), Jconv(n, 0))
+		fmt.Fprintf(&buf, "%v-%v%v", Oconv(int(n.Op), 0), Vconv(&n.Val, 0), Jconv(n, 0))
 
-	case ONAME,
-		ONONAME:
+	case ONAME, ONONAME:
 		if n.Sym != nil {
-			fp += fmt.Sprintf("%v-%v%v", Oconv(int(n.Op), 0), Sconv(n.Sym, 0), Jconv(n, 0))
+			fmt.Fprintf(&buf, "%v-%v%v", Oconv(int(n.Op), 0), Sconv(n.Sym, 0), Jconv(n, 0))
 		} else {
-			fp += fmt.Sprintf("%v%v", Oconv(int(n.Op), 0), Jconv(n, 0))
+			fmt.Fprintf(&buf, "%v%v", Oconv(int(n.Op), 0), Jconv(n, 0))
 		}
 		if recur && n.Type == nil && n.Ntype != nil {
-			fp = indent(fp)
-			fp += fmt.Sprintf("%v-ntype%v", Oconv(int(n.Op), 0), Nconv(n.Ntype, 0))
+			indent(&buf)
+			fmt.Fprintf(&buf, "%v-ntype%v", Oconv(int(n.Op), 0), Nconv(n.Ntype, 0))
 		}
 
 	case OASOP:
-		fp += fmt.Sprintf("%v-%v%v", Oconv(int(n.Op), 0), Oconv(int(n.Etype), 0), Jconv(n, 0))
+		fmt.Fprintf(&buf, "%v-%v%v", Oconv(int(n.Op), 0), Oconv(int(n.Etype), 0), Jconv(n, 0))
 
 	case OTYPE:
-		fp += fmt.Sprintf("%v %v%v type=%v", Oconv(int(n.Op), 0), Sconv(n.Sym, 0), Jconv(n, 0), Tconv(n.Type, 0))
+		fmt.Fprintf(&buf, "%v %v%v type=%v", Oconv(int(n.Op), 0), Sconv(n.Sym, 0), Jconv(n, 0), Tconv(n.Type, 0))
 		if recur && n.Type == nil && n.Ntype != nil {
-			fp = indent(fp)
-			fp += fmt.Sprintf("%v-ntype%v", Oconv(int(n.Op), 0), Nconv(n.Ntype, 0))
+			indent(&buf)
+			fmt.Fprintf(&buf, "%v-ntype%v", Oconv(int(n.Op), 0), Nconv(n.Ntype, 0))
 		}
 	}
 
 	if n.Sym != nil && n.Op != ONAME {
-		fp += fmt.Sprintf(" %v G%d", Sconv(n.Sym, 0), n.Vargen)
+		fmt.Fprintf(&buf, " %v G%d", Sconv(n.Sym, 0), n.Vargen)
 	}
 
 	if n.Type != nil {
-		fp += fmt.Sprintf(" %v", Tconv(n.Type, 0))
+		fmt.Fprintf(&buf, " %v", Tconv(n.Type, 0))
 	}
 
 	if recur {
 		if n.Left != nil {
-			fp += fmt.Sprintf("%v", Nconv(n.Left, 0))
+			buf.WriteString(Nconv(n.Left, 0))
 		}
 		if n.Right != nil {
-			fp += fmt.Sprintf("%v", Nconv(n.Right, 0))
+			buf.WriteString(Nconv(n.Right, 0))
 		}
 		if n.List != nil {
-			fp = indent(fp)
-			fp += fmt.Sprintf("%v-list%v", Oconv(int(n.Op), 0), Hconv(n.List, 0))
+			indent(&buf)
+			fmt.Fprintf(&buf, "%v-list%v", Oconv(int(n.Op), 0), Hconv(n.List, 0))
 		}
 
 		if n.Rlist != nil {
-			fp = indent(fp)
-			fp += fmt.Sprintf("%v-rlist%v", Oconv(int(n.Op), 0), Hconv(n.Rlist, 0))
+			indent(&buf)
+			fmt.Fprintf(&buf, "%v-rlist%v", Oconv(int(n.Op), 0), Hconv(n.Rlist, 0))
 		}
 
 		if n.Ntest != nil {
-			fp = indent(fp)
-			fp += fmt.Sprintf("%v-test%v", Oconv(int(n.Op), 0), Nconv(n.Ntest, 0))
+			indent(&buf)
+			fmt.Fprintf(&buf, "%v-test%v", Oconv(int(n.Op), 0), Nconv(n.Ntest, 0))
 		}
 
 		if n.Nbody != nil {
-			fp = indent(fp)
-			fp += fmt.Sprintf("%v-body%v", Oconv(int(n.Op), 0), Hconv(n.Nbody, 0))
+			indent(&buf)
+			fmt.Fprintf(&buf, "%v-body%v", Oconv(int(n.Op), 0), Hconv(n.Nbody, 0))
 		}
 
 		if n.Nelse != nil {
-			fp = indent(fp)
-			fp += fmt.Sprintf("%v-else%v", Oconv(int(n.Op), 0), Hconv(n.Nelse, 0))
+			indent(&buf)
+			fmt.Fprintf(&buf, "%v-else%v", Oconv(int(n.Op), 0), Hconv(n.Nelse, 0))
 		}
 
 		if n.Nincr != nil {
-			fp = indent(fp)
-			fp += fmt.Sprintf("%v-incr%v", Oconv(int(n.Op), 0), Nconv(n.Nincr, 0))
+			indent(&buf)
+			fmt.Fprintf(&buf, "%v-incr%v", Oconv(int(n.Op), 0), Nconv(n.Nincr, 0))
 		}
 	}
 
-	return fp
+	return buf.String()
 }
 
 // Fmt "%S": syms
@@ -1801,8 +1667,7 @@
 	_ = r
 	var str string
 	switch fmtmode {
-	case FErr,
-		FExp:
+	case FErr, FExp:
 		str = nodefmt(n, flag)
 
 	case FDbg:
@@ -1837,17 +1702,17 @@
 		sep = ", "
 	}
 
-	var fp string
+	var buf bytes.Buffer
 	for ; l != nil; l = l.Next {
-		fp += fmt.Sprintf("%v", Nconv(l.N, 0))
+		buf.WriteString(Nconv(l.N, 0))
 		if l.Next != nil {
-			fp += sep
+			buf.WriteString(sep)
 		}
 	}
 
 	flag = sf
 	fmtmode = sm
-	return fp
+	return buf.String()
 }
 
 func dumplist(s string, l *NodeList) {
diff --git a/src/cmd/internal/gc/gen.go b/src/cmd/internal/gc/gen.go
index 079158a..caae2f1 100644
--- a/src/cmd/internal/gc/gen.go
+++ b/src/cmd/internal/gc/gen.go
@@ -57,8 +57,7 @@
 		// so the param already has a valid xoffset.
 
 		// expression to refer to stack copy
-		case PPARAM,
-			PPARAMOUT:
+		case PPARAM, PPARAMOUT:
 			n.Stackparam = Nod(OPARAM, n, nil)
 
 			n.Stackparam.Type = n.Type
@@ -93,8 +92,7 @@
 			Curfn = oldfn
 		}
 
-	case OIND,
-		ODOTPTR:
+	case OIND, ODOTPTR:
 		break
 
 		// ODOTPTR has already been introduced,
@@ -102,8 +100,7 @@
 	// In &x[0], if x is a slice, then x does not
 	// escape--the pointer inside x does, but that
 	// is always a heap pointer anyway.
-	case ODOT,
-		OINDEX:
+	case ODOT, OINDEX:
 		if !Isslice(n.Left.Type) {
 			addrescapes(n.Left)
 		}
@@ -171,9 +168,9 @@
 		// decide what to complain about.
 		// prefer to complain about 'into block' over declarations,
 		// so scan backward to find most recent block or else dcl.
-		block := (*Sym)(nil)
+		var block *Sym
 
-		dcl := (*Sym)(nil)
+		var dcl *Sym
 		ts := to.Sym
 		for ; nt > nf; nt-- {
 			if ts.Pkg == nil {
@@ -235,13 +232,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)
 	}
 }
 
@@ -332,29 +329,24 @@
  * clearslim generates code to zero a slim node.
  */
 func Clearslim(n *Node) {
-	z := Node{}
+	var z Node
 	z.Op = OLITERAL
 	z.Type = n.Type
 	z.Addable = 1
 
 	switch Simtype[n.Type.Etype] {
-	case TCOMPLEX64,
-		TCOMPLEX128:
+	case TCOMPLEX64, TCOMPLEX128:
 		z.Val.U.Cval = new(Mpcplx)
 		Mpmovecflt(&z.Val.U.Cval.Real, 0.0)
 		Mpmovecflt(&z.Val.U.Cval.Imag, 0.0)
 
-	case TFLOAT32,
-		TFLOAT64:
+	case TFLOAT32, TFLOAT64:
 		var zero Mpflt
 		Mpmovecflt(&zero, 0.0)
 		z.Val.Ctype = CTFLT
 		z.Val.U.Fval = &zero
 
-	case TPTR32,
-		TPTR64,
-		TCHAN,
-		TMAP:
+	case TPTR32, TPTR64, TCHAN, TMAP:
 		z.Val.Ctype = CTNIL
 
 	case TBOOL:
@@ -377,7 +369,7 @@
 	}
 
 	ullmancalc(&z)
-	Thearch.Cgen(&z, n)
+	Cgen(&z, n)
 }
 
 /*
@@ -393,17 +385,177 @@
 	 */
 
 	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)
+}
+
+/*
+ * generate one of:
+ *	res, resok = x.(T)
+ *	res = x.(T) (when resok == nil)
+ * n.Left is x
+ * n.Type is T
+ */
+func cgen_dottype(n *Node, res, resok *Node) {
+	if Debug_typeassert > 0 {
+		Warn("type assertion inlined")
+	}
+	//	iface := n.Left
+	//	r1 := iword(iface)
+	//	if n.Left is non-empty interface {
+	//		r1 = *r1
+	//	}
+	//	if r1 == T {
+	//		res = idata(iface)
+	//		resok = true
+	//	} else {
+	//		assert[EI]2T(x, T, nil) // (when resok == nil; does not return)
+	//		resok = false // (when resok != nil)
+	//	}
+	//
+	var iface Node
+	Igen(n.Left, &iface, res)
+	var r1, r2 Node
+	byteptr := Ptrto(Types[TUINT8]) // type used in runtime prototypes for runtime type (*byte)
+	Regalloc(&r1, byteptr, nil)
+	iface.Type = byteptr
+	Cgen(&iface, &r1)
+	if !isnilinter(n.Left.Type) {
+		// Holding itab, want concrete type in second word.
+		Thearch.Gins(Thearch.Optoas(OCMP, byteptr), &r1, Nodintconst(0))
+		p := Gbranch(Thearch.Optoas(OEQ, byteptr), nil, -1)
+		r2 = r1
+		r2.Op = OINDREG
+		r2.Xoffset = int64(Widthptr)
+		Cgen(&r2, &r1)
+		Patch(p, Pc)
+	}
+	Regalloc(&r2, byteptr, nil)
+	Cgen(typename(n.Type), &r2)
+	Thearch.Gins(Thearch.Optoas(OCMP, byteptr), &r1, &r2)
+	p := Gbranch(Thearch.Optoas(ONE, byteptr), nil, -1)
+	iface.Xoffset += int64(Widthptr)
+	Cgen(&iface, &r1)
+	Regfree(&iface)
+
+	if resok == nil {
+		r1.Type = res.Type
+		Cgen(&r1, res)
+		q := Gbranch(obj.AJMP, nil, 0)
+		Patch(p, Pc)
+
+		fn := syslook("panicdottype", 0)
+		dowidth(fn.Type)
+		call := Nod(OCALLFUNC, fn, nil)
+		r1.Type = byteptr
+		r2.Type = byteptr
+		call.List = list(list(list1(&r1), &r2), typename(n.Left.Type))
+		call.List = ascompatte(OCALLFUNC, call, false, getinarg(fn.Type), call.List, 0, nil)
+		gen(call)
+		Regfree(&r1)
+		Regfree(&r2)
+		Thearch.Gins(obj.AUNDEF, nil, nil)
+		Patch(q, Pc)
+	} else {
+		// This half is handling the res, resok = x.(T) case,
+		// which is called from gen, not cgen, and is consequently fussier
+		// about blank assignments. We have to avoid calling cgen for those.
+		Regfree(&r2)
+		r1.Type = res.Type
+		if !isblank(res) {
+			Cgen(&r1, res)
+		}
+		Regfree(&r1)
+		if !isblank(resok) {
+			Cgen(Nodbool(true), resok)
+		}
+		q := Gbranch(obj.AJMP, nil, 0)
+		Patch(p, Pc)
+		if !isblank(res) {
+			n := nodnil()
+			n.Type = res.Type
+			Cgen(n, res)
+		}
+		if !isblank(resok) {
+			Cgen(Nodbool(false), resok)
+		}
+		Patch(q, Pc)
+	}
+}
+
+/*
+ * generate:
+ *	res, resok = x.(T)
+ * n.Left is x
+ * n.Type is T
+ */
+func Cgen_As2dottype(n, res, resok *Node) {
+	if Debug_typeassert > 0 {
+		Warn("type assertion inlined")
+	}
+	//	iface := n.Left
+	//	r1 := iword(iface)
+	//	if n.Left is non-empty interface {
+	//		r1 = *r1
+	//	}
+	//	if r1 == T {
+	//		res = idata(iface)
+	//		resok = true
+	//	} else {
+	//		res = nil
+	//		resok = false
+	//	}
+	//
+	var iface Node
+	Igen(n.Left, &iface, nil)
+	var r1, r2 Node
+	byteptr := Ptrto(Types[TUINT8]) // type used in runtime prototypes for runtime type (*byte)
+	Regalloc(&r1, byteptr, res)
+	iface.Type = byteptr
+	Cgen(&iface, &r1)
+	if !isnilinter(n.Left.Type) {
+		// Holding itab, want concrete type in second word.
+		Thearch.Gins(Thearch.Optoas(OCMP, byteptr), &r1, Nodintconst(0))
+		p := Gbranch(Thearch.Optoas(OEQ, byteptr), nil, -1)
+		r2 = r1
+		r2.Op = OINDREG
+		r2.Xoffset = int64(Widthptr)
+		Cgen(&r2, &r1)
+		Patch(p, Pc)
+	}
+	Regalloc(&r2, byteptr, nil)
+	Cgen(typename(n.Type), &r2)
+	Thearch.Gins(Thearch.Optoas(OCMP, byteptr), &r1, &r2)
+	p := Gbranch(Thearch.Optoas(ONE, byteptr), nil, -1)
+	iface.Type = n.Type
+	iface.Xoffset += int64(Widthptr)
+	Cgen(&iface, &r1)
+	if iface.Op != 0 {
+		Regfree(&iface)
+	}
+	Cgen(&r1, res)
+	q := Gbranch(obj.AJMP, nil, 0)
+	Patch(p, Pc)
+
+	fn := syslook("panicdottype", 0)
+	dowidth(fn.Type)
+	call := Nod(OCALLFUNC, fn, nil)
+	call.List = list(list(list1(&r1), &r2), typename(n.Left.Type))
+	call.List = ascompatte(OCALLFUNC, call, false, getinarg(fn.Type), call.List, 0, nil)
+	gen(call)
+	Regfree(&r1)
+	Regfree(&r2)
+	Thearch.Gins(obj.AUNDEF, nil, nil)
+	Patch(q, Pc)
 }
 
 /*
@@ -418,7 +570,7 @@
 func Cgen_slice(n *Node, res *Node) {
 	cap := n.List.N
 	len := n.List.Next.N
-	offs := (*Node)(nil)
+	var offs *Node
 	if n.List.Next.Next != nil {
 		offs = n.List.Next.Next.N
 	}
@@ -443,7 +595,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
 	}
@@ -452,14 +604,14 @@
 	}
 
 	if n.Op == OSLICEARR || n.Op == OSLICE3ARR {
-		if Isptr[n.Left.Type.Etype] == 0 {
+		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 +620,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 +641,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 +655,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 +670,7 @@
 
 		dst.Xoffset += int64(Array_cap)
 		dst.Type = Types[Simtype[TUINT]]
-		Thearch.Cgen(tmpcap, &dst)
+		Cgen(tmpcap, &dst)
 	}
 }
 
@@ -590,10 +742,8 @@
 
 	// give each tmp a different name so that there
 	// a chance to registerizer them
-	namebuf = fmt.Sprintf("autotmp_%.4d", statuniqgen)
-
+	s := Lookupf("autotmp_%.4d", statuniqgen)
 	statuniqgen++
-	s := Lookup(namebuf)
 	n := Nod(ONAME, nil, nil)
 	n.Sym = s
 	s.Def = n
@@ -603,7 +753,7 @@
 	n.Ullman = 1
 	n.Esc = EscNever
 	n.Curfn = Curfn
-	Curfn.Dcl = list(Curfn.Dcl, n)
+	Curfn.Func.Dcl = list(Curfn.Func.Dcl, n)
 
 	dowidth(t)
 	n.Xoffset = 0
@@ -613,7 +763,7 @@
 func temp(t *Type) *Node {
 	n := Nod(OXXX, nil, nil)
 	Tempname(n, t)
-	n.Sym.Def.Used = 1
+	n.Sym.Def.Used = true
 	return n.Orig
 }
 
@@ -622,7 +772,7 @@
 
 	lno := setlineno(n)
 
-	wasregalloc := Thearch.Anyregalloc()
+	wasregalloc := Anyregalloc()
 
 	if n == nil {
 		goto ret
@@ -675,9 +825,7 @@
 		if n.Defn != nil {
 			switch n.Defn.Op {
 			// so stmtlabel can find the label
-			case OFOR,
-				OSWITCH,
-				OSELECT:
+			case OFOR, OSWITCH, OSELECT:
 				n.Defn.Sym = lab.Sym
 			}
 		}
@@ -762,10 +910,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
@@ -776,15 +924,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
@@ -833,14 +981,17 @@
 		}
 		Cgen_as(n.Left, n.Right)
 
+	case OAS2DOTTYPE:
+		cgen_dottype(n.Rlist.N, n.List.N, n.List.Next.N)
+
 	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,9 +999,8 @@
 	case ODEFER:
 		cgen_proc(n, 2)
 
-	case ORETURN,
-		ORETJMP:
-		Thearch.Cgen_ret(n)
+	case ORETURN, ORETJMP:
+		cgen_ret(n)
 
 	case OCHECKNIL:
 		Cgen_checknil(n.Left)
@@ -860,7 +1010,7 @@
 	}
 
 ret:
-	if Thearch.Anyregalloc() != wasregalloc {
+	if Anyregalloc() != wasregalloc {
 		Dump("node", n)
 		Fatal("registers left allocated")
 	}
@@ -910,10 +1060,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,...)
 
@@ -931,7 +1081,7 @@
 	if n2.Left.Op == ONAME {
 		n2.Left.Class = PFUNC
 	}
-	Thearch.Cgen_call(&n2, proc)
+	cgen_call(&n2, proc)
 }
 
 func checklabels() {
@@ -958,3 +1108,278 @@
 		}
 	}
 }
+
+/*
+ * copy a composite value by moving its individual components.
+ * Slices, strings and interfaces are supported.
+ * Small structs or arrays with elements of basic type are
+ * also supported.
+ * nr is N when assigning a zero value.
+ * return 1 if can do, 0 if can't.
+ */
+func Componentgen(nr *Node, nl *Node) bool {
+	var nodl Node
+	var nodr Node
+
+	freel := 0
+	freer := 0
+
+	var isConstString bool
+
+	switch nl.Type.Etype {
+	default:
+		goto no
+
+	case TARRAY:
+		t := nl.Type
+
+		// Slices are ok.
+		if Isslice(t) {
+			break
+		}
+
+		// Small arrays are ok.
+		if t.Bound > 0 && t.Bound <= 3 && !Isfat(t.Type) {
+			break
+		}
+
+		goto no
+
+		// Small structs with non-fat types are ok.
+	// Zero-sized structs are treated separately elsewhere.
+	case TSTRUCT:
+		fldcount := int64(0)
+
+		for t := nl.Type.Type; t != nil; t = t.Down {
+			if Isfat(t.Type) && !Isslice(t) {
+				goto no
+			}
+			if t.Etype != TFIELD {
+				Fatal("componentgen: not a TFIELD: %v", Tconv(t, obj.FmtLong))
+			}
+			fldcount++
+		}
+
+		if fldcount == 0 || fldcount > 4 {
+			goto no
+		}
+
+	case TSTRING, TINTER:
+		break
+	}
+
+	isConstString = Isconst(nr, CTSTR)
+	nodl = *nl
+	if !cadable(nl) {
+		if nr != nil && !cadable(nr) && !isConstString {
+			goto no
+		}
+		Igen(nl, &nodl, nil)
+		freel = 1
+	}
+
+	if nr != nil {
+		nodr = *nr
+		if !cadable(nr) && !isConstString {
+			Igen(nr, &nodr, nil)
+			freer = 1
+		}
+	} else {
+		// When zeroing, prepare a register containing zero.
+		var tmp Node
+		Nodconst(&tmp, nl.Type, 0)
+
+		Regalloc(&nodr, Types[TUINT], nil)
+		Thearch.Gmove(&tmp, &nodr)
+		freer = 1
+	}
+
+	// nl and nr are 'cadable' which basically means they are names (variables) now.
+	// If they are the same variable, don't generate any code, because the
+	// VARDEF we generate will mark the old value as dead incorrectly.
+	// (And also the assignments are useless.)
+	if nr != nil && nl.Op == ONAME && nr.Op == ONAME && nl == nr {
+		goto yes
+	}
+
+	switch nl.Type.Etype {
+	// componentgen for arrays.
+	case TARRAY:
+		if nl.Op == ONAME {
+			Gvardef(nl)
+		}
+		t := nl.Type
+		if !Isslice(t) {
+			nodl.Type = t.Type
+			nodr.Type = nodl.Type
+			for fldcount := int64(0); fldcount < t.Bound; fldcount++ {
+				if nr == nil {
+					Clearslim(&nodl)
+				} else {
+					Thearch.Gmove(&nodr, &nodl)
+				}
+				nodl.Xoffset += t.Type.Width
+				nodr.Xoffset += t.Type.Width
+			}
+
+			goto yes
+		}
+
+		// componentgen for slices.
+		nodl.Xoffset += int64(Array_array)
+
+		nodl.Type = Ptrto(nl.Type.Type)
+
+		if nr != nil {
+			nodr.Xoffset += int64(Array_array)
+			nodr.Type = nodl.Type
+		}
+
+		Thearch.Gmove(&nodr, &nodl)
+
+		nodl.Xoffset += int64(Array_nel) - int64(Array_array)
+		nodl.Type = Types[Simtype[TUINT]]
+
+		if nr != nil {
+			nodr.Xoffset += int64(Array_nel) - int64(Array_array)
+			nodr.Type = nodl.Type
+		}
+
+		Thearch.Gmove(&nodr, &nodl)
+
+		nodl.Xoffset += int64(Array_cap) - int64(Array_nel)
+		nodl.Type = Types[Simtype[TUINT]]
+
+		if nr != nil {
+			nodr.Xoffset += int64(Array_cap) - int64(Array_nel)
+			nodr.Type = nodl.Type
+		}
+
+		Thearch.Gmove(&nodr, &nodl)
+
+		goto yes
+
+	case TSTRING:
+		if nl.Op == ONAME {
+			Gvardef(nl)
+		}
+		nodl.Xoffset += int64(Array_array)
+		nodl.Type = Ptrto(Types[TUINT8])
+
+		if isConstString {
+			Regalloc(&nodr, Types[Tptr], nil)
+			p := Thearch.Gins(Thearch.Optoas(OAS, Types[Tptr]), nil, &nodr)
+			Datastring(nr.Val.U.Sval, &p.From)
+			p.From.Type = obj.TYPE_ADDR
+			Regfree(&nodr)
+		} else if nr != nil {
+			nodr.Xoffset += int64(Array_array)
+			nodr.Type = nodl.Type
+		}
+
+		Thearch.Gmove(&nodr, &nodl)
+
+		nodl.Xoffset += int64(Array_nel) - int64(Array_array)
+		nodl.Type = Types[Simtype[TUINT]]
+
+		if isConstString {
+			Nodconst(&nodr, nodl.Type, int64(len(nr.Val.U.Sval)))
+		} else if nr != nil {
+			nodr.Xoffset += int64(Array_nel) - int64(Array_array)
+			nodr.Type = nodl.Type
+		}
+
+		Thearch.Gmove(&nodr, &nodl)
+
+		goto yes
+
+	case TINTER:
+		if nl.Op == ONAME {
+			Gvardef(nl)
+		}
+		nodl.Xoffset += int64(Array_array)
+		nodl.Type = Ptrto(Types[TUINT8])
+
+		if nr != nil {
+			nodr.Xoffset += int64(Array_array)
+			nodr.Type = nodl.Type
+		}
+
+		Thearch.Gmove(&nodr, &nodl)
+
+		nodl.Xoffset += int64(Array_nel) - int64(Array_array)
+		nodl.Type = Ptrto(Types[TUINT8])
+
+		if nr != nil {
+			nodr.Xoffset += int64(Array_nel) - int64(Array_array)
+			nodr.Type = nodl.Type
+		}
+
+		Thearch.Gmove(&nodr, &nodl)
+
+		goto yes
+
+	case TSTRUCT:
+		if nl.Op == ONAME {
+			Gvardef(nl)
+		}
+		loffset := nodl.Xoffset
+		roffset := nodr.Xoffset
+
+		// funarg structs may not begin at offset zero.
+		if nl.Type.Etype == TSTRUCT && nl.Type.Funarg != 0 && nl.Type.Type != nil {
+			loffset -= nl.Type.Type.Width
+		}
+		if nr != nil && nr.Type.Etype == TSTRUCT && nr.Type.Funarg != 0 && nr.Type.Type != nil {
+			roffset -= nr.Type.Type.Width
+		}
+
+		for t := nl.Type.Type; t != nil; t = t.Down {
+			nodl.Xoffset = loffset + t.Width
+			nodl.Type = t.Type
+
+			if nr == nil {
+				Clearslim(&nodl)
+			} else {
+				nodr.Xoffset = roffset + t.Width
+				nodr.Type = nodl.Type
+				Thearch.Gmove(&nodr, &nodl)
+			}
+		}
+
+		goto yes
+	}
+
+no:
+	if freer != 0 {
+		Regfree(&nodr)
+	}
+	if freel != 0 {
+		Regfree(&nodl)
+	}
+	return false
+
+yes:
+	if freer != 0 {
+		Regfree(&nodr)
+	}
+	if freel != 0 {
+		Regfree(&nodl)
+	}
+	return true
+}
+
+func cadable(n *Node) bool {
+	if n.Addable == 0 {
+		// dont know how it happens,
+		// but it does
+		return false
+	}
+
+	switch n.Op {
+	case ONAME:
+		return true
+	}
+
+	return false
+}
diff --git a/src/cmd/internal/gc/go.go b/src/cmd/internal/gc/go.go
index a1debbd..a6e525a 100644
--- a/src/cmd/internal/gc/go.go
+++ b/src/cmd/internal/gc/go.go
@@ -7,12 +7,9 @@
 import (
 	"bytes"
 	"cmd/internal/obj"
+	"math/big"
 )
 
-// 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.
-
 // avoid <ctype.h>
 
 // The parser's maximum stack size.
@@ -20,16 +17,21 @@
 // or bison will check for its definition and use
 // a potentially smaller value if it is undefined.
 const (
-	NHUNK    = 50000
-	BUFSIZ   = 8192
-	NSYMB    = 500
-	NHASH    = 1024
-	STRINGSZ = 200
-	MAXALIGN = 7
-	UINF     = 100
-	PRIME1   = 3
-	AUNK     = 100
-	AMEM     = 0 + iota - 9
+	NHUNK           = 50000
+	BUFSIZ          = 8192
+	NSYMB           = 500
+	NHASH           = 1024
+	MAXALIGN        = 7
+	UINF            = 100
+	PRIME1          = 3
+	BADWIDTH        = -1000000000
+	MaxStackVarSize = 10 * 1024 * 1024
+)
+
+const (
+	// These values are known by runtime.
+	// The MEMx and NOEQx values must run in parallel.  See algtype.
+	AMEM = iota
 	AMEM0
 	AMEM8
 	AMEM16
@@ -51,37 +53,35 @@
 	AFLOAT64
 	ACPLX64
 	ACPLX128
-	BADWIDTH        = -1000000000
-	MaxStackVarSize = 10 * 1024 * 1024
+	AUNK = 100
 )
 
-/*
- * note this is the representation
- * of the compilers string literals,
- * it is not the runtime representation
- */
-type Strlit struct {
-	S string
-}
-
 const (
-	Mpscale = 29
-	Mpprec  = 16
-	Mpnorm  = Mpprec - 1
+	Mpscale = 29         // safely smaller than bits in a long
+	Mpprec  = 16         // Mpscale*Mpprec is max number of bits
+	Mpnorm  = Mpprec - 1 // significant words in a normalized float
 	Mpbase  = 1 << Mpscale
 	Mpsign  = Mpbase >> 1
 	Mpmask  = Mpbase - 1
 	Mpdebug = 0
 )
 
+// Mpint represents an integer constant.
 type Mpint struct {
+	Val big.Int
+	Ovf bool // set if Val overflowed compiler limit (sticky)
+}
+
+// Mpfix is the original (old) representation of an integer constant.
+// Still needed for Mpflt.
+type Mpfix struct {
 	A   [Mpprec]int
 	Neg uint8
 	Ovf uint8
 }
 
 type Mpflt struct {
-	Val Mpint
+	Val Mpfix
 	Exp int16
 }
 
@@ -93,156 +93,45 @@
 type Val struct {
 	Ctype int16
 	U     struct {
-		Reg  int16
-		Bval int16
-		Xval *Mpint
-		Fval *Mpflt
-		Cval *Mpcplx
-		Sval *Strlit
+		Reg  int16   // OREGISTER
+		Bval int16   // bool value CTBOOL
+		Xval *Mpint  // int CTINT, rune CTRUNE
+		Fval *Mpflt  // float CTFLT
+		Cval *Mpcplx // float CTCPLX
+		Sval string  // string CTSTR
 	}
 }
 
-type Array struct {
-	length   int32
-	size     int32
-	capacity int32
-	data     string
-}
-
-type Bvec struct {
-	n int32
-	b []uint32
-}
-
 type Pkg struct {
-	Name     string
-	Path     *Strlit
+	Name     string // package name
+	Path     string // string literal used in import statement
 	Pathsym  *Sym
-	Prefix   string
-	Link     *Pkg
-	Imported uint8
-	Exported int8
-	Direct   int8
-	Safe     bool
+	Prefix   string // escaped path for use in symbol table
+	Imported uint8  // export data of this package was parsed
+	Exported int8   // import line written in export data
+	Direct   int8   // imported directly
+	Safe     bool   // whether the package is marked as safe
+	Syms     map[string]*Sym
 }
 
 type Sym struct {
-	Lexical    uint16
-	Flags      uint8
-	Sym        uint8
-	Link       *Sym
-	Npkg       int32
-	Uniqgen    uint32
-	Importdef  *Pkg
-	Linkname   string
+	Lexical   uint16
+	Flags     uint8
+	Link      *Sym
+	Uniqgen   uint32
+	Importdef *Pkg   // where imported definition was found
+	Linkname  string // link name
+
+	// saved and restored by dcopy
 	Pkg        *Pkg
-	Name       string
-	Def        *Node
-	Label      *Label
-	Block      int32
-	Lastlineno int32
-	Origpkg    *Pkg
+	Name       string // variable name
+	Def        *Node  // definition: ONAME OTYPE OPACK or OLITERAL
+	Label      *Label // corresponding label (ephemeral)
+	Block      int32  // blocknumber to catch redeclaration
+	Lastlineno int32  // last declaration for diagnostic
+	Origpkg    *Pkg   // original package for . import
 	Lsym       *obj.LSym
-}
-
-type Node struct {
-	Left           *Node
-	Right          *Node
-	Ntest          *Node
-	Nincr          *Node
-	Ninit          *NodeList
-	Nbody          *NodeList
-	Nelse          *NodeList
-	List           *NodeList
-	Rlist          *NodeList
-	Op             uint8
-	Nointerface    bool
-	Ullman         uint8
-	Addable        uint8
-	Trecur         uint8
-	Etype          uint8
-	Bounded        bool
-	Class          uint8
-	Method         uint8
-	Embedded       uint8
-	Colas          uint8
-	Diag           uint8
-	Noescape       bool
-	Nosplit        bool
-	Builtin        uint8
-	Nowritebarrier bool
-	Walkdef        uint8
-	Typecheck      uint8
-	Local          uint8
-	Dodata         uint8
-	Initorder      uint8
-	Used           uint8
-	Isddd          uint8
-	Readonly       uint8
-	Implicit       uint8
-	Addrtaken      uint8
-	Assigned       uint8
-	Captured       uint8
-	Byval          uint8
-	Dupok          uint8
-	Wrapper        uint8
-	Reslice        uint8
-	Likely         int8
-	Hasbreak       uint8
-	Needzero       uint8
-	Needctxt       bool
-	Esc            uint
-	Funcdepth      int
-	Type           *Type
-	Orig           *Node
-	Nname          *Node
-	Shortname      *Node
-	Enter          *NodeList
-	Exit           *NodeList
-	Cvars          *NodeList
-	Dcl            *NodeList
-	Inl            *NodeList
-	Inldcl         *NodeList
-	Closgen        int
-	Outerfunc      *Node
-	Val            Val
-	Ntype          *Node
-	Defn           *Node
-	Pack           *Node
-	Curfn          *Node
-	Paramfld       *Type
-	Decldepth      int
-	Heapaddr       *Node
-	Outerexpr      *Node
-	Stackparam     *Node
-	Alloc          *Node
-	Outer          *Node
-	Closure        *Node
-	Top            int
-	Inlvar         *Node
-	Pkg            *Pkg
-	Initplan       *InitPlan
-	Escflowsrc     *NodeList
-	Escretval      *NodeList
-	Escloopdepth   int
-	Sym            *Sym
-	InlCost        int32
-	Vargen         int32
-	Lineno         int32
-	Endlineno      int32
-	Xoffset        int64
-	Stkdelta       int64
-	Ostk           int32
-	Iota           int32
-	Walkgen        uint32
-	Esclevel       int32
-	Opt            interface{}
-}
-
-type NodeList struct {
-	N    *Node
-	Next *NodeList
-	End  *NodeList
+	Fsym       *Sym // funcsym
 }
 
 type Type struct {
@@ -250,63 +139,83 @@
 	Nointerface bool
 	Noalg       uint8
 	Chan        uint8
-	Trecur      uint8
+	Trecur      uint8 // to detect loops
 	Printed     uint8
-	Embedded    uint8
+	Embedded    uint8 // TFIELD embedded type
 	Siggen      uint8
-	Funarg      uint8
+	Funarg      uint8 // on TSTRUCT and TFIELD
 	Copyany     uint8
-	Local       uint8
+	Local       bool // created in this file
 	Deferwidth  uint8
-	Broke       uint8
-	Isddd       uint8
+	Broke       uint8 // broken type definition.
+	Isddd       bool  // TFIELD is ... argument
 	Align       uint8
-	Haspointers uint8
-	Nod         *Node
-	Orig        *Type
-	Lineno      int
-	Thistuple   int
-	Outtuple    int
-	Intuple     int
-	Outnamed    uint8
-	Method      *Type
-	Xmethod     *Type
-	Sym         *Sym
-	Vargen      int32
-	Nname       *Node
-	Argwid      int64
-	Type        *Type
-	Width       int64
-	Down        *Type
-	Outer       *Type
-	Note        *Strlit
-	Bound       int64
-	Bucket      *Type
-	Hmap        *Type
-	Hiter       *Type
-	Map         *Type
-	Maplineno   int32
-	Embedlineno int32
-	Copyto      *NodeList
-	Lastfn      *Node
+	Haspointers uint8 // 0 unknown, 1 no, 2 yes
+
+	Nod    *Node // canonical OTYPE node
+	Orig   *Type // original type (type literal or predefined type)
+	Lineno int
+
+	// TFUNC
+	Thistuple int
+	Outtuple  int
+	Intuple   int
+	Outnamed  uint8
+
+	Method  *Type
+	Xmethod *Type
+
+	Sym    *Sym
+	Vargen int32 // unique name for OTYPE/ONAME
+
+	Nname  *Node
+	Argwid int64
+
+	// most nodes
+	Type  *Type // actual type for TFIELD, element type for TARRAY, TCHAN, TMAP, TPTRxx
+	Width int64 // offset in TFIELD, width in all others
+
+	// TFIELD
+	Down  *Type   // next struct field, also key type in TMAP
+	Outer *Type   // outer struct
+	Note  *string // literal string annotation
+
+	// TARRAY
+	Bound int64 // negative is dynamic array
+
+	// TMAP
+	Bucket *Type // internal type representing a hash bucket
+	Hmap   *Type // internal type representing a Hmap (map header object)
+	Hiter  *Type // internal type representing hash iterator state
+	Map    *Type // link from the above 3 internal types back to the map type.
+
+	Maplineno   int32 // first use of TFORW as map key
+	Embedlineno int32 // first use of TFORW as embedded type
+
+	// for TFORW, where to copy the eventual value to
+	Copyto *NodeList
+
+	Lastfn *Node // for usefield
 }
 
 type Label struct {
-	Used     uint8
-	Sym      *Sym
-	Def      *Node
-	Use      *NodeList
-	Link     *Label
-	Gotopc   *obj.Prog
-	Labelpc  *obj.Prog
-	Breakpc  *obj.Prog
-	Continpc *obj.Prog
+	Used uint8
+	Sym  *Sym
+	Def  *Node
+	Use  *NodeList
+	Link *Label
+
+	// for use during gen
+	Gotopc   *obj.Prog // pointer to unresolved gotos
+	Labelpc  *obj.Prog // pointer to code
+	Breakpc  *obj.Prog // pointer to code
+	Continpc *obj.Prog // pointer to code
 }
 
 type InitEntry struct {
-	Xoffset int64
-	Key     *Node
-	Expr    *Node
+	Xoffset int64 // struct, array only
+	Key     *Node // map only
+	Expr    *Node // bytes of run-time computed expressions
 }
 
 type InitPlan struct {
@@ -325,30 +234,14 @@
 	EscNever
 	EscBits           = 3
 	EscMask           = (1 << EscBits) - 1
-	EscContentEscapes = 1 << EscBits
+	EscContentEscapes = 1 << EscBits // value obtained by indirect of parameter escapes to some returned result
 	EscReturnBits     = EscBits + 1
 )
 
-/*
- * Every node has a walkgen field.
- * If you want to do a traversal of a node graph that
- * might contain duplicates and want to avoid
- * visiting the same nodes twice, increment walkgen
- * before starting.  Then before processing a node, do
- *
- *	if(n->walkgen == walkgen)
- *		return;
- *	n->walkgen = walkgen;
- *
- * Such a walk cannot call another such walk recursively,
- * because of the use of the global walkgen.
- */
-var walkgen uint32
-
 const (
-	SymExport   = 1 << 0
+	SymExport   = 1 << 0 // to be exported
 	SymPackage  = 1 << 1
-	SymExported = 1 << 2
+	SymExported = 1 << 2 // already written out by export
 	SymUniq     = 1 << 3
 	SymSiggen   = 1 << 4
 	SymAsm      = 1 << 5
@@ -365,165 +258,9 @@
 	N     *Node
 }
 
-// Node ops.
-const (
-	OXXX = iota
-	ONAME
-	ONONAME
-	OTYPE
-	OPACK
-	OLITERAL
-	OADD
-	OSUB
-	OOR
-	OXOR
-	OADDSTR
-	OADDR
-	OANDAND
-	OAPPEND
-	OARRAYBYTESTR
-	OARRAYBYTESTRTMP
-	OARRAYRUNESTR
-	OSTRARRAYBYTE
-	OSTRARRAYBYTETMP
-	OSTRARRAYRUNE
-	OAS
-	OAS2
-	OAS2FUNC
-	OAS2RECV
-	OAS2MAPR
-	OAS2DOTTYPE
-	OASOP
-	OCALL
-	OCALLFUNC
-	OCALLMETH
-	OCALLINTER
-	OCALLPART
-	OCAP
-	OCLOSE
-	OCLOSURE
-	OCMPIFACE
-	OCMPSTR
-	OCOMPLIT
-	OMAPLIT
-	OSTRUCTLIT
-	OARRAYLIT
-	OPTRLIT
-	OCONV
-	OCONVIFACE
-	OCONVNOP
-	OCOPY
-	ODCL
-	ODCLFUNC
-	ODCLFIELD
-	ODCLCONST
-	ODCLTYPE
-	ODELETE
-	ODOT
-	ODOTPTR
-	ODOTMETH
-	ODOTINTER
-	OXDOT
-	ODOTTYPE
-	ODOTTYPE2
-	OEQ
-	ONE
-	OLT
-	OLE
-	OGE
-	OGT
-	OIND
-	OINDEX
-	OINDEXMAP
-	OKEY
-	OPARAM
-	OLEN
-	OMAKE
-	OMAKECHAN
-	OMAKEMAP
-	OMAKESLICE
-	OMUL
-	ODIV
-	OMOD
-	OLSH
-	ORSH
-	OAND
-	OANDNOT
-	ONEW
-	ONOT
-	OCOM
-	OPLUS
-	OMINUS
-	OOROR
-	OPANIC
-	OPRINT
-	OPRINTN
-	OPAREN
-	OSEND
-	OSLICE
-	OSLICEARR
-	OSLICESTR
-	OSLICE3
-	OSLICE3ARR
-	ORECOVER
-	ORECV
-	ORUNESTR
-	OSELRECV
-	OSELRECV2
-	OIOTA
-	OREAL
-	OIMAG
-	OCOMPLEX
-	OBLOCK
-	OBREAK
-	OCASE
-	OXCASE
-	OCONTINUE
-	ODEFER
-	OEMPTY
-	OFALL
-	OXFALL
-	OFOR
-	OGOTO
-	OIF
-	OLABEL
-	OPROC
-	ORANGE
-	ORETURN
-	OSELECT
-	OSWITCH
-	OTYPESW
-	OTCHAN
-	OTMAP
-	OTSTRUCT
-	OTINTER
-	OTFUNC
-	OTARRAY
-	ODDD
-	ODDDARG
-	OINLCALL
-	OEFACE
-	OITAB
-	OSPTR
-	OCLOSUREVAR
-	OCFUNC
-	OCHECKNIL
-	OVARKILL
-	OREGISTER
-	OINDREG
-	OCMP
-	ODEC
-	OINC
-	OEXTEND
-	OHMUL
-	OLROT
-	ORROTC
-	ORETJMP
-	OEND
-)
-
 const (
 	Txxx = iota
+
 	TINT8
 	TUINT8
 	TINT16
@@ -535,13 +272,18 @@
 	TINT
 	TUINT
 	TUINTPTR
+
 	TCOMPLEX64
 	TCOMPLEX128
+
 	TFLOAT32
 	TFLOAT64
+
 	TBOOL
+
 	TPTR32
 	TPTR64
+
 	TFUNC
 	TARRAY
 	T_old_DARRAY
@@ -554,17 +296,23 @@
 	TANY
 	TSTRING
 	TUNSAFEPTR
+
+	// pseudo-types for literals
 	TIDEAL
 	TNIL
 	TBLANK
+
+	// pseudo-type for frame layout
 	TFUNCARGS
 	TCHANARGS
 	TINTERMETH
+
 	NTYPE
 )
 
 const (
 	CTxxx = iota
+
 	CTINT
 	CTRUNE
 	CTFLT
@@ -575,6 +323,8 @@
 )
 
 const (
+	/* types of channel */
+	/* must match ../../pkg/nreflect/type.go:/Chandir */
 	Cxxx  = 0
 	Crecv = 1 << 0
 	Csend = 1 << 1
@@ -583,55 +333,33 @@
 
 // declaration context
 const (
-	Pxxx = iota
-	PEXTERN
-	PAUTO
-	PPARAM
-	PPARAMOUT
-	PPARAMREF
-	PFUNC
-	PDISCARD
-	PHEAP = 1 << 7
+	Pxxx      = iota
+	PEXTERN   // global variable
+	PAUTO     // local variables
+	PPARAM    // input arguments
+	PPARAMOUT // output results
+	PPARAMREF // closure variable reference
+	PFUNC     // global function
+
+	PDISCARD // discard during parse of duplicate import
+
+	PHEAP = 1 << 7 // an extra bit to identify an escaped variable
 )
 
 const (
-	Etop      = 1 << 1
-	Erv       = 1 << 2
+	Etop      = 1 << 1 // evaluated at statement level
+	Erv       = 1 << 2 // evaluated in value context
 	Etype     = 1 << 3
-	Ecall     = 1 << 4
-	Efnstruct = 1 << 5
-	Eiota     = 1 << 6
-	Easgn     = 1 << 7
-	Eindir    = 1 << 8
-	Eaddr     = 1 << 9
-	Eproc     = 1 << 10
-	Ecomplit  = 1 << 11
+	Ecall     = 1 << 4  // call-only expressions are ok
+	Efnstruct = 1 << 5  // multivalue function returns are ok
+	Eiota     = 1 << 6  // iota is ok
+	Easgn     = 1 << 7  // assigning to expression
+	Eindir    = 1 << 8  // indirecting through expression
+	Eaddr     = 1 << 9  // taking address of expression
+	Eproc     = 1 << 10 // inside a go statement
+	Ecomplit  = 1 << 11 // type in composite literal
 )
 
-const (
-	BITS = 3
-	NVAR = BITS * 64
-)
-
-type Bits struct {
-	b [BITS]uint64
-}
-
-var zbits Bits
-
-type Var struct {
-	offset     int64
-	node       *Node
-	nextinnode *Var
-	width      int
-	id         int
-	name       int8
-	etype      int8
-	addr       int8
-}
-
-var var_ [NVAR]Var
-
 type Typedef struct {
 	Name   string
 	Etype  int
@@ -652,13 +380,12 @@
 type Io struct {
 	infile     string
 	bin        *obj.Biobuf
-	ilineno    int32
 	nlsemi     int
 	eofnl      int
 	last       int
 	peekc      int
-	peekc1     int
-	cp         string
+	peekc1     int    // second peekc for ...
+	cp         string // used for content when bin==nil
 	importsafe bool
 }
 
@@ -676,14 +403,18 @@
  * smagic and umagic
  */
 type Magic struct {
-	W   int
-	S   int
-	Bad int
-	Sd  int64
-	Sm  int64
-	Ud  uint64
-	Um  uint64
-	Ua  int
+	W   int // input for both - width
+	S   int // output for both - shift
+	Bad int // output for both - unexpected failure
+
+	// magic multiplier for signed literal divisors
+	Sd int64 // input - literal divisor
+	Sm int64 // output - multiplier
+
+	// magic multiplier for unsigned literal divisors
+	Ud uint64 // input - literal divisor
+	Um uint64 // output - multiplier
+	Ua int    // output - adder
 }
 
 /*
@@ -749,8 +480,6 @@
 
 var nolocalimports int
 
-var namebuf string
-
 var lexbuf bytes.Buffer
 var strbuf bytes.Buffer
 
@@ -761,8 +490,7 @@
 var debugstr string
 
 var Debug_checknil int
-
-var hash [NHASH]*Sym
+var Debug_typeassert int
 
 var importmyname *Sym // my name for package
 
@@ -796,8 +524,6 @@
 
 var rawpkg *Pkg // fake package for raw symbol names
 
-var phash [128]*Pkg
-
 var Tptr int // either TPTR32 or TPTR64
 
 var myimportpath string
@@ -822,43 +548,33 @@
 
 var Simtype [NTYPE]uint8
 
-var Isptr [NTYPE]uint8
+var (
+	Isptr     [NTYPE]bool
+	isforw    [NTYPE]bool
+	Isint     [NTYPE]bool
+	Isfloat   [NTYPE]bool
+	Iscomplex [NTYPE]bool
+	Issigned  [NTYPE]bool
+	issimple  [NTYPE]bool
+)
 
-var isforw [NTYPE]uint8
+var (
+	okforeq    [NTYPE]bool
+	okforadd   [NTYPE]bool
+	okforand   [NTYPE]bool
+	okfornone  [NTYPE]bool
+	okforcmp   [NTYPE]bool
+	okforbool  [NTYPE]bool
+	okforcap   [NTYPE]bool
+	okforlen   [NTYPE]bool
+	okforarith [NTYPE]bool
+	okforconst [NTYPE]bool
+)
 
-var Isint [NTYPE]uint8
-
-var Isfloat [NTYPE]uint8
-
-var Iscomplex [NTYPE]uint8
-
-var Issigned [NTYPE]uint8
-
-var issimple [NTYPE]uint8
-
-var okforeq [NTYPE]uint8
-
-var okforadd [NTYPE]uint8
-
-var okforand [NTYPE]uint8
-
-var okfornone [NTYPE]uint8
-
-var okforcmp [NTYPE]uint8
-
-var okforbool [NTYPE]uint8
-
-var okforcap [NTYPE]uint8
-
-var okforlen [NTYPE]uint8
-
-var okforarith [NTYPE]uint8
-
-var okforconst [NTYPE]uint8
-
-var okfor [OEND][]byte
-
-var iscmp [OEND]uint8
+var (
+	okfor [OEND][]bool
+	iscmp [OEND]bool
+)
 
 var Minintval [NTYPE]*Mpint
 
@@ -916,7 +632,7 @@
 
 var nblank *Node
 
-var Use_sse int
+var Use_sse bool // should we generate SSE2 instructions for 386 targets
 
 var hunk string
 
@@ -924,7 +640,7 @@
 
 var thunk int32
 
-var Funcdepth int
+var Funcdepth int32
 
 var typecheckok int
 
@@ -962,81 +678,6 @@
 
 var Nacl bool
 
-/*
- *	y.tab.c
- */
-
-/*
- *	align.c
- */
-
-/*
- *	array.c
- */
-
-/*
- *	bits.c
- */
-
-/*
- *	mparith1.c
- */
-
-/*
- *	mparith2.c
- */
-
-/*
- *	mparith3.c
- */
-
-/*
- *	obj.c
- */
-
-/*
- *	order.c
- */
-
-/*
- *	range.c
- */
-
-/*
- *	reflect.c
- */
-
-/*
- *	select.c
- */
-
-/*
- *	sinit.c
- */
-
-/*
- *	subr.c
- */
-
-/*
- *	swt.c
- */
-
-/*
- *	typecheck.c
- */
-
-/*
- *	unsafe.c
- */
-
-/*
- *	walk.c
- */
-
-/*
- *	thearch-specific ggen.c/gsubr.c/gobj.c/pgen.c/plive.c
- */
 var continpc *obj.Prog
 
 var breakpc *obj.Prog
@@ -1051,118 +692,146 @@
 
 var zerosize int64
 
-/*
- *	racewalk.c
- */
-
-/*
- *	flow.c
- */
 type Flow struct {
-	Prog   *obj.Prog
-	P1     *Flow
-	P2     *Flow
+	Prog   *obj.Prog // actual instruction
+	P1     *Flow     // predecessors of this instruction: p1,
+	P2     *Flow     // and then p2 linked though p2link.
 	P2link *Flow
-	S1     *Flow
+	S1     *Flow // successors of this instruction (at most two: s1 and s2).
 	S2     *Flow
-	Link   *Flow
-	Active int32
-	Id     int32
-	Rpo    int32
-	Loop   uint16
-	Refset uint8
-	Data   interface{}
+	Link   *Flow // next instruction in function code
+
+	Active int32 // usable by client
+
+	Id     int32  // sequence number in flow graph
+	Rpo    int32  // reverse post ordering
+	Loop   uint16 // x5 for every loop
+	Refset uint8  // diagnostic generated
+
+	Data interface{} // for use by client
 }
 
 type Graph struct {
 	Start *Flow
 	Num   int
-	Rpo   []*Flow
+
+	// After calling flowrpo, rpo lists the flow nodes in reverse postorder,
+	// and each non-dead Flow node f has g->rpo[f->rpo] == f.
+	Rpo []*Flow
 }
 
 /*
  *	interface to back end
  */
-type ProgInfo struct {
-	Flags    uint32
-	Reguse   uint64
-	Regset   uint64
-	Regindex uint64
-}
 
 const (
-	Pseudo     = 1 << 1
-	OK         = 1 << 2
-	SizeB      = 1 << 3
-	SizeW      = 1 << 4
-	SizeL      = 1 << 5
-	SizeQ      = 1 << 6
-	SizeF      = 1 << 7
-	SizeD      = 1 << 8
-	LeftAddr   = 1 << 9
-	LeftRead   = 1 << 10
-	LeftWrite  = 1 << 11
+	// Pseudo-op, like TEXT, GLOBL, TYPE, PCDATA, FUNCDATA.
+	Pseudo = 1 << 1
+
+	// There's nothing to say about the instruction,
+	// but it's still okay to see.
+	OK = 1 << 2
+
+	// Size of right-side write, or right-side read if no write.
+	SizeB = 1 << 3
+	SizeW = 1 << 4
+	SizeL = 1 << 5
+	SizeQ = 1 << 6
+	SizeF = 1 << 7
+	SizeD = 1 << 8
+
+	// Left side (Prog.from): address taken, read, write.
+	LeftAddr  = 1 << 9
+	LeftRead  = 1 << 10
+	LeftWrite = 1 << 11
+
+	// Register in middle (Prog.reg); only ever read. (arm, ppc64)
 	RegRead    = 1 << 12
 	CanRegRead = 1 << 13
+
+	// Right side (Prog.to): address taken, read, write.
 	RightAddr  = 1 << 14
 	RightRead  = 1 << 15
 	RightWrite = 1 << 16
-	Move       = 1 << 17
-	Conv       = 1 << 18
-	Cjmp       = 1 << 19
-	Break      = 1 << 20
-	Call       = 1 << 21
-	Jump       = 1 << 22
-	Skip       = 1 << 23
-	SetCarry   = 1 << 24
-	UseCarry   = 1 << 25
-	KillCarry  = 1 << 26
-	ShiftCX    = 1 << 27
-	ImulAXDX   = 1 << 28
-	PostInc    = 1 << 29
+
+	// Instruction kinds
+	Move  = 1 << 17 // straight move
+	Conv  = 1 << 18 // size conversion
+	Cjmp  = 1 << 19 // conditional jump
+	Break = 1 << 20 // breaks control flow (no fallthrough)
+	Call  = 1 << 21 // function call
+	Jump  = 1 << 22 // jump
+	Skip  = 1 << 23 // data instruction
+
+	// Set, use, or kill of carry bit.
+	// Kill means we never look at the carry bit after this kind of instruction.
+	SetCarry  = 1 << 24
+	UseCarry  = 1 << 25
+	KillCarry = 1 << 26
+
+	// Special cases for register use. (amd64, 386)
+	ShiftCX  = 1 << 27 // possible shift by CX
+	ImulAXDX = 1 << 28 // possible multiply into DX:AX
+
+	// Instruction updates whichever of from/to is type D_OREG. (ppc64)
+	PostInc = 1 << 29
 )
 
 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)
-	Igen           func(*Node, *Node, *Node)
-	Linkarchinit   func()
-	Peep           func(*obj.Prog)
-	Proginfo       func(*ProgInfo, *obj.Prog)
-	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/go.y b/src/cmd/internal/gc/go.y
index 53aec54..62d2556 100644
--- a/src/cmd/internal/gc/go.y
+++ b/src/cmd/internal/gc/go.y
@@ -249,15 +249,15 @@
 	{
 		if importpkg.Name == "" {
 			importpkg.Name = $2.Name;
-			Pkglookup($2.Name, nil).Npkg++;
+			numImport[$2.Name]++
 		} else if importpkg.Name != $2.Name {
-			Yyerror("conflicting names %s and %s for package \"%v\"", importpkg.Name, $2.Name, Zconv(importpkg.Path, 0));
+			Yyerror("conflicting names %s and %s for package %q", importpkg.Name, $2.Name, importpkg.Path);
 		}
 		importpkg.Direct = 1;
 		importpkg.Safe = curio.importsafe
 
 		if safemode != 0 && !curio.importsafe {
-			Yyerror("cannot import unsafe package \"%v\"", Zconv(importpkg.Path, 0));
+			Yyerror("cannot import unsafe package %q", importpkg.Path);
 		}
 	}
 
@@ -404,7 +404,7 @@
 typedcl:
 	typedclname ntype
 	{
-		$$ = typedcl1($1, $2, 1);
+		$$ = typedcl1($1, $2, true);
 	}
 
 simple_stmt:
@@ -418,7 +418,7 @@
 		switch($$.Op) {
 		case ONAME, ONONAME, OTYPE, OPACK, OLITERAL:
 			$$ = Nod(OPAREN, $$, nil);
-			$$.Implicit = 1;
+			$$.Implicit = true;
 			break;
 		}
 	}
@@ -460,13 +460,13 @@
 |	expr LINC
 	{
 		$$ = Nod(OASOP, $1, Nodintconst(1));
-		$$.Implicit = 1;
+		$$.Implicit = true;
 		$$.Etype = OADD;
 	}
 |	expr LDEC
 	{
 		$$ = Nod(OASOP, $1, Nodintconst(1));
-		$$.Implicit = 1;
+		$$.Implicit = true;
 		$$.Etype = OSUB;
 	}
 
@@ -886,7 +886,7 @@
 			// Special case for &T{...}: turn into (*T){...}.
 			$$ = $2;
 			$$.Right = Nod(OIND, $$.Right, nil);
-			$$.Right.Implicit = 1;
+			$$.Right.Implicit = true;
 		} else {
 			$$ = Nod(OADDR, $2, nil);
 		}
@@ -935,7 +935,7 @@
 	{
 		$$ = Nod(OCALL, $1, nil);
 		$$.List = $3;
-		$$.Isddd = 1;
+		$$.Isddd = true;
 	}
 
 pexpr_no_paren:
@@ -949,7 +949,7 @@
 		if $1.Op == OPACK {
 			var s *Sym
 			s = restrictlookup($3.Name, $1.Pkg);
-			$1.Used = 1;
+			$1.Used = true;
 			$$ = oldname(s);
 			break;
 		}
@@ -1034,7 +1034,7 @@
 		switch($$.Op) {
 		case ONAME, ONONAME, OTYPE, OPACK, OLITERAL:
 			$$ = Nod(OPAREN, $$, nil);
-			$$.Implicit = 1;
+			$$.Implicit = true;
 		}
 	}
 |	'{' start_complit braced_keyval_list '}'
@@ -1130,7 +1130,7 @@
 	{
 		var p *Pkg
 
-		if $2.U.Sval.S == "" {
+		if $2.U.Sval == "" {
 			p = importpkg;
 		} else {
 			if isbadimport($2.U.Sval) {
@@ -1144,7 +1144,7 @@
 	{
 		var p *Pkg
 
-		if $2.U.Sval.S == "" {
+		if $2.U.Sval == "" {
 			p = importpkg;
 		} else {
 			if isbadimport($2.U.Sval) {
@@ -1160,7 +1160,7 @@
 	{
 		$$ = oldname($1);
 		if $$.Pack != nil {
-			$$.Pack.Used = 1;
+			$$.Pack.Used = true;
 		}
 	}
 
@@ -1238,7 +1238,7 @@
 		if $1.Op == OPACK {
 			var s *Sym
 			s = restrictlookup($3.Name, $1.Pkg);
-			$1.Used = 1;
+			$1.Used = true;
 			$$ = oldname(s);
 			break;
 		}
@@ -1326,10 +1326,10 @@
 			Yyerror("can only use //go:noescape with external func implementations");
 		}
 		$$.Nbody = $3;
-		$$.Endlineno = lineno;
+		$$.Func.Endlineno = lineno;
 		$$.Noescape = noescape;
-		$$.Nosplit = nosplit;
-		$$.Nowritebarrier = nowritebarrier;
+		$$.Func.Nosplit = nosplit;
+		$$.Func.Nowritebarrier = nowritebarrier;
 		funcbody($$);
 	}
 
@@ -1358,7 +1358,7 @@
 		t.Rlist = $5;
 
 		$$ = Nod(ODCLFUNC, nil, nil);
-		$$.Nname = newname($1);
+		$$.Nname = newfuncname($1);
 		$$.Nname.Defn = $$;
 		$$.Nname.Ntype = t;		// TODO: check if nname already has an ntype
 		declare($$.Nname, PFUNC);
@@ -1392,8 +1392,8 @@
 		t.Rlist = $8;
 
 		$$ = Nod(ODCLFUNC, nil, nil);
-		$$.Shortname = newname($4);
-		$$.Nname = methodname1($$.Shortname, rcvr.Right);
+		$$.Func.Shortname = newfuncname($4);
+		$$.Nname = methodname1($$.Func.Shortname, rcvr.Right);
 		$$.Nname.Defn = $$;
 		$$.Nname.Ntype = t;
 		$$.Nname.Nointerface = nointerface;
@@ -1422,7 +1422,7 @@
 			Yyerror("inconsistent definition for func %v during import\n\t%v\n\t%v", Sconv(s, 0), Tconv(s.Def.Type, 0), Tconv(t, 0));
 		}
 
-		$$ = newname(s);
+		$$ = newfuncname(s);
 		$$.Type = t;
 		declare($$, PFUNC);
 
@@ -1626,7 +1626,7 @@
 		$$ = $1;
 		n = oldname($1);
 		if n.Pack != nil {
-			n.Pack.Used = 1;
+			n.Pack.Used = true;
 		}
 	}
 |	LNAME '.' sym
@@ -1637,7 +1637,7 @@
 			Yyerror("%v is not a package", Sconv($1, 0));
 			pkg = localpkg;
 		} else {
-			$1.Def.Used = 1;
+			$1.Def.Used = true;
 			pkg = $1.Def.Pkg;
 		}
 		$$ = restrictlookup($3.Name, pkg);
@@ -1787,7 +1787,7 @@
 		if $$.List == nil && Curfn != nil {
 			var l *NodeList
 
-			for l=Curfn.Dcl; l != nil; l=l.Next {
+			for l=Curfn.Func.Dcl; l != nil; l=l.Next {
 				if l.N.Class == PPARAM {
 					continue;
 				}
@@ -1969,15 +1969,15 @@
 			break;
 		}
 
-		$2.Inl = $3;
+		$2.Func.Inl = $3;
 
 		funcbody($2);
 		importlist = list(importlist, $2);
 
 		if Debug['E'] > 0 {
-			print("import [%v] func %lN \n", Zconv(importpkg.Path, 0), $2);
-			if Debug['m'] > 2 && $2.Inl != nil {
-				print("inl body:%+H\n", $2.Inl);
+			print("import [%q] func %lN \n", importpkg.Path, $2);
+			if Debug['m'] > 2 && $2.Func.Inl != nil {
+				print("inl body:%+H\n", $2.Func.Inl);
 			}
 		}
 	}
@@ -2103,7 +2103,7 @@
 		if $1 != nil {
 			$$.Left = newname($1);
 		}
-		$$.Isddd = 1;
+		$$.Isddd = true;
 		$$.Val = $4;
 	}
 
@@ -2118,7 +2118,7 @@
 			$$.Val = $3;
 		} else {
 			s = $2.Sym;
-			if s == nil && Isptr[$2.Etype] != 0 {
+			if s == nil && Isptr[$2.Etype] {
 				s = $2.Type.Sym;
 			}
 			p = importpkg;
diff --git a/src/cmd/internal/gc/gsubr.go b/src/cmd/internal/gc/gsubr.go
index ad5e494..499c216 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
 
@@ -76,14 +81,11 @@
 	return true
 }
 
-/*
- * gsubr.c
- */
 func Gbranch(as int, t *Type, likely int) *obj.Prog {
 	p := Prog(as)
 	p.To.Type = obj.TYPE_BRANCH
-	p.To.U.Branch = nil
-	if as != obj.AJMP && likely != 0 && Thearch.Thechar != '9' {
+	p.To.Val = nil
+	if as != obj.AJMP && likely != 0 && Thearch.Thechar != '9' && Thearch.Thechar != '7' {
 		p.From.Type = obj.TYPE_CONST
 		p.From.Offset = int64(bool2int(likely > 0))
 	}
@@ -167,18 +169,19 @@
 	Clearp(Pc)
 }
 
+// Fixup instructions after allocauto (formerly compactframe) has moved all autos around.
 func fixautoused(p *obj.Prog) {
 	for lp := &p; ; {
 		p = *lp
 		if p == nil {
 			break
 		}
-		if p.As == obj.ATYPE && p.From.Node != nil && p.From.Name == obj.NAME_AUTO && ((p.From.Node).(*Node)).Used == 0 {
+		if p.As == obj.ATYPE && p.From.Node != nil && p.From.Name == obj.NAME_AUTO && !((p.From.Node).(*Node)).Used {
 			*lp = p.Link
 			continue
 		}
 
-		if (p.As == obj.AVARDEF || p.As == obj.AVARKILL) && p.To.Node != nil && ((p.To.Node).(*Node)).Used == 0 {
+		if (p.As == obj.AVARDEF || p.As == obj.AVARKILL) && p.To.Node != nil && !((p.To.Node).(*Node)).Used {
 			// Cannot remove VARDEF instruction, because - unlike TYPE handled above -
 			// VARDEFs are interspersed with other code, and a jump might be using the
 			// VARDEF as a target. Replace with a no-op instead. A later pass will remove
@@ -207,7 +210,7 @@
 	p.To.Sym = nil
 	p.To.Type = obj.TYPE_CONST
 	p.To.Offset = nam.Type.Width
-	if nam.Readonly != 0 {
+	if nam.Readonly {
 		p.From3.Offset = obj.RODATA
 	}
 	if nam.Type != nil && !haspointers(nam.Type) {
@@ -247,9 +250,7 @@
 func Isfat(t *Type) bool {
 	if t != nil {
 		switch t.Etype {
-		case TSTRUCT,
-			TARRAY,
-			TSTRING,
+		case TSTRUCT, TARRAY, TSTRING,
 			TINTER: // maybe remove later
 			return true
 		}
@@ -258,6 +259,7 @@
 	return false
 }
 
+// Sweep the prog list to mark any used nodes.
 func markautoused(p *obj.Prog) {
 	for ; p != nil; p = p.Link {
 		if p.As == obj.ATYPE || p.As == obj.AVARDEF || p.As == obj.AVARKILL {
@@ -265,17 +267,18 @@
 		}
 
 		if p.From.Node != nil {
-			((p.From.Node).(*Node)).Used = 1
+			((p.From.Node).(*Node)).Used = true
 		}
 
 		if p.To.Node != nil {
-			((p.To.Node).(*Node)).Used = 1
+			((p.To.Node).(*Node)).Used = true
 		}
 	}
 }
 
-func Naddr(n *Node, a *obj.Addr, canemitcode int) {
-	*a = obj.Addr{}
+// Naddr rewrites a to refer to n.
+// It assumes that a is zeroed on entry.
+func Naddr(a *obj.Addr, n *Node) {
 	if n == nil {
 		return
 	}
@@ -294,6 +297,9 @@
 
 	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:
@@ -329,7 +335,7 @@
 		a.Node = n.Left.Orig
 
 	case OCLOSUREVAR:
-		if !Curfn.Needctxt {
+		if !Curfn.Func.Needctxt {
 			Fatal("closurevar without needctxt")
 		}
 		a.Type = obj.TYPE_MEM
@@ -338,7 +344,7 @@
 		a.Offset = n.Xoffset
 
 	case OCFUNC:
-		Naddr(n.Left, a, canemitcode)
+		Naddr(a, n.Left)
 		a.Sym = Linksym(n.Left.Sym)
 
 	case ONAME:
@@ -376,8 +382,7 @@
 		case PAUTO:
 			a.Name = obj.NAME_AUTO
 
-		case PPARAM,
-			PPARAMOUT:
+		case PPARAM, PPARAMOUT:
 			a.Name = obj.NAME_PARAM
 
 		case PFUNC:
@@ -399,10 +404,9 @@
 
 		case CTFLT:
 			a.Type = obj.TYPE_FCONST
-			a.U.Dval = mpgetflt(n.Val.U.Fval)
+			a.Val = mpgetflt(n.Val.U.Fval)
 
-		case CTINT,
-			CTRUNE:
+		case CTINT, CTRUNE:
 			a.Sym = nil
 			a.Type = obj.TYPE_CONST
 			a.Offset = Mpgetfix(n.Val.U.Xval)
@@ -422,19 +426,20 @@
 		}
 
 	case OADDR:
-		Naddr(n.Left, a, canemitcode)
+		Naddr(a, n.Left)
 		a.Etype = uint8(Tptr)
-		if Thearch.Thechar != '5' && Thearch.Thechar != '9' { // TODO(rsc): Do this even for arm, ppc64.
+		if Thearch.Thechar != '5' && Thearch.Thechar != '7' && Thearch.Thechar != '9' { // TODO(rsc): Do this even for arm, ppc64.
 			a.Width = int64(Widthptr)
 		}
 		if a.Type != obj.TYPE_MEM {
+			a := a // copy to let escape into Ctxt.Dconv
 			Fatal("naddr: OADDR %v (from %v)", Ctxt.Dconv(a), Oconv(int(n.Left.Op), 0))
 		}
 		a.Type = obj.TYPE_ADDR
 
 		// itable of interface value
 	case OITAB:
-		Naddr(n.Left, a, canemitcode)
+		Naddr(a, n.Left)
 
 		if a.Type == obj.TYPE_CONST && a.Offset == 0 {
 			break // itab(nil)
@@ -444,7 +449,7 @@
 
 		// pointer in a string or slice
 	case OSPTR:
-		Naddr(n.Left, a, canemitcode)
+		Naddr(a, n.Left)
 
 		if a.Type == obj.TYPE_CONST && a.Offset == 0 {
 			break // ptr(nil)
@@ -455,13 +460,13 @@
 
 		// len of string or slice
 	case OLEN:
-		Naddr(n.Left, a, canemitcode)
+		Naddr(a, n.Left)
 
 		if a.Type == obj.TYPE_CONST && a.Offset == 0 {
 			break // len(nil)
 		}
 		a.Etype = Simtype[TUINT]
-		if Thearch.Thechar == '9' {
+		if Thearch.Thechar == '7' || Thearch.Thechar == '9' {
 			a.Etype = Simtype[TINT]
 		}
 		a.Offset += int64(Array_nel)
@@ -471,13 +476,13 @@
 
 		// cap of string or slice
 	case OCAP:
-		Naddr(n.Left, a, canemitcode)
+		Naddr(a, n.Left)
 
 		if a.Type == obj.TYPE_CONST && a.Offset == 0 {
 			break // cap(nil)
 		}
 		a.Etype = Simtype[TUINT]
-		if Thearch.Thechar == '9' {
+		if Thearch.Thechar == '7' || Thearch.Thechar == '9' {
 			a.Etype = Simtype[TINT]
 		}
 		a.Offset += int64(Array_cap)
@@ -485,6 +490,7 @@
 			a.Width = int64(Widthint)
 		}
 	}
+	return
 }
 
 func newplist() *obj.Plist {
@@ -524,7 +530,7 @@
 
 	if fp == 1 {
 		var n *Node
-		for l := Curfn.Dcl; l != nil; l = l.Next {
+		for l := Curfn.Func.Dcl; l != nil; l = l.Next {
 			n = l.N
 			if (n.Class == PPARAM || n.Class == PPARAMOUT) && !isblanksym(t.Sym) && n.Sym == t.Sym {
 				return n
@@ -556,11 +562,8 @@
 		n.Op = OINDREG
 
 		n.Val.U.Reg = int16(Thearch.REGSP)
-		if Thearch.Thechar == '5' {
-			n.Xoffset += 4
-		}
-		if Thearch.Thechar == '9' {
-			n.Xoffset += 8
+		if HasLinkRegister() {
+			n.Xoffset += int64(Ctxt.Arch.Ptrsize)
 		}
 
 	case 1: // input arg
@@ -568,10 +571,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
@@ -582,7 +581,7 @@
 	if p.To.Type != obj.TYPE_BRANCH {
 		Fatal("patch: not a branch")
 	}
-	p.To.U.Branch = to
+	p.To.Val = to
 	p.To.Offset = to.Pc
 }
 
@@ -590,8 +589,237 @@
 	if p.To.Type != obj.TYPE_BRANCH {
 		Fatal("unpatch: not a branch")
 	}
-	q := p.To.U.Branch
-	p.To.U.Branch = nil
+	q, _ := p.To.Val.(*obj.Prog)
+	p.To.Val = nil
 	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 Thearch.Thechar == '8' && !Use_sse {
+			i = Thearch.FREGMIN // x86.REG_F0
+			break Switch
+		}
+		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/init.go b/src/cmd/internal/gc/init.go
index 3c27bd6..b3a6a00 100644
--- a/src/cmd/internal/gc/init.go
+++ b/src/cmd/internal/gc/init.go
@@ -4,8 +4,6 @@
 
 package gc
 
-import "fmt"
-
 //	case OADD:
 //		if(n->right->op == OLITERAL) {
 //			v = n->right->vconst;
@@ -31,8 +29,7 @@
 
 func renameinit() *Sym {
 	renameinit_initgen++
-	namebuf = fmt.Sprintf("init.%d", renameinit_initgen)
-	return Lookup(namebuf)
+	return Lookupf("init.%d", renameinit_initgen)
 }
 
 /*
@@ -57,10 +54,7 @@
 	// are there any interesting init statements
 	for l := n; l != nil; l = l.Next {
 		switch l.N.Op {
-		case ODCLFUNC,
-			ODCLCONST,
-			ODCLTYPE,
-			OEMPTY:
+		case ODCLFUNC, ODCLCONST, ODCLTYPE, OEMPTY:
 			break
 
 		case OAS:
@@ -88,14 +82,8 @@
 	}
 
 	// are there any imported init functions
-	for h := uint32(0); h < NHASH; h++ {
-		for s = hash[h]; s != nil; s = s.Link {
-			if s.Name[0] != 'i' || s.Name != "init" {
-				continue
-			}
-			if s.Def == nil {
-				continue
-			}
+	for _, s := range initSyms {
+		if s.Def != nil {
 			return true
 		}
 	}
@@ -115,21 +103,17 @@
 		return
 	}
 
-	r := (*NodeList)(nil)
+	var r *NodeList
 
 	// (1)
-	namebuf = "initdone·"
-
-	gatevar := newname(Lookup(namebuf))
+	gatevar := newname(Lookup("initdone·"))
 	addvar(gatevar, Types[TUINT8], PEXTERN)
 
 	// (2)
 	Maxarg = 0
 
-	namebuf = "init"
-
 	fn := Nod(ODCLFUNC, nil, nil)
-	initsym := Lookup(namebuf)
+	initsym := Lookup("init")
 	fn.Nname = newname(initsym)
 	fn.Nname.Defn = fn
 	fn.Nname.Ntype = Nod(OTFUNC, nil, nil)
@@ -161,22 +145,10 @@
 	r = list(r, a)
 
 	// (7)
-	var s *Sym
-	for h := uint32(0); h < NHASH; h++ {
-		for s = hash[h]; s != nil; s = s.Link {
-			if s.Name[0] != 'i' || s.Name != "init" {
-				continue
-			}
-			if s.Def == nil {
-				continue
-			}
-			if s == initsym {
-				continue
-			}
-
+	for _, s := range initSyms {
+		if s.Def != nil && s != initsym {
 			// could check that it is fn of no args/returns
 			a = Nod(OCALL, s.Def, nil)
-
 			r = list(r, a)
 		}
 	}
@@ -187,8 +159,7 @@
 	// (9)
 	// could check that it is fn of no args/returns
 	for i := 1; ; i++ {
-		namebuf = fmt.Sprintf("init.%d", i)
-		s = Lookup(namebuf)
+		s := Lookupf("init.%d", i)
 		if s.Def == nil {
 			break
 		}
diff --git a/src/cmd/internal/gc/inl.go b/src/cmd/internal/gc/inl.go
index 57a0ab6..7ba94b5 100644
--- a/src/cmd/internal/gc/inl.go
+++ b/src/cmd/internal/gc/inl.go
@@ -50,7 +50,7 @@
 		// method
 		rcvr := getthisx(fn.Type).Type.Type
 
-		if Isptr[rcvr.Etype] != 0 {
+		if Isptr[rcvr.Etype] {
 			rcvr = rcvr.Type
 		}
 		if rcvr.Sym == nil {
@@ -79,7 +79,7 @@
 	}
 
 	if Debug['m'] > 2 {
-		fmt.Printf("typecheck import [%v] %v { %v }\n", Sconv(fn.Sym, 0), Nconv(fn, obj.FmtLong), Hconv(fn.Inl, obj.FmtSharp))
+		fmt.Printf("typecheck import [%v] %v { %v }\n", Sconv(fn.Sym, 0), Nconv(fn, obj.FmtLong), Hconv(fn.Func.Inl, obj.FmtSharp))
 	}
 
 	save_safemode := safemode
@@ -87,7 +87,7 @@
 
 	savefn := Curfn
 	Curfn = fn
-	typechecklist(fn.Inl, Etop)
+	typechecklist(fn.Func.Inl, Etop)
 	Curfn = savefn
 
 	safemode = save_safemode
@@ -118,7 +118,7 @@
 	// can't handle ... args yet
 	if Debug['l'] < 3 {
 		for t := fn.Type.Type.Down.Down.Type; t != nil; t = t.Down {
-			if t.Isddd != 0 {
+			if t.Isddd {
 				return
 			}
 		}
@@ -133,17 +133,17 @@
 	savefn := Curfn
 	Curfn = fn
 
-	fn.Nname.Inl = fn.Nbody
-	fn.Nbody = inlcopylist(fn.Nname.Inl)
-	fn.Nname.Inldcl = inlcopylist(fn.Nname.Defn.Dcl)
-	fn.Nname.InlCost = int32(maxBudget - budget)
+	fn.Nname.Func.Inl = fn.Nbody
+	fn.Nbody = inlcopylist(fn.Nname.Func.Inl)
+	fn.Nname.Func.Inldcl = inlcopylist(fn.Nname.Defn.Func.Dcl)
+	fn.Nname.Func.InlCost = int32(maxBudget - budget)
 
 	// hack, TODO, check for better way to link method nodes back to the thing with the ->inl
 	// this is so export can find the body of a method
 	fn.Type.Nname = fn.Nname
 
 	if Debug['m'] > 1 {
-		fmt.Printf("%v: can inline %v as: %v { %v }\n", fn.Line(), Nconv(fn.Nname, obj.FmtSharp), Tconv(fn.Type, obj.FmtSharp), Hconv(fn.Nname.Inl, obj.FmtSharp))
+		fmt.Printf("%v: can inline %v as: %v { %v }\n", fn.Line(), Nconv(fn.Nname, obj.FmtSharp), Tconv(fn.Type, obj.FmtSharp), Hconv(fn.Nname.Func.Inl, obj.FmtSharp))
 	} else if Debug['m'] != 0 {
 		fmt.Printf("%v: can inline %v\n", fn.Line(), Nconv(fn.Nname, 0))
 	}
@@ -169,13 +169,13 @@
 	switch n.Op {
 	// Call is okay if inlinable and we have the budget for the body.
 	case OCALLFUNC:
-		if n.Left.Inl != nil {
-			*budget -= int(n.Left.InlCost)
+		if n.Left.Func != nil && n.Left.Func.Inl != nil {
+			*budget -= int(n.Left.Func.InlCost)
 			break
 		}
 		if n.Left.Op == ONAME && n.Left.Left != nil && n.Left.Left.Op == OTYPE && n.Left.Right != nil && n.Left.Right.Op == ONAME { // methods called as functions
-			if n.Left.Sym.Def != nil && n.Left.Sym.Def.Inl != nil {
-				*budget -= int(n.Left.Sym.Def.InlCost)
+			if n.Left.Sym.Def != nil && n.Left.Sym.Def.Func.Inl != nil {
+				*budget -= int(n.Left.Sym.Def.Func.InlCost)
 				break
 			}
 		}
@@ -191,8 +191,8 @@
 		if n.Left.Type.Nname == nil {
 			Fatal("no function definition for [%p] %v\n", n.Left.Type, Tconv(n.Left.Type, obj.FmtSign))
 		}
-		if n.Left.Type.Nname.Inl != nil {
-			*budget -= int(n.Left.Type.Nname.InlCost)
+		if n.Left.Type.Nname.Func.Inl != nil {
+			*budget -= int(n.Left.Type.Nname.Func.InlCost)
 			break
 		}
 		if Debug['l'] < 4 {
@@ -200,10 +200,7 @@
 		}
 
 	// Things that are too hairy, irrespective of the budget
-	case OCALL,
-		OCALLINTER,
-		OPANIC,
-		ORECOVER:
+	case OCALL, OCALLINTER, OPANIC, ORECOVER:
 		if Debug['l'] < 4 {
 			return true
 		}
@@ -231,7 +228,7 @@
 // Any name-like node of non-local class is marked for re-export by adding it to
 // the exportlist.
 func inlcopylist(ll *NodeList) *NodeList {
-	l := (*NodeList)(nil)
+	var l *NodeList
 	for ; ll != nil; ll = ll.Next {
 		l = list(l, inlcopy(ll.N))
 	}
@@ -244,15 +241,15 @@
 	}
 
 	switch n.Op {
-	case ONAME,
-		OTYPE,
-		OLITERAL:
+	case ONAME, OTYPE, OLITERAL:
 		return n
 	}
 
 	m := Nod(OXXX, nil, nil)
 	*m = *n
-	m.Inl = nil
+	if m.Func != nil {
+		m.Func.Inl = nil
+	}
 	m.Left = inlcopy(n.Left)
 	m.Right = inlcopy(n.Right)
 	m.List = inlcopylist(n.List)
@@ -338,11 +335,9 @@
 
 	switch n.Op {
 	// inhibit inlining of their argument
-	case ODEFER,
-		OPROC:
+	case ODEFER, OPROC:
 		switch n.Left.Op {
-		case OCALLFUNC,
-			OCALLMETH:
+		case OCALLFUNC, OCALLMETH:
 			n.Left.Etype = n.Op
 		}
 		fallthrough
@@ -453,8 +448,7 @@
 	// transmogrify this node itself unless inhibited by the
 	// switch at the top of this function.
 	switch n.Op {
-	case OCALLFUNC,
-		OCALLMETH:
+	case OCALLFUNC, OCALLMETH:
 		if n.Etype == OPROC || n.Etype == ODEFER {
 			return
 		}
@@ -465,11 +459,11 @@
 		if Debug['m'] > 3 {
 			fmt.Printf("%v:call to func %v\n", n.Line(), Nconv(n.Left, obj.FmtSign))
 		}
-		if n.Left.Inl != nil { // normal case
-			mkinlcall(np, n.Left, int(n.Isddd))
+		if n.Left.Func != nil && n.Left.Func.Inl != nil { // normal case
+			mkinlcall(np, n.Left, n.Isddd)
 		} else if n.Left.Op == ONAME && n.Left.Left != nil && n.Left.Left.Op == OTYPE && n.Left.Right != nil && n.Left.Right.Op == ONAME { // methods called as functions
 			if n.Left.Sym.Def != nil {
-				mkinlcall(np, n.Left.Sym.Def, int(n.Isddd))
+				mkinlcall(np, n.Left.Sym.Def, n.Isddd)
 			}
 		}
 
@@ -487,13 +481,13 @@
 			Fatal("no function definition for [%p] %v\n", n.Left.Type, Tconv(n.Left.Type, obj.FmtSign))
 		}
 
-		mkinlcall(np, n.Left.Type.Nname, int(n.Isddd))
+		mkinlcall(np, n.Left.Type.Nname, n.Isddd)
 	}
 
 	lineno = int32(lno)
 }
 
-func mkinlcall(np **Node, fn *Node, isddd int) {
+func mkinlcall(np **Node, fn *Node, isddd bool) {
 	save_safemode := safemode
 
 	// imported functions may refer to unsafe as long as the
@@ -525,9 +519,9 @@
 // On return ninit has the parameter assignments, the nbody is the
 // inlined function body and list, rlist contain the input, output
 // parameters.
-func mkinlcall1(np **Node, fn *Node, isddd int) {
+func mkinlcall1(np **Node, fn *Node, isddd bool) {
 	// For variadic fn.
-	if fn.Inl == nil {
+	if fn.Func.Inl == nil {
 		return
 	}
 
@@ -543,7 +537,7 @@
 
 	// Bingo, we have a function node, and it has an inlineable body
 	if Debug['m'] > 1 {
-		fmt.Printf("%v: inlining call to %v %v { %v }\n", n.Line(), Sconv(fn.Sym, 0), Tconv(fn.Type, obj.FmtSharp), Hconv(fn.Inl, obj.FmtSharp))
+		fmt.Printf("%v: inlining call to %v %v { %v }\n", n.Line(), Sconv(fn.Sym, 0), Tconv(fn.Type, obj.FmtSharp), Hconv(fn.Func.Inl, obj.FmtSharp))
 	} else if Debug['m'] != 0 {
 		fmt.Printf("%v: inlining call to %v\n", n.Line(), Nconv(fn, 0))
 	}
@@ -561,9 +555,9 @@
 
 	var dcl *NodeList
 	if fn.Defn != nil { // local function
-		dcl = fn.Inldcl // imported function
+		dcl = fn.Func.Inldcl // imported function
 	} else {
-		dcl = fn.Dcl
+		dcl = fn.Func.Dcl
 	}
 
 	inlretvars = nil
@@ -628,17 +622,17 @@
 	// check if inlined function is variadic.
 	variadic := false
 
-	varargtype := (*Type)(nil)
+	var varargtype *Type
 	varargcount := 0
 	for t := fn.Type.Type.Down.Down.Type; t != nil; t = t.Down {
-		if t.Isddd != 0 {
+		if t.Isddd {
 			variadic = true
 			varargtype = t.Type
 		}
 	}
 
 	// but if argument is dotted too forget about variadicity.
-	if variadic && isddd != 0 {
+	if variadic && isddd {
 		variadic = false
 	}
 
@@ -647,10 +641,7 @@
 
 	if n.List != nil && n.List.Next == nil {
 		switch n.List.N.Op {
-		case OCALL,
-			OCALLFUNC,
-			OCALLINTER,
-			OCALLMETH:
+		case OCALL, OCALLFUNC, OCALLINTER, OCALLMETH:
 			if n.List.N.Left.Type.Outtuple > 1 {
 				multiret = n.List.N.Left.Type.Outtuple - 1
 			}
@@ -694,13 +685,13 @@
 	// append ordinary arguments to LHS.
 	chkargcount := n.List != nil && n.List.Next != nil
 
-	vararg := (*Node)(nil)      // the slice argument to a variadic call
-	varargs := (*NodeList)(nil) // the list of LHS names to put in vararg.
+	var vararg *Node      // the slice argument to a variadic call
+	var varargs *NodeList // the list of LHS names to put in vararg.
 	if !chkargcount {
 		// 0 or 1 expression on RHS.
 		var i int
 		for t := getinargx(fn.Type).Type; t != nil; t = t.Down {
-			if variadic && t.Isddd != 0 {
+			if variadic && t.Isddd {
 				vararg = tinlvar(t)
 				for i = 0; i < varargcount && ll != nil; i++ {
 					m = argvar(varargtype, i)
@@ -720,7 +711,7 @@
 			if ll == nil {
 				break
 			}
-			if variadic && t.Isddd != 0 {
+			if variadic && t.Isddd {
 				break
 			}
 			as.List = list(as.List, tinlvar(t))
@@ -729,7 +720,7 @@
 		}
 
 		// match varargcount arguments with variadic parameters.
-		if variadic && t != nil && t.Isddd != 0 {
+		if variadic && t != nil && t.Isddd {
 			vararg = tinlvar(t)
 			var i int
 			for i = 0; i < varargcount && ll != nil; i++ {
@@ -783,7 +774,7 @@
 
 	inlretlabel = newlabel_inl()
 	inlgen++
-	body := inlsubstlist(fn.Inl)
+	body := inlsubstlist(fn.Func.Inl)
 
 	body = list(body, Nod(OGOTO, inlretlabel, nil)) // avoid 'not used' when function doesnt have return
 	body = list(body, Nod(OLABEL, inlretlabel, nil))
@@ -814,15 +805,15 @@
 	// instead we emit the things that the body needs
 	// and each use must redo the inlining.
 	// luckily these are small.
-	body = fn.Inl
-	fn.Inl = nil // prevent infinite recursion (shouldn't happen anyway)
+	body = fn.Func.Inl
+	fn.Func.Inl = nil // prevent infinite recursion (shouldn't happen anyway)
 	inlnodelist(call.Nbody)
 	for ll := call.Nbody; ll != nil; ll = ll.Next {
 		if ll.N.Op == OINLCALL {
 			inlconv2stmt(ll.N)
 		}
 	}
-	fn.Inl = body
+	fn.Func.Inl = body
 
 	if Debug['m'] > 2 {
 		fmt.Printf("%v: After inlining %v\n\n", n.Line(), Nconv(*np, obj.FmtSign))
@@ -840,7 +831,7 @@
 	n := newname(var_.Sym)
 	n.Type = var_.Type
 	n.Class = PAUTO
-	n.Used = 1
+	n.Used = true
 	n.Curfn = Curfn // the calling function, not the called one
 	n.Addrtaken = var_.Addrtaken
 
@@ -853,32 +844,30 @@
 		addrescapes(n)
 	}
 
-	Curfn.Dcl = list(Curfn.Dcl, n)
+	Curfn.Func.Dcl = list(Curfn.Func.Dcl, n)
 	return n
 }
 
 // Synthesize a variable to store the inlined function's results in.
 func retvar(t *Type, i int) *Node {
-	namebuf = fmt.Sprintf("~r%d", i)
-	n := newname(Lookup(namebuf))
+	n := newname(Lookupf("~r%d", i))
 	n.Type = t.Type
 	n.Class = PAUTO
-	n.Used = 1
+	n.Used = true
 	n.Curfn = Curfn // the calling function, not the called one
-	Curfn.Dcl = list(Curfn.Dcl, n)
+	Curfn.Func.Dcl = list(Curfn.Func.Dcl, n)
 	return n
 }
 
 // Synthesize a variable to store the inlined function's arguments
 // when they come from a multiple return call.
 func argvar(t *Type, i int) *Node {
-	namebuf = fmt.Sprintf("~arg%d", i)
-	n := newname(Lookup(namebuf))
+	n := newname(Lookupf("~arg%d", i))
 	n.Type = t.Type
 	n.Class = PAUTO
-	n.Used = 1
+	n.Used = true
 	n.Curfn = Curfn // the calling function, not the called one
-	Curfn.Dcl = list(Curfn.Dcl, n)
+	Curfn.Func.Dcl = list(Curfn.Func.Dcl, n)
 	return n
 }
 
@@ -886,8 +875,7 @@
 
 func newlabel_inl() *Node {
 	newlabel_inl_label++
-	namebuf = fmt.Sprintf(".inlret%.6d", newlabel_inl_label)
-	n := newname(Lookup(namebuf))
+	n := newname(Lookupf(".inlret%.6d", newlabel_inl_label))
 	n.Etype = 1 // flag 'safe' for escape analysis (no backjumps)
 	return n
 }
@@ -897,7 +885,7 @@
 // to input/output parameters with ones to the tmpnames, and
 // substituting returns with assignments to the output.
 func inlsubstlist(ll *NodeList) *NodeList {
-	l := (*NodeList)(nil)
+	var l *NodeList
 	for ; ll != nil; ll = ll.Next {
 		l = list(l, inlsubst(ll.N))
 	}
@@ -923,8 +911,7 @@
 		}
 		return n
 
-	case OLITERAL,
-		OTYPE:
+	case OLITERAL, OTYPE:
 		return n
 
 		// Since we don't handle bodies with closures, this return is guaranteed to belong to the current inlined function.
@@ -953,8 +940,7 @@
 		//		dump("Return after substitution", m);
 		return m
 
-	case OGOTO,
-		OLABEL:
+	case OGOTO, OLABEL:
 		m := Nod(OXXX, nil, nil)
 		*m = *n
 		m.Ninit = nil
diff --git a/src/cmd/internal/gc/lex.go b/src/cmd/internal/gc/lex.go
index 4e5f011..cc25929 100644
--- a/src/cmd/internal/gc/lex.go
+++ b/src/cmd/internal/gc/lex.go
@@ -43,10 +43,11 @@
 var debugtab = []struct {
 	name string
 	val  *int
-}{struct {
-	name string
-	val  *int
-}{"nil", &Debug_checknil}}
+}{
+	{"nil", &Debug_checknil},          // print information about nil checks
+	{"typeassert", &Debug_typeassert}, // print information about type assertion inlining
+	{"disablenil", &Disable_checknil}, // disable nil checks
+}
 
 // Our own isdigit, isspace, isalpha, isalnum that take care
 // of EOF and other out of range arguments.
@@ -121,50 +122,50 @@
 	Ctxt.Bso = &bstdout
 	bstdout = *obj.Binitw(os.Stdout)
 
-	localpkg = mkpkg(newstrlit(""))
+	localpkg = mkpkg("")
 	localpkg.Prefix = "\"\""
 
 	// pseudo-package, for scoping
-	builtinpkg = mkpkg(newstrlit("go.builtin"))
+	builtinpkg = mkpkg("go.builtin")
 
 	builtinpkg.Prefix = "go.builtin" // not go%2ebuiltin
 
 	// pseudo-package, accessed by import "unsafe"
-	unsafepkg = mkpkg(newstrlit("unsafe"))
+	unsafepkg = mkpkg("unsafe")
 
 	unsafepkg.Name = "unsafe"
 
 	// real package, referred to by generated runtime calls
-	Runtimepkg = mkpkg(newstrlit("runtime"))
+	Runtimepkg = mkpkg("runtime")
 
 	Runtimepkg.Name = "runtime"
 
 	// pseudo-packages used in symbol tables
-	gostringpkg = mkpkg(newstrlit("go.string"))
+	gostringpkg = mkpkg("go.string")
 
 	gostringpkg.Name = "go.string"
 	gostringpkg.Prefix = "go.string" // not go%2estring
 
-	itabpkg = mkpkg(newstrlit("go.itab"))
+	itabpkg = mkpkg("go.itab")
 
 	itabpkg.Name = "go.itab"
 	itabpkg.Prefix = "go.itab" // not go%2eitab
 
-	weaktypepkg = mkpkg(newstrlit("go.weak.type"))
+	weaktypepkg = mkpkg("go.weak.type")
 
 	weaktypepkg.Name = "go.weak.type"
 	weaktypepkg.Prefix = "go.weak.type" // not go%2eweak%2etype
 
-	typelinkpkg = mkpkg(newstrlit("go.typelink"))
+	typelinkpkg = mkpkg("go.typelink")
 	typelinkpkg.Name = "go.typelink"
 	typelinkpkg.Prefix = "go.typelink" // not go%2etypelink
 
-	trackpkg = mkpkg(newstrlit("go.track"))
+	trackpkg = mkpkg("go.track")
 
 	trackpkg.Name = "go.track"
 	trackpkg.Prefix = "go.track" // not go%2etrack
 
-	typepkg = mkpkg(newstrlit("type"))
+	typepkg = mkpkg("type")
 
 	typepkg.Name = "type"
 
@@ -221,13 +222,16 @@
 	obj.Flagcount("wb", "enable write barrier", &use_writebarrier)
 	obj.Flagcount("x", "debug lexer", &Debug['x'])
 	obj.Flagcount("y", "debug declarations in canned imports (with -d)", &Debug['y'])
+	var flag_shared int
 	if Thearch.Thechar == '6' {
 		obj.Flagcount("largemodel", "generate code that assumes a large memory model", &flag_largemodel)
+		obj.Flagcount("shared", "generate code that can be linked into a shared library", &flag_shared)
 	}
 
 	obj.Flagstr("cpuprofile", "file: write cpu profile to file", &cpuprofile)
 	obj.Flagstr("memprofile", "file: write memory profile to file", &memprofile)
 	obj.Flagparse(usage)
+	Ctxt.Flag_shared = int32(flag_shared)
 	Ctxt.Debugasm = int32(Debug['S'])
 	Ctxt.Debugvlog = int32(Debug['v'])
 
@@ -238,7 +242,7 @@
 	startProfile()
 
 	if flag_race != 0 {
-		racepkg = mkpkg(newstrlit("runtime/race"))
+		racepkg = mkpkg("runtime/race")
 		racepkg.Name = "race"
 	}
 
@@ -274,13 +278,13 @@
 	}
 
 	if Thearch.Thechar == '8' {
-		p := obj.Getgo386()
-		if p == "387" {
-			Use_sse = 0
-		} else if p == "sse2" {
-			Use_sse = 1
-		} else {
-			log.Fatalf("unsupported setting GO386=%s", p)
+		switch v := obj.Getgo386(); v {
+		case "387":
+			Use_sse = false
+		case "sse2":
+			Use_sse = true
+		default:
+			log.Fatalf("unsupported setting GO386=%s", v)
 		}
 	}
 
@@ -403,7 +407,7 @@
 		// Typecheck imported function bodies if debug['l'] > 1,
 		// otherwise lazily when used or re-exported.
 		for l := importlist; l != nil; l = l.Next {
-			if l.N.Inl != nil {
+			if l.N.Func.Inl != nil {
 				saveerrors()
 				typecheckinl(l.N)
 			}
@@ -549,32 +553,31 @@
 }
 
 // is this path a local name?  begins with ./ or ../ or /
-func islocalname(name *Strlit) bool {
-	return strings.HasPrefix(name.S, "/") ||
-		Ctxt.Windows != 0 && len(name.S) >= 3 && yy_isalpha(int(name.S[0])) && name.S[1] == ':' && name.S[2] == '/' ||
-		strings.HasPrefix(name.S, "./") || name.S == "." ||
-		strings.HasPrefix(name.S, "../") || name.S == ".."
+func islocalname(name string) bool {
+	return strings.HasPrefix(name, "/") ||
+		Ctxt.Windows != 0 && len(name) >= 3 && yy_isalpha(int(name[0])) && name[1] == ':' && name[2] == '/' ||
+		strings.HasPrefix(name, "./") || name == "." ||
+		strings.HasPrefix(name, "../") || name == ".."
 }
 
-func findpkg(name *Strlit) bool {
+func findpkg(name string) (file string, ok bool) {
 	if islocalname(name) {
 		if safemode != 0 || nolocalimports != 0 {
-			return false
+			return "", false
 		}
 
 		// try .a before .6.  important for building libraries:
 		// if there is an array.6 in the array.a library,
 		// want to find all of array.a, not just array.6.
-		namebuf = fmt.Sprintf("%v.a", Zconv(name, 0))
-
-		if obj.Access(namebuf, 0) >= 0 {
-			return true
+		file = fmt.Sprintf("%s.a", name)
+		if obj.Access(file, 0) >= 0 {
+			return file, true
 		}
-		namebuf = fmt.Sprintf("%v.%c", Zconv(name, 0), Thearch.Thechar)
-		if obj.Access(namebuf, 0) >= 0 {
-			return true
+		file = fmt.Sprintf("%s.%c", name, Thearch.Thechar)
+		if obj.Access(file, 0) >= 0 {
+			return file, true
 		}
-		return false
+		return "", false
 	}
 
 	// local imports should be canonicalized already.
@@ -582,19 +585,19 @@
 	// as different from "encoding/base64".
 	var q string
 	_ = q
-	if path.Clean(name.S) != name.S {
-		Yyerror("non-canonical import path %v (should be %s)", Zconv(name, 0), q)
-		return false
+	if path.Clean(name) != name {
+		Yyerror("non-canonical import path %q (should be %q)", name, q)
+		return "", false
 	}
 
 	for p := idirs; p != nil; p = p.link {
-		namebuf = fmt.Sprintf("%s/%v.a", p.dir, Zconv(name, 0))
-		if obj.Access(namebuf, 0) >= 0 {
-			return true
+		file = fmt.Sprintf("%s/%s.a", p.dir, name)
+		if obj.Access(file, 0) >= 0 {
+			return file, true
 		}
-		namebuf = fmt.Sprintf("%s/%v.%c", p.dir, Zconv(name, 0), Thearch.Thechar)
-		if obj.Access(namebuf, 0) >= 0 {
-			return true
+		file = fmt.Sprintf("%s/%s.%c", p.dir, name, Thearch.Thechar)
+		if obj.Access(file, 0) >= 0 {
+			return file, true
 		}
 	}
 
@@ -609,21 +612,21 @@
 			suffix = "race"
 		}
 
-		namebuf = fmt.Sprintf("%s/pkg/%s_%s%s%s/%v.a", goroot, goos, goarch, suffixsep, suffix, Zconv(name, 0))
-		if obj.Access(namebuf, 0) >= 0 {
-			return true
+		file = fmt.Sprintf("%s/pkg/%s_%s%s%s/%s.a", goroot, goos, goarch, suffixsep, suffix, name)
+		if obj.Access(file, 0) >= 0 {
+			return file, true
 		}
-		namebuf = fmt.Sprintf("%s/pkg/%s_%s%s%s/%v.%c", goroot, goos, goarch, suffixsep, suffix, Zconv(name, 0), Thearch.Thechar)
-		if obj.Access(namebuf, 0) >= 0 {
-			return true
+		file = fmt.Sprintf("%s/pkg/%s_%s%s%s/%s.%c", goroot, goos, goarch, suffixsep, suffix, name, Thearch.Thechar)
+		if obj.Access(file, 0) >= 0 {
+			return file, true
 		}
 	}
 
-	return false
+	return "", false
 }
 
 func fakeimport() {
-	importpkg = mkpkg(newstrlit("fake"))
+	importpkg = mkpkg("fake")
 	cannedimports("fake.6", "$$\n")
 }
 
@@ -634,7 +637,7 @@
 		return
 	}
 
-	if len(f.U.Sval.S) == 0 {
+	if len(f.U.Sval) == 0 {
 		Yyerror("import path is empty")
 		fakeimport()
 		return
@@ -649,17 +652,17 @@
 	// but we reserve the import path "main" to identify
 	// the main package, just as we reserve the import
 	// path "math" to identify the standard math package.
-	if f.U.Sval.S == "main" {
+	if f.U.Sval == "main" {
 		Yyerror("cannot import \"main\"")
 		errorexit()
 	}
 
-	if myimportpath != "" && f.U.Sval.S == myimportpath {
-		Yyerror("import \"%v\" while compiling that package (import cycle)", Zconv(f.U.Sval, 0))
+	if myimportpath != "" && f.U.Sval == myimportpath {
+		Yyerror("import %q while compiling that package (import cycle)", f.U.Sval)
 		errorexit()
 	}
 
-	if f.U.Sval.S == "unsafe" {
+	if f.U.Sval == "unsafe" {
 		if safemode != 0 {
 			Yyerror("cannot import package unsafe")
 			errorexit()
@@ -673,7 +676,7 @@
 
 	path_ := f.U.Sval
 	if islocalname(path_) {
-		if path_.S[0] == '/' {
+		if path_[0] == '/' {
 			Yyerror("import path cannot be absolute path")
 			fakeimport()
 			return
@@ -685,9 +688,9 @@
 		}
 		cleanbuf := prefix
 		cleanbuf += "/"
-		cleanbuf += path_.S
+		cleanbuf += path_
 		cleanbuf = path.Clean(cleanbuf)
-		path_ = newstrlit(cleanbuf)
+		path_ = cleanbuf
 
 		if isbadimport(path_) {
 			fakeimport()
@@ -695,8 +698,9 @@
 		}
 	}
 
-	if !findpkg(path_) {
-		Yyerror("can't find import: \"%v\"", Zconv(f.U.Sval, 0))
+	file, found := findpkg(path_)
+	if !found {
+		Yyerror("can't find import: %q", f.U.Sval)
 		errorexit()
 	}
 
@@ -705,7 +709,6 @@
 	// If we already saw that package, feed a dummy statement
 	// to the lexer to avoid parsing export data twice.
 	if importpkg.Imported != 0 {
-		file := namebuf
 		tag := ""
 		if importpkg.Safe {
 			tag = "safe"
@@ -720,16 +723,13 @@
 
 	var err error
 	var imp *obj.Biobuf
-	imp, err = obj.Bopenr(namebuf)
+	imp, err = obj.Bopenr(file)
 	if err != nil {
-		Yyerror("can't open import: \"%v\": %v", Zconv(f.U.Sval, 0), err)
+		Yyerror("can't open import: %q: %v", f.U.Sval, err)
 		errorexit()
 	}
 
-	file := namebuf
-
-	n := len(namebuf)
-	if n > 2 && namebuf[n-2] == '.' && namebuf[n-1] == 'a' {
+	if strings.HasSuffix(file, ".a") {
 		if !skiptopkgdef(imp) {
 			Yyerror("import %s: not a package file", file)
 			errorexit()
@@ -754,7 +754,7 @@
 
 	// assume files move (get installed)
 	// so don't record the full path.
-	linehist(file[n-len(path_.S)-2:], -1, 1) // acts as #pragma lib
+	linehist(file[len(file)-len(path_)-2:], -1, 1) // acts as #pragma lib
 
 	/*
 	 * position the input right
@@ -788,7 +788,7 @@
 		return
 	}
 
-	Yyerror("no import in \"%v\"", Zconv(f.U.Sval, 0))
+	Yyerror("no import in %q", f.U.Sval)
 	unimportfile()
 }
 
@@ -844,7 +844,6 @@
 var _yylex_lstk *Loophack
 
 func _yylex(yylval *yySymType) int32 {
-	var c int
 	var c1 int
 	var escflag int
 	var v int64
@@ -857,7 +856,7 @@
 	prevlineno = lineno
 
 l0:
-	c = getc()
+	c := getc()
 	if yy_isspace(c) {
 		if c == '\n' && curio.nlsemi != 0 {
 			ungetc(c)
@@ -887,7 +886,82 @@
 	}
 
 	if yy_isdigit(c) {
-		goto tnum
+		cp = &lexbuf
+		cp.Reset()
+		if c != '0' {
+			for {
+				cp.WriteByte(byte(c))
+				c = getc()
+				if yy_isdigit(c) {
+					continue
+				}
+				if c == '.' {
+					goto casedot
+				}
+				if c == 'e' || c == 'E' || c == 'p' || c == 'P' {
+					goto caseep
+				}
+				if c == 'i' {
+					goto casei
+				}
+				goto ncu
+			}
+		}
+
+		cp.WriteByte(byte(c))
+		c = getc()
+		if c == 'x' || c == 'X' {
+			for {
+				cp.WriteByte(byte(c))
+				c = getc()
+				if yy_isdigit(c) {
+					continue
+				}
+				if c >= 'a' && c <= 'f' {
+					continue
+				}
+				if c >= 'A' && c <= 'F' {
+					continue
+				}
+				if lexbuf.Len() == 2 {
+					Yyerror("malformed hex constant")
+				}
+				if c == 'p' {
+					goto caseep
+				}
+				goto ncu
+			}
+		}
+
+		if c == 'p' { // 0p begins floating point zero
+			goto caseep
+		}
+
+		c1 = 0
+		for {
+			if !yy_isdigit(c) {
+				break
+			}
+			if c < '0' || c > '7' {
+				c1 = 1 // not octal
+			}
+			cp.WriteByte(byte(c))
+			c = getc()
+		}
+
+		if c == '.' {
+			goto casedot
+		}
+		if c == 'e' || c == 'E' {
+			goto caseep
+		}
+		if c == 'i' {
+			goto casei
+		}
+		if c1 != 0 {
+			Yyerror("malformed octal constant")
+		}
+		goto ncu
 	}
 
 	switch c {
@@ -1203,8 +1277,7 @@
 		 *
 		 * i said it was clumsy.
 		 */
-	case '(',
-		'[':
+	case '(', '[':
 		if loophack != 0 || _yylex_lstk != nil {
 			h = new(Loophack)
 			if h == nil {
@@ -1221,8 +1294,7 @@
 
 		goto lx
 
-	case ')',
-		']':
+	case ')', ']':
 		if _yylex_lstk != nil {
 			h = _yylex_lstk
 			loophack = h.v
@@ -1303,15 +1375,12 @@
 	cp = nil
 	ungetc(c)
 
-	s = Lookup(lexbuf.String())
+	s = LookupBytes(lexbuf.Bytes())
 	switch s.Lexical {
 	case LIGNORE:
 		goto l0
 
-	case LFOR,
-		LIF,
-		LSWITCH,
-		LSELECT:
+	case LFOR, LIF, LSWITCH, LSELECT:
 		loophack = 1 // see comment about loophack above
 	}
 
@@ -1321,86 +1390,6 @@
 	yylval.sym = s
 	return int32(s.Lexical)
 
-tnum:
-	cp = &lexbuf
-	cp.Reset()
-	if c != '0' {
-		for {
-			cp.WriteByte(byte(c))
-			c = getc()
-			if yy_isdigit(c) {
-				continue
-			}
-			goto dc
-		}
-	}
-
-	cp.WriteByte(byte(c))
-	c = getc()
-	if c == 'x' || c == 'X' {
-		for {
-			cp.WriteByte(byte(c))
-			c = getc()
-			if yy_isdigit(c) {
-				continue
-			}
-			if c >= 'a' && c <= 'f' {
-				continue
-			}
-			if c >= 'A' && c <= 'F' {
-				continue
-			}
-			if lexbuf.Len() == 2 {
-				Yyerror("malformed hex constant")
-			}
-			if c == 'p' {
-				goto caseep
-			}
-			goto ncu
-		}
-	}
-
-	if c == 'p' { // 0p begins floating point zero
-		goto caseep
-	}
-
-	c1 = 0
-	for {
-		if !yy_isdigit(c) {
-			break
-		}
-		if c < '0' || c > '7' {
-			c1 = 1 // not octal
-		}
-		cp.WriteByte(byte(c))
-		c = getc()
-	}
-
-	if c == '.' {
-		goto casedot
-	}
-	if c == 'e' || c == 'E' {
-		goto caseep
-	}
-	if c == 'i' {
-		goto casei
-	}
-	if c1 != 0 {
-		Yyerror("malformed octal constant")
-	}
-	goto ncu
-
-dc:
-	if c == '.' {
-		goto casedot
-	}
-	if c == 'e' || c == 'E' || c == 'p' || c == 'P' {
-		goto caseep
-	}
-	if c == 'i' {
-		goto casei
-	}
-
 ncu:
 	cp = nil
 	ungetc(c)
@@ -1408,7 +1397,7 @@
 	str = lexbuf.String()
 	yylval.val.U.Xval = new(Mpint)
 	mpatofix(yylval.val.U.Xval, str)
-	if yylval.val.U.Xval.Ovf != 0 {
+	if yylval.val.U.Xval.Ovf {
 		Yyerror("overflow in constant")
 		Mpmovecfix(yylval.val.U.Xval, 0)
 	}
@@ -1497,7 +1486,7 @@
 	return LLITERAL
 
 strlit:
-	yylval.val.U.Sval = &Strlit{S: cp.String()}
+	yylval.val.U.Sval = internString(cp.Bytes())
 	yylval.val.Ctype = CTSTR
 	if Debug['x'] != 0 {
 		fmt.Printf("lex: string literal\n")
@@ -1506,6 +1495,18 @@
 	return LLITERAL
 }
 
+var internedStrings = map[string]string{}
+
+func internString(b []byte) string {
+	s, ok := internedStrings[string(b)] // string(b) here doesn't allocate
+	if ok {
+		return s
+	}
+	s = string(b)
+	internedStrings[s] = s
+	return s
+}
+
 func more(pp *string) bool {
 	p := *pp
 	for p != "" && yy_isspace(int(p[0])) {
@@ -1523,31 +1524,91 @@
  */
 func getlinepragma() int {
 	var cmd, verb, name string
-	var n int
-	var cp *bytes.Buffer
-	var linep int
 
 	c := int(getr())
 	if c == 'g' {
-		goto go_
+		cp := &lexbuf
+		cp.Reset()
+		cp.WriteByte('g') // already read
+		for {
+			c = int(getr())
+			if c == EOF || c >= utf8.RuneSelf {
+				return c
+			}
+			if c == '\n' {
+				break
+			}
+			cp.WriteByte(byte(c))
+		}
+		cp = nil
+
+		text := lexbuf.String()
+
+		if strings.HasPrefix(text, "go:cgo_") {
+			pragcgo(text)
+		}
+
+		cmd = text
+		verb = cmd
+		if i := strings.Index(verb, " "); i >= 0 {
+			verb = verb[:i]
+		}
+
+		if verb == "go:linkname" {
+			if imported_unsafe == 0 {
+				Yyerror("//go:linkname only allowed in Go files that import \"unsafe\"")
+			}
+			f := strings.Fields(cmd)
+			if len(f) != 3 {
+				Yyerror("usage: //go:linkname localname linkname")
+				return c
+			}
+
+			Lookup(f[1]).Linkname = f[2]
+			return c
+		}
+
+		if verb == "go:nointerface" && obj.Fieldtrack_enabled != 0 {
+			nointerface = true
+			return c
+		}
+
+		if verb == "go:noescape" {
+			noescape = true
+			return c
+		}
+
+		if verb == "go:nosplit" {
+			nosplit = true
+			return c
+		}
+
+		if verb == "go:nowritebarrier" {
+			if compiling_runtime == 0 {
+				Yyerror("//go:nowritebarrier only allowed in runtime")
+			}
+			nowritebarrier = true
+			return c
+		}
+		return c
 	}
 	if c != 'l' {
-		goto out
+		return c
 	}
 	for i := 1; i < 5; i++ {
 		c = int(getr())
 		if c != int("line "[i]) {
-			goto out
+			return c
 		}
 	}
 
-	cp = &lexbuf
+	cp := &lexbuf
 	cp.Reset()
-	linep = 0
+	linep := 0
 	for {
 		c = int(getr())
 		if c == EOF {
-			goto out
+			return c
 		}
 		if c == '\n' {
 			break
@@ -1564,10 +1625,11 @@
 	cp = nil
 
 	if linep == 0 {
-		goto out
+		return c
 	}
-	n = 0
-	for _, c := range lexbuf.String()[linep:] {
+	text := lexbuf.String()
+	n := 0
+	for _, c := range text[linep:] {
 		if c < '0' || c > '9' {
 			goto out
 		}
@@ -1579,84 +1641,12 @@
 	}
 
 	if n <= 0 {
-		goto out
+		return c
 	}
 
-	// try to avoid allocating file name over and over
-	name = lexbuf.String()[:linep-1]
-	for h := Ctxt.Hist; h != nil; h = h.Link {
-		if h.Name != "" && h.Name == name {
-			linehist(h.Name, int32(n), 0)
-			goto out
-		}
-	}
-
+	name = text[:linep-1]
 	linehist(name, int32(n), 0)
-	goto out
-
-go_:
-	cp = &lexbuf
-	cp.Reset()
-	cp.WriteByte('g') // already read
-	for {
-		c = int(getr())
-		if c == EOF || c >= utf8.RuneSelf {
-			goto out
-		}
-		if c == '\n' {
-			break
-		}
-		cp.WriteByte(byte(c))
-	}
-
-	cp = nil
-
-	if strings.HasPrefix(lexbuf.String(), "go:cgo_") {
-		pragcgo(lexbuf.String())
-	}
-
-	cmd = lexbuf.String()
-	verb = cmd
-	if i := strings.Index(verb, " "); i >= 0 {
-		verb = verb[:i]
-	}
-
-	if verb == "go:linkname" {
-		if imported_unsafe == 0 {
-			Yyerror("//go:linkname only allowed in Go files that import \"unsafe\"")
-		}
-		f := strings.Fields(cmd)
-		if len(f) != 3 {
-			Yyerror("usage: //go:linkname localname linkname")
-			goto out
-		}
-
-		Lookup(f[1]).Linkname = f[2]
-		goto out
-	}
-
-	if verb == "go:nointerface" && obj.Fieldtrack_enabled != 0 {
-		nointerface = true
-		goto out
-	}
-
-	if verb == "go:noescape" {
-		noescape = true
-		goto out
-	}
-
-	if verb == "go:nosplit" {
-		nosplit = true
-		goto out
-	}
-
-	if verb == "go:nowritebarrier" {
-		if compiling_runtime == 0 {
-			Yyerror("//go:nowritebarrier only allowed in runtime")
-		}
-		nowritebarrier = true
-		goto out
-	}
+	return c
 
 out:
 	return c
@@ -1708,14 +1698,12 @@
 		var p string
 		p, ok = getquoted(&q)
 		if !ok {
-			goto err1
+			Yyerror("usage: //go:cgo_dynamic_linker \"path\"")
+			return
 		}
 		pragcgobuf += fmt.Sprintf("cgo_dynamic_linker %v\n", plan9quote(p))
-		goto out
+		return
 
-	err1:
-		Yyerror("usage: //go:cgo_dynamic_linker \"path\"")
-		goto out
 	}
 
 	if verb == "dynexport" {
@@ -1729,7 +1717,7 @@
 		}
 		if !more(&q) {
 			pragcgobuf += fmt.Sprintf("%s %v\n", verb, plan9quote(local))
-			goto out
+			return
 		}
 
 		remote = getimpsym(&q)
@@ -1737,11 +1725,11 @@
 			goto err2
 		}
 		pragcgobuf += fmt.Sprintf("%s %v %v\n", verb, plan9quote(local), plan9quote(remote))
-		goto out
+		return
 
 	err2:
 		Yyerror("usage: //go:%s local [remote]", verb)
-		goto out
+		return
 	}
 
 	if verb == "cgo_import_dynamic" || verb == "dynimport" {
@@ -1754,7 +1742,7 @@
 		}
 		if !more(&q) {
 			pragcgobuf += fmt.Sprintf("cgo_import_dynamic %v\n", plan9quote(local))
-			goto out
+			return
 		}
 
 		remote = getimpsym(&q)
@@ -1763,7 +1751,7 @@
 		}
 		if !more(&q) {
 			pragcgobuf += fmt.Sprintf("cgo_import_dynamic %v %v\n", plan9quote(local), plan9quote(remote))
-			goto out
+			return
 		}
 
 		p, ok = getquoted(&q)
@@ -1771,24 +1759,22 @@
 			goto err3
 		}
 		pragcgobuf += fmt.Sprintf("cgo_import_dynamic %v %v %v\n", plan9quote(local), plan9quote(remote), plan9quote(p))
-		goto out
+		return
 
 	err3:
 		Yyerror("usage: //go:cgo_import_dynamic local [remote [\"library\"]]")
-		goto out
+		return
 	}
 
 	if verb == "cgo_import_static" {
 		local := getimpsym(&q)
 		if local == "" || more(&q) {
-			goto err4
+			Yyerror("usage: //go:cgo_import_static local")
+			return
 		}
 		pragcgobuf += fmt.Sprintf("cgo_import_static %v\n", plan9quote(local))
-		goto out
+		return
 
-	err4:
-		Yyerror("usage: //go:cgo_import_static local")
-		goto out
 	}
 
 	if verb == "cgo_ldflag" {
@@ -1796,17 +1782,13 @@
 		var p string
 		p, ok = getquoted(&q)
 		if !ok {
-			goto err5
+			Yyerror("usage: //go:cgo_ldflag \"arg\"")
+			return
 		}
 		pragcgobuf += fmt.Sprintf("cgo_ldflag %v\n", plan9quote(p))
-		goto out
+		return
 
-	err5:
-		Yyerror("usage: //go:cgo_ldflag \"arg\"")
-		goto out
 	}
-
-out:
 }
 
 type yy struct{}
@@ -1950,7 +1932,10 @@
 			r, w := utf8.DecodeRune(buf[:i+1])
 			if r == utf8.RuneError && w == 1 {
 				lineno = lexlineno
-				Yyerror("illegal UTF-8 sequence % x", buf[:i+1])
+				// The string conversion here makes a copy for passing
+				// to fmt.Printf, so that buf itself does not escape and can
+				// be allocated on the stack.
+				Yyerror("illegal UTF-8 sequence % x", string(buf[:i+1]))
 			}
 			return int32(r)
 		}
@@ -1983,7 +1968,6 @@
 
 	u := 0
 	c = int(getr())
-	var l int64
 	var i int
 	switch c {
 	case 'x':
@@ -2010,7 +1994,24 @@
 		'6',
 		'7':
 		*escflg = 1 // it's a byte
-		goto oct
+		l := int64(c) - '0'
+		for i := 2; i > 0; i-- {
+			c = getc()
+			if c >= '0' && c <= '7' {
+				l = l*8 + int64(c) - '0'
+				continue
+			}
+
+			Yyerror("non-octal character in escape sequence: %c", c)
+			ungetc(c)
+		}
+
+		if l > 255 {
+			Yyerror("octal escape value > 255: %d", l)
+		}
+
+		*val = l
+		return false
 
 	case 'a':
 		c = '\a'
@@ -2039,7 +2040,7 @@
 	return false
 
 hex:
-	l = 0
+	l := int64(0)
 	for ; i > 0; i-- {
 		c = getc()
 		if c >= '0' && c <= '9' {
@@ -2069,26 +2070,6 @@
 
 	*val = l
 	return false
-
-oct:
-	l = int64(c) - '0'
-	for i := 2; i > 0; i-- {
-		c = getc()
-		if c >= '0' && c <= '7' {
-			l = l*8 + int64(c) - '0'
-			continue
-		}
-
-		Yyerror("non-octal character in escape sequence: %c", c)
-		ungetc(c)
-	}
-
-	if l > 255 {
-		Yyerror("octal escape value > 255: %d", l)
-	}
-
-	*val = l
-	return false
 }
 
 var syms = []struct {
@@ -2507,7 +2488,6 @@
 			s1.Def = Nod(ONAME, nil, nil)
 			s1.Def.Sym = s1
 			s1.Def.Etype = uint8(etype)
-			s1.Def.Builtin = 1
 		}
 	}
 
@@ -2635,7 +2615,6 @@
 			s.Def = Nod(ONAME, nil, nil)
 			s.Def.Sym = s
 			s.Def.Etype = uint8(etype)
-			s.Def.Builtin = 1
 			s.Origpkg = builtinpkg
 		}
 	}
@@ -3100,21 +3079,21 @@
 	}{"','", "comma"},
 }
 
-func pkgnotused(lineno int, path_ *Strlit, name string) {
+func pkgnotused(lineno int, path string, name string) {
 	// If the package was imported with a name other than the final
 	// import path element, show it explicitly in the error message.
 	// Note that this handles both renamed imports and imports of
 	// packages containing unconventional package declarations.
 	// Note that this uses / always, even on Windows, because Go import
 	// paths always use forward slashes.
-	elem := path_.S
+	elem := path
 	if i := strings.LastIndex(elem, "/"); i >= 0 {
 		elem = elem[i+1:]
 	}
 	if name == "" || elem == name {
-		yyerrorl(int(lineno), "imported and not used: \"%v\"", Zconv(path_, 0))
+		yyerrorl(int(lineno), "imported and not used: %q", path)
 	} else {
-		yyerrorl(int(lineno), "imported and not used: \"%v\" as %s", Zconv(path_, 0), name)
+		yyerrorl(int(lineno), "imported and not used: %q as %s", path, name)
 	}
 }
 
@@ -3128,36 +3107,33 @@
 		if pkgname != localpkg.Name {
 			Yyerror("package %s; expected %s", pkgname, localpkg.Name)
 		}
-		var s *Sym
-		for h := int32(0); h < NHASH; h++ {
-			for s = hash[h]; s != nil; s = s.Link {
-				if s.Def == nil || s.Pkg != localpkg {
-					continue
+		for _, s := range localpkg.Syms {
+			if s.Def == nil {
+				continue
+			}
+			if s.Def.Op == OPACK {
+				// throw away top-level package name leftover
+				// from previous file.
+				// leave s->block set to cause redeclaration
+				// errors if a conflicting top-level name is
+				// introduced by a different file.
+				if !s.Def.Used && nsyntaxerrors == 0 {
+					pkgnotused(int(s.Def.Lineno), s.Def.Pkg.Path, s.Name)
 				}
-				if s.Def.Op == OPACK {
-					// throw away top-level package name leftover
-					// from previous file.
-					// leave s->block set to cause redeclaration
-					// errors if a conflicting top-level name is
-					// introduced by a different file.
-					if s.Def.Used == 0 && nsyntaxerrors == 0 {
-						pkgnotused(int(s.Def.Lineno), s.Def.Pkg.Path, s.Name)
-					}
-					s.Def = nil
-					continue
+				s.Def = nil
+				continue
+			}
+
+			if s.Def.Sym != s {
+				// throw away top-level name left over
+				// from previous import . "x"
+				if s.Def.Pack != nil && !s.Def.Pack.Used && nsyntaxerrors == 0 {
+					pkgnotused(int(s.Def.Pack.Lineno), s.Def.Pack.Pkg.Path, "")
+					s.Def.Pack.Used = true
 				}
 
-				if s.Def.Sym != s {
-					// throw away top-level name left over
-					// from previous import . "x"
-					if s.Def.Pack != nil && s.Def.Pack.Used == 0 && nsyntaxerrors == 0 {
-						pkgnotused(int(s.Def.Pack.Lineno), s.Def.Pack.Pkg.Path, "")
-						s.Def.Pack.Used = 1
-					}
-
-					s.Def = nil
-					continue
-				}
+				s.Def = nil
+				continue
 			}
 		}
 	}
@@ -3172,10 +3148,9 @@
 				p = p[i+1:]
 			}
 		}
-		namebuf = p
-		if i := strings.LastIndex(namebuf, "."); i >= 0 {
-			namebuf = namebuf[:i]
+		if i := strings.LastIndex(p, "."); i >= 0 {
+			p = p[:i]
 		}
-		outfile = fmt.Sprintf("%s.%c", namebuf, Thearch.Thechar)
+		outfile = fmt.Sprintf("%s.%c", p, Thearch.Thechar)
 	}
 }
diff --git a/src/cmd/internal/gc/md5.go b/src/cmd/internal/gc/md5.go
deleted file mode 100644
index 3b51900..0000000
--- a/src/cmd/internal/gc/md5.go
+++ /dev/null
@@ -1,298 +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 gc
-
-// 64-bit MD5 (does full MD5 but returns 64 bits only).
-// Translation of ../../crypto/md5/md5*.go.
-
-// 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.
-
-type MD5 struct {
-	s   [4]uint32
-	x   [64]uint8
-	nx  int
-	len uint64
-}
-
-const (
-	_Chunk = 64
-)
-
-const (
-	_Init0 = 0x67452301
-	_Init1 = 0xEFCDAB89
-	_Init2 = 0x98BADCFE
-	_Init3 = 0x10325476
-)
-
-func md5reset(d *MD5) {
-	d.s[0] = _Init0
-	d.s[1] = _Init1
-	d.s[2] = _Init2
-	d.s[3] = _Init3
-	d.nx = 0
-	d.len = 0
-}
-
-func md5write(d *MD5, p []byte, nn int) {
-	d.len += uint64(nn)
-	if d.nx > 0 {
-		n := nn
-		if n > _Chunk-d.nx {
-			n = _Chunk - d.nx
-		}
-		for i := 0; i < n; i++ {
-			d.x[d.nx+i] = uint8(p[i])
-		}
-		d.nx += n
-		if d.nx == _Chunk {
-			md5block(d, d.x[:], _Chunk)
-			d.nx = 0
-		}
-
-		p = p[n:]
-		nn -= n
-	}
-
-	n := md5block(d, p, nn)
-	p = p[n:]
-	nn -= n
-	if nn > 0 {
-		for i := 0; i < nn; i++ {
-			d.x[i] = uint8(p[i])
-		}
-		d.nx = nn
-	}
-}
-
-func md5sum(d *MD5, hi *uint64) uint64 {
-	// Padding.  Add a 1 bit and 0 bits until 56 bytes mod 64.
-	len := d.len
-
-	tmp := [64]uint8{}
-	tmp[0] = 0x80
-	if len%64 < 56 {
-		md5write(d, tmp[:], int(56-len%64))
-	} else {
-		md5write(d, tmp[:], int(64+56-len%64))
-	}
-
-	// Length in bits.
-	len <<= 3
-
-	for i := 0; i < 8; i++ {
-		tmp[i] = uint8(len >> uint(8*i))
-	}
-	md5write(d, tmp[:], 8)
-
-	if d.nx != 0 {
-		Fatal("md5sum")
-	}
-
-	if hi != nil {
-		*hi = uint64(d.s[2]) | uint64(d.s[3])<<32
-	}
-	return uint64(d.s[0]) | uint64(d.s[1])<<32
-}
-
-// MD5 block step.
-// In its own file so that a faster assembly or C version
-// can be substituted easily.
-
-// table[i] = int((1<<32) * abs(sin(i+1 radians))).
-var table = [64]uint32{
-	// round 1
-	0xd76aa478,
-	0xe8c7b756,
-	0x242070db,
-	0xc1bdceee,
-	0xf57c0faf,
-	0x4787c62a,
-	0xa8304613,
-	0xfd469501,
-	0x698098d8,
-	0x8b44f7af,
-	0xffff5bb1,
-	0x895cd7be,
-	0x6b901122,
-	0xfd987193,
-	0xa679438e,
-	0x49b40821,
-
-	// round 2
-	0xf61e2562,
-	0xc040b340,
-	0x265e5a51,
-	0xe9b6c7aa,
-	0xd62f105d,
-	0x2441453,
-	0xd8a1e681,
-	0xe7d3fbc8,
-	0x21e1cde6,
-	0xc33707d6,
-	0xf4d50d87,
-	0x455a14ed,
-	0xa9e3e905,
-	0xfcefa3f8,
-	0x676f02d9,
-	0x8d2a4c8a,
-
-	// round3
-	0xfffa3942,
-	0x8771f681,
-	0x6d9d6122,
-	0xfde5380c,
-	0xa4beea44,
-	0x4bdecfa9,
-	0xf6bb4b60,
-	0xbebfbc70,
-	0x289b7ec6,
-	0xeaa127fa,
-	0xd4ef3085,
-	0x4881d05,
-	0xd9d4d039,
-	0xe6db99e5,
-	0x1fa27cf8,
-	0xc4ac5665,
-
-	// round 4
-	0xf4292244,
-	0x432aff97,
-	0xab9423a7,
-	0xfc93a039,
-	0x655b59c3,
-	0x8f0ccc92,
-	0xffeff47d,
-	0x85845dd1,
-	0x6fa87e4f,
-	0xfe2ce6e0,
-	0xa3014314,
-	0x4e0811a1,
-	0xf7537e82,
-	0xbd3af235,
-	0x2ad7d2bb,
-	0xeb86d391,
-}
-
-var shift1 = []uint32{7, 12, 17, 22}
-
-var shift2 = []uint32{5, 9, 14, 20}
-
-var shift3 = []uint32{4, 11, 16, 23}
-
-var shift4 = []uint32{6, 10, 15, 21}
-
-func md5block(dig *MD5, p []byte, nn int) int {
-	var aa uint32
-	var bb uint32
-	var cc uint32
-	var dd uint32
-	var i int
-	var j int
-	var X [16]uint32
-
-	a := dig.s[0]
-	b := dig.s[1]
-	c := dig.s[2]
-	d := dig.s[3]
-	n := 0
-
-	for nn >= _Chunk {
-		aa = a
-		bb = b
-		cc = c
-		dd = d
-
-		for i = 0; i < 16; i++ {
-			j = i * 4
-			X[i] = uint32(p[j]) | uint32(p[j+1])<<8 | uint32(p[j+2])<<16 | uint32(p[j+3])<<24
-		}
-
-		// Round 1.
-		for i = 0; i < 16; i++ {
-			x := uint32(i)
-			t := uint32(i)
-			s := shift1[i%4]
-			f := ((c ^ d) & b) ^ d
-			a += f + X[x] + table[t]
-			a = a<<s | a>>(32-s)
-			a += b
-
-			t = d
-			d = c
-			c = b
-			b = a
-			a = t
-		}
-
-		// Round 2.
-		for i = 0; i < 16; i++ {
-			x := (1 + 5*uint32(i)) % 16
-			t := 16 + uint32(i)
-			s := shift2[i%4]
-			g := ((b ^ c) & d) ^ c
-			a += g + X[x] + table[t]
-			a = a<<s | a>>(32-s)
-			a += b
-
-			t = d
-			d = c
-			c = b
-			b = a
-			a = t
-		}
-
-		// Round 3.
-		for i = 0; i < 16; i++ {
-			x := (5 + 3*uint32(i)) % 16
-			t := 32 + uint32(i)
-			s := shift3[i%4]
-			h := b ^ c ^ d
-			a += h + X[x] + table[t]
-			a = a<<s | a>>(32-s)
-			a += b
-
-			t = d
-			d = c
-			c = b
-			b = a
-			a = t
-		}
-
-		// Round 4.
-		for i = 0; i < 16; i++ {
-			x := (7 * uint32(i)) % 16
-			s := shift4[i%4]
-			t := 48 + uint32(i)
-			ii := c ^ (b | ^d)
-			a += ii + X[x] + table[t]
-			a = a<<s | a>>(32-s)
-			a += b
-
-			t = d
-			d = c
-			c = b
-			b = a
-			a = t
-		}
-
-		a += aa
-		b += bb
-		c += cc
-		d += dd
-
-		p = p[_Chunk:]
-		n += _Chunk
-		nn -= _Chunk
-	}
-
-	dig.s[0] = a
-	dig.s[1] = b
-	dig.s[2] = c
-	dig.s[3] = d
-	return n
-}
diff --git a/src/cmd/internal/gc/mkbuiltin.go b/src/cmd/internal/gc/mkbuiltin.go
index f32a75b..b2362a6 100644
--- a/src/cmd/internal/gc/mkbuiltin.go
+++ b/src/cmd/internal/gc/mkbuiltin.go
@@ -50,7 +50,7 @@
 
 // Compile .go file, import data from .6 file, and write Go string version.
 func mkbuiltin(w io.Writer, gochar string, name string) {
-	if err := exec.Command("go", "tool", gochar+"g", "-A", "builtins/"+name+".go").Run(); err != nil {
+	if err := exec.Command("go", "tool", gochar+"g", "-A", "builtin/"+name+".go").Run(); err != nil {
 		log.Fatal(err)
 	}
 	obj := fmt.Sprintf("%s.%s", name, gochar)
diff --git a/src/cmd/internal/gc/mparith1.go b/src/cmd/internal/gc/mparith1.go
index 104992f..51d888a 100644
--- a/src/cmd/internal/gc/mparith1.go
+++ b/src/cmd/internal/gc/mparith1.go
@@ -8,39 +8,33 @@
 	"cmd/internal/obj"
 	"fmt"
 	"math"
+	"math/big"
 )
 
 /// uses arithmetic
 
-func mpcmpfixflt(a *Mpint, b *Mpflt) int {
+func mpcmpfixflt(a *Mpfix, b *Mpflt) int {
 	var c Mpflt
 
-	buf := fmt.Sprintf("%v", Bconv(a, 0))
+	buf := _Bconv(a, 0)
 	mpatoflt(&c, buf)
 	return mpcmpfltflt(&c, b)
 }
 
-func mpcmpfltfix(a *Mpflt, b *Mpint) int {
+func mpcmpfltfix(a *Mpflt, b *Mpfix) int {
 	var c Mpflt
 
-	buf := fmt.Sprintf("%v", Bconv(b, 0))
+	buf := _Bconv(b, 0)
 	mpatoflt(&c, buf)
 	return mpcmpfltflt(a, &c)
 }
 
-func Mpcmpfixfix(a *Mpint, b *Mpint) int {
-	var c Mpint
-
-	mpmovefixfix(&c, a)
-	mpsubfixfix(&c, b)
-	return mptestfix(&c)
+func Mpcmpfixfix(a, b *Mpint) int {
+	return a.Val.Cmp(&b.Val)
 }
 
 func mpcmpfixc(b *Mpint, c int64) int {
-	var c1 Mpint
-
-	Mpmovecfix(&c1, c)
-	return Mpcmpfixfix(b, &c1)
+	return b.Val.Cmp(big.NewInt(c))
 }
 
 func mpcmpfltflt(a *Mpflt, b *Mpflt) int {
@@ -58,10 +52,14 @@
 	return mpcmpfltflt(b, &a)
 }
 
-func mpsubfixfix(a *Mpint, b *Mpint) {
-	mpnegfix(a)
-	mpaddfixfix(a, b, 0)
-	mpnegfix(a)
+func mpsubfixfix(a, b *Mpint) {
+	a.Val.Sub(&a.Val, &b.Val)
+}
+
+func _mpsubfixfix(a *Mpfix, b *Mpfix) {
+	_mpnegfix(a)
+	_mpaddfixfix(a, b, 0)
+	_mpnegfix(a)
 }
 
 func mpsubfltflt(a *Mpflt, b *Mpflt) {
@@ -70,11 +68,11 @@
 	mpnegflt(a)
 }
 
-func mpaddcfix(a *Mpint, c int64) {
-	var b Mpint
+func mpaddcfix(a *Mpfix, c int64) {
+	var b Mpfix
 
-	Mpmovecfix(&b, c)
-	mpaddfixfix(a, &b, 0)
+	_Mpmovecfix(&b, c)
+	_mpaddfixfix(a, &b, 0)
 }
 
 func mpaddcflt(a *Mpflt, c float64) {
@@ -84,11 +82,11 @@
 	mpaddfltflt(a, &b)
 }
 
-func mpmulcfix(a *Mpint, c int64) {
-	var b Mpint
+func mpmulcfix(a *Mpfix, c int64) {
+	var b Mpfix
 
-	Mpmovecfix(&b, c)
-	mpmulfixfix(a, &b)
+	_Mpmovecfix(&b, c)
+	_mpmulfixfix(a, &b)
 }
 
 func mpmulcflt(a *Mpflt, c float64) {
@@ -98,31 +96,110 @@
 	mpmulfltflt(a, &b)
 }
 
-func mpdivfixfix(a *Mpint, b *Mpint) {
-	var q Mpint
-	var r Mpint
-
-	mpdivmodfixfix(&q, &r, a, b)
-	mpmovefixfix(a, &q)
+func mpdivfixfix(a, b *Mpint) {
+	a.Val.Quo(&a.Val, &b.Val)
 }
 
-func mpmodfixfix(a *Mpint, b *Mpint) {
-	var q Mpint
-	var r Mpint
+func _mpdivfixfix(a *Mpfix, b *Mpfix) {
+	var q Mpfix
+	var r Mpfix
 
 	mpdivmodfixfix(&q, &r, a, b)
-	mpmovefixfix(a, &r)
+	_mpmovefixfix(a, &q)
 }
 
-func mpcomfix(a *Mpint) {
-	var b Mpint
+func mpmodfixfix(a, b *Mpint) {
+	a.Val.Rem(&a.Val, &b.Val)
+}
 
-	Mpmovecfix(&b, 1)
-	mpnegfix(a)
-	mpsubfixfix(a, &b)
+func _mpmodfixfix(a *Mpfix, b *Mpfix) {
+	var q Mpfix
+	var r Mpfix
+
+	mpdivmodfixfix(&q, &r, a, b)
+	_mpmovefixfix(a, &r)
+}
+
+func mpcomfix(a *Mpfix) {
+	var b Mpfix
+
+	_Mpmovecfix(&b, 1)
+	_mpnegfix(a)
+	_mpsubfixfix(a, &b)
+}
+
+// *a = Mpfix(*b)
+func mpmoveintfix(a *Mpfix, b *Mpint) {
+	if b.Ovf {
+		_Mpmovecfix(a, 0)
+		a.Ovf = 1
+		return
+	}
+
+	var bb big.Int
+	bb.Abs(&b.Val)
+	i := 0
+	for ; i < Mpprec && bb.Sign() != 0; i++ {
+		// depends on (unspecified) behavior of Int.Uint64
+		a.A[i] = int(bb.Uint64() & Mpmask)
+		bb.Rsh(&bb, Mpscale)
+	}
+
+	if bb.Sign() != 0 {
+		// MPint overflows
+		_Mpmovecfix(a, 0)
+		a.Ovf = 1
+		return
+	}
+
+	for ; i < Mpprec; i++ {
+		a.A[i] = 0
+	}
+
+	a.Neg = 0
+	if b.Val.Sign() < 0 {
+		a.Neg = 1
+	}
+	a.Ovf = 0
+
+	// leave for debugging
+	// println("mpmoveintfix:", b.Val.String(), "->", _Bconv(a, 0))
+}
+
+// *a = big.Int(*b)
+func mpmovefixint(a *Mpint, b *Mpfix) {
+	if b.Ovf != 0 {
+		mpsetovf(a)
+		return
+	}
+
+	i := Mpprec - 1
+	for ; i >= 0 && b.A[i] == 0; i-- {
+	}
+
+	a.Val.SetUint64(0)
+	var x big.Int
+	for ; i >= 0; i-- {
+		a.Val.Lsh(&a.Val, Mpscale)
+		a.Val.Or(&a.Val, x.SetUint64(uint64(b.A[i]&Mpmask)))
+	}
+
+	if b.Neg != 0 {
+		a.Val.Neg(&a.Val)
+	}
+	a.Ovf = false
+
+	// leave for debugging
+	// println("mpmovefixint:", _Bconv(b, 0), "->", a.Val.String())
 }
 
 func Mpmovefixflt(a *Mpflt, b *Mpint) {
+	mpmoveintfix(&a.Val, b) // a.Val = *b
+	a.Exp = 0
+	mpnorm(a)
+}
+
+func _Mpmovefixflt(a *Mpflt, b *Mpfix) {
 	a.Val = *b
 	a.Exp = 0
 	mpnorm(a)
@@ -131,11 +208,11 @@
 // convert (truncate) b to a.
 // return -1 (but still convert) if b was non-integer.
 func mpexactfltfix(a *Mpint, b *Mpflt) int {
-	*a = b.Val
+	mpmovefixint(a, &b.Val) // *a = b.Val
 	Mpshiftfix(a, int(b.Exp))
 	if b.Exp < 0 {
 		var f Mpflt
-		f.Val = *a
+		mpmoveintfix(&f.Val, a) // f.Val = *a
 		f.Exp = 0
 		mpnorm(&f)
 		if mpcmpfltflt(b, &f) != 0 {
@@ -176,7 +253,11 @@
 	return -1
 }
 
-func mpmovefixfix(a *Mpint, b *Mpint) {
+func mpmovefixfix(a, b *Mpint) {
+	a.Val.Set(&b.Val)
+}
+
+func _mpmovefixfix(a *Mpfix, b *Mpfix) {
 	*a = *b
 }
 
@@ -202,7 +283,7 @@
 	}
 }
 
-func mphextofix(a *Mpint, s string) {
+func mphextofix(a *Mpfix, s string) {
 	for s != "" && s[0] == '0' {
 		s = s[1:]
 	}
@@ -259,8 +340,7 @@
 		c := s[0]
 		s = s[1:]
 		switch c {
-		case '-',
-			'+':
+		case '-', '+':
 			break
 
 		case '0':
@@ -330,9 +410,7 @@
 			f = 1
 			fallthrough
 
-		case ' ',
-			'\t',
-			'+':
+		case ' ', '\t', '+':
 			continue
 
 		case '.':
@@ -361,13 +439,11 @@
 			}
 			continue
 
-		case 'P',
-			'p':
+		case 'P', 'p':
 			eb = 1
 			fallthrough
 
-		case 'E',
-			'e':
+		case 'E', 'e':
 			ex = 0
 			ef = 0
 			for {
@@ -445,120 +521,54 @@
 	Mpmovecflt(a, 0.0)
 }
 
-//
-// fixed point input
-// required syntax is [+-][0[x]]d*
-//
 func mpatofix(a *Mpint, as string) {
-	var c int
-	var s0 string
-
-	s := as
-	f := 0
-	Mpmovecfix(a, 0)
-
-	c, s = intstarstringplusplus(s)
-	switch c {
-	case '-':
-		f = 1
-		fallthrough
-
-	case '+':
-		c, s = intstarstringplusplus(s)
-		if c != '0' {
-			break
-		}
-		fallthrough
-
-	case '0':
-		goto oct
+	_, ok := a.Val.SetString(as, 0)
+	if !ok {
+		// required syntax is [+-][0[x]]d*
+		// At the moment we lose precise error cause;
+		// the old code distinguished between:
+		// - malformed hex constant
+		// - malformed octal constant
+		// - malformed decimal constant
+		// TODO(gri) use different conversion function
+		Yyerror("malformed integer constant: %s", as)
+		a.Val.SetUint64(0)
+		return
 	}
-
-	for c != 0 {
-		if c >= '0' && c <= '9' {
-			mpmulcfix(a, 10)
-			mpaddcfix(a, int64(c)-'0')
-			c, s = intstarstringplusplus(s)
-			continue
-		}
-
-		Yyerror("malformed decimal constant: %s", as)
-		goto bad
-	}
-
-	goto out
-
-oct:
-	c, s = intstarstringplusplus(s)
-	if c == 'x' || c == 'X' {
-		goto hex
-	}
-	for c != 0 {
-		if c >= '0' && c <= '7' {
-			mpmulcfix(a, 8)
-			mpaddcfix(a, int64(c)-'0')
-			c, s = intstarstringplusplus(s)
-			continue
-		}
-
-		Yyerror("malformed octal constant: %s", as)
-		goto bad
-	}
-
-	goto out
-
-hex:
-	s0 = s
-	c, _ = intstarstringplusplus(s)
-	for c != 0 {
-		if (c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F') {
-			s = s[1:]
-			c, _ = intstarstringplusplus(s)
-			continue
-		}
-
-		Yyerror("malformed hex constant: %s", as)
-		goto bad
-	}
-
-	mphextofix(a, s0)
-	if a.Ovf != 0 {
+	if mptestovf(a, 0) {
 		Yyerror("constant too large: %s", as)
-		goto bad
 	}
-
-out:
-	if f != 0 {
-		mpnegfix(a)
-	}
-	return
-
-bad:
-	Mpmovecfix(a, 0)
 }
 
 func Bconv(xval *Mpint, flag int) string {
-	var q Mpint
+	if flag&obj.FmtSharp != 0 {
+		return fmt.Sprintf("%#x", &xval.Val)
+	}
+	return xval.Val.String()
+}
 
-	mpmovefixfix(&q, xval)
+func _Bconv(xval *Mpfix, flag int) string {
+	var q Mpfix
+
+	_mpmovefixfix(&q, xval)
 	f := 0
 	if mptestfix(&q) < 0 {
 		f = 1
-		mpnegfix(&q)
+		_mpnegfix(&q)
 	}
 
 	var buf [500]byte
 	p := len(buf)
-	var r Mpint
+	var r Mpfix
 	if flag&obj.FmtSharp != 0 /*untyped*/ {
 		// Hexadecimal
-		var sixteen Mpint
-		Mpmovecfix(&sixteen, 16)
+		var sixteen Mpfix
+		_Mpmovecfix(&sixteen, 16)
 
 		var digit int
 		for {
 			mpdivmodfixfix(&q, &r, &q, &sixteen)
-			digit = int(Mpgetfix(&r))
+			digit = int(_Mpgetfix(&r))
 			if digit < 10 {
 				p--
 				buf[p] = byte(digit + '0')
@@ -577,13 +587,13 @@
 		buf[p] = '0'
 	} else {
 		// Decimal
-		var ten Mpint
-		Mpmovecfix(&ten, 10)
+		var ten Mpfix
+		_Mpmovecfix(&ten, 10)
 
 		for {
 			mpdivmodfixfix(&q, &r, &q, &ten)
 			p--
-			buf[p] = byte(Mpgetfix(&r) + '0')
+			buf[p] = byte(_Mpgetfix(&r) + '0')
 			if mptestfix(&q) <= 0 {
 				break
 			}
@@ -650,21 +660,21 @@
 	fv = *fvp
 
 	for fv.Val.A[0] == 0 {
-		Mpshiftfix(&fv.Val, -Mpscale)
+		_Mpshiftfix(&fv.Val, -Mpscale)
 		fv.Exp += Mpscale
 	}
 
 	for fv.Val.A[0]&1 == 0 {
-		Mpshiftfix(&fv.Val, -1)
+		_Mpshiftfix(&fv.Val, -1)
 		fv.Exp += 1
 	}
 
 	if fv.Exp >= 0 {
-		buf = fmt.Sprintf("%vp+%d", Bconv(&fv.Val, obj.FmtSharp), fv.Exp)
+		buf = fmt.Sprintf("%vp+%d", _Bconv(&fv.Val, obj.FmtSharp), fv.Exp)
 		goto out
 	}
 
-	buf = fmt.Sprintf("%vp-%d", Bconv(&fv.Val, obj.FmtSharp), -fv.Exp)
+	buf = fmt.Sprintf("%vp-%d", _Bconv(&fv.Val, obj.FmtSharp), -fv.Exp)
 
 out:
 	var fp string
diff --git a/src/cmd/internal/gc/mparith2.go b/src/cmd/internal/gc/mparith2.go
index c9c9230..80253dd 100644
--- a/src/cmd/internal/gc/mparith2.go
+++ b/src/cmd/internal/gc/mparith2.go
@@ -8,7 +8,7 @@
 // return the significant
 // words of the argument
 //
-func mplen(a *Mpint) int {
+func mplen(a *Mpfix) int {
 	n := -1
 	for i := 0; i < Mpprec; i++ {
 		if a.A[i] != 0 {
@@ -23,7 +23,7 @@
 // left shift mpint by one
 // ignores sign
 //
-func mplsh(a *Mpint, quiet int) {
+func mplsh(a *Mpfix, quiet int) {
 	var x int
 
 	c := 0
@@ -48,7 +48,7 @@
 // left shift mpint by Mpscale
 // ignores sign
 //
-func mplshw(a *Mpint, quiet int) {
+func mplshw(a *Mpfix, quiet int) {
 	i := Mpprec - 1
 	if a.A[i] != 0 {
 		a.Ovf = 1
@@ -67,7 +67,7 @@
 // right shift mpint by one
 // ignores sign and overflow
 //
-func mprsh(a *Mpint) {
+func mprsh(a *Mpfix) {
 	var x int
 
 	c := 0
@@ -90,7 +90,7 @@
 // right shift mpint by Mpscale
 // ignores sign and overflow
 //
-func mprshw(a *Mpint) {
+func mprshw(a *Mpfix) {
 	var i int
 
 	lo := a.A[0]
@@ -107,7 +107,7 @@
 //
 // return the sign of (abs(a)-abs(b))
 //
-func mpcmp(a *Mpint, b *Mpint) int {
+func mpcmp(a *Mpfix, b *Mpfix) int {
 	if a.Ovf != 0 || b.Ovf != 0 {
 		if nsavederrors+nerrors == 0 {
 			Yyerror("ovf in cmp")
@@ -133,7 +133,7 @@
 // negate a
 // ignore sign and ovf
 //
-func mpneg(a *Mpint) {
+func mpneg(a *Mpfix) {
 	var x int
 
 	c := 0
@@ -149,8 +149,21 @@
 	}
 }
 
-// shift left by s (or right by -s)
 func Mpshiftfix(a *Mpint, s int) {
+	switch {
+	case s > 0:
+		if mptestovf(a, s) {
+			Yyerror("constant shift overflow")
+			return
+		}
+		a.Val.Lsh(&a.Val, uint(s))
+	case s < 0:
+		a.Val.Rsh(&a.Val, uint(-s))
+	}
+}
+
+// shift left by s (or right by -s)
+func _Mpshiftfix(a *Mpfix, s int) {
 	if s >= 0 {
 		for s >= Mpscale {
 			mplshw(a, 0)
@@ -175,9 +188,40 @@
 	}
 }
 
-/// implements fix arihmetic
+/// implements fix arithmetic
 
-func mpaddfixfix(a *Mpint, b *Mpint, quiet int) {
+func mpsetovf(a *Mpint) {
+	a.Val.SetUint64(0)
+	a.Ovf = true
+}
+
+func mptestovf(a *Mpint, extra int) bool {
+	// We don't need to be precise here, any reasonable upper limit would do.
+	// For now, use existing limit so we pass all the tests unchanged.
+	const limit = Mpscale * Mpprec
+	if a.Val.BitLen()+extra > limit {
+		mpsetovf(a)
+	}
+	return a.Ovf
+}
+
+func mpaddfixfix(a, b *Mpint, quiet int) {
+	if a.Ovf || b.Ovf {
+		if nsavederrors+nerrors == 0 {
+			Yyerror("ovf in mpaddxx")
+		}
+		mpsetovf(a)
+		return
+	}
+
+	a.Val.Add(&a.Val, &b.Val)
+
+	if mptestovf(a, 0) && quiet == 0 {
+		Yyerror("constant addition overflow")
+	}
+}
+
+func _mpaddfixfix(a *Mpfix, b *Mpfix, quiet int) {
 	if a.Ovf != 0 || b.Ovf != 0 {
 		if nsavederrors+nerrors == 0 {
 			Yyerror("ovf in mpaddxx")
@@ -187,12 +231,44 @@
 	}
 
 	c := 0
-	var x int
 	if a.Neg != b.Neg {
-		goto sub
+		// perform a-b
+		switch mpcmp(a, b) {
+		case 0:
+			_Mpmovecfix(a, 0)
+
+		case 1:
+			var x int
+			for i := 0; i < Mpprec; i++ {
+				x = a.A[i] - b.A[i] - c
+				c = 0
+				if x < 0 {
+					x += Mpbase
+					c = 1
+				}
+
+				a.A[i] = x
+			}
+
+		case -1:
+			a.Neg ^= 1
+			var x int
+			for i := 0; i < Mpprec; i++ {
+				x = b.A[i] - a.A[i] - c
+				c = 0
+				if x < 0 {
+					x += Mpbase
+					c = 1
+				}
+
+				a.A[i] = x
+			}
+		}
+		return
 	}
 
 	// perform a+b
+	var x int
 	for i := 0; i < Mpprec; i++ {
 		x = a.A[i] + b.A[i] + c
 		c = 0
@@ -210,43 +286,25 @@
 	}
 
 	return
+}
 
-	// perform a-b
-sub:
-	switch mpcmp(a, b) {
-	case 0:
-		Mpmovecfix(a, 0)
-
-	case 1:
-		var x int
-		for i := 0; i < Mpprec; i++ {
-			x = a.A[i] - b.A[i] - c
-			c = 0
-			if x < 0 {
-				x += Mpbase
-				c = 1
-			}
-
-			a.A[i] = x
+func mpmulfixfix(a, b *Mpint) {
+	if a.Ovf || b.Ovf {
+		if nsavederrors+nerrors == 0 {
+			Yyerror("ovf in mpmulfixfix")
 		}
+		mpsetovf(a)
+		return
+	}
 
-	case -1:
-		a.Neg ^= 1
-		var x int
-		for i := 0; i < Mpprec; i++ {
-			x = b.A[i] - a.A[i] - c
-			c = 0
-			if x < 0 {
-				x += Mpbase
-				c = 1
-			}
+	a.Val.Mul(&a.Val, &b.Val)
 
-			a.A[i] = x
-		}
+	if mptestovf(a, 0) {
+		Yyerror("constant multiplication overflow")
 	}
 }
 
-func mpmulfixfix(a *Mpint, b *Mpint) {
+func _mpmulfixfix(a *Mpfix, b *Mpfix) {
 	if a.Ovf != 0 || b.Ovf != 0 {
 		if nsavederrors+nerrors == 0 {
 			Yyerror("ovf in mpmulfixfix")
@@ -260,21 +318,21 @@
 	na := mplen(a)
 
 	nb := mplen(b)
-	var s Mpint
-	var c *Mpint
+	var s Mpfix
+	var c *Mpfix
 	if na > nb {
-		mpmovefixfix(&s, a)
+		_mpmovefixfix(&s, a)
 		c = b
 		na = nb
 	} else {
-		mpmovefixfix(&s, b)
+		_mpmovefixfix(&s, b)
 		c = a
 	}
 
 	s.Neg = 0
 
-	var q Mpint
-	Mpmovecfix(&q, 0)
+	var q Mpfix
+	_Mpmovecfix(&q, 0)
 	var j int
 	var x int
 	for i := 0; i < na; i++ {
@@ -286,7 +344,7 @@
 					goto out
 				}
 
-				mpaddfixfix(&q, &s, 1)
+				_mpaddfixfix(&q, &s, 1)
 				if q.Ovf != 0 {
 					goto out
 				}
@@ -299,13 +357,13 @@
 
 out:
 	q.Neg = a.Neg ^ b.Neg
-	mpmovefixfix(a, &q)
+	_mpmovefixfix(a, &q)
 	if a.Ovf != 0 {
 		Yyerror("constant multiplication overflow")
 	}
 }
 
-func mpmulfract(a *Mpint, b *Mpint) {
+func mpmulfract(a *Mpfix, b *Mpfix) {
 	if a.Ovf != 0 || b.Ovf != 0 {
 		if nsavederrors+nerrors == 0 {
 			Yyerror("ovf in mpmulflt")
@@ -314,11 +372,11 @@
 		return
 	}
 
-	var s Mpint
-	mpmovefixfix(&s, b)
+	var s Mpfix
+	_mpmovefixfix(&s, b)
 	s.Neg = 0
-	var q Mpint
-	Mpmovecfix(&q, 0)
+	var q Mpfix
+	_Mpmovecfix(&q, 0)
 
 	i := Mpprec - 1
 	x := a.A[i]
@@ -337,162 +395,73 @@
 		for j = 0; j < Mpscale; j++ {
 			x <<= 1
 			if x&Mpbase != 0 {
-				mpaddfixfix(&q, &s, 1)
+				_mpaddfixfix(&q, &s, 1)
 			}
 			mprsh(&s)
 		}
 	}
 
 	q.Neg = a.Neg ^ b.Neg
-	mpmovefixfix(a, &q)
+	_mpmovefixfix(a, &q)
 	if a.Ovf != 0 {
 		Yyerror("constant multiplication overflow")
 	}
 }
 
-func mporfixfix(a *Mpint, b *Mpint) {
-	x := 0
-	if a.Ovf != 0 || b.Ovf != 0 {
+func mporfixfix(a, b *Mpint) {
+	if a.Ovf || b.Ovf {
 		if nsavederrors+nerrors == 0 {
 			Yyerror("ovf in mporfixfix")
 		}
-		Mpmovecfix(a, 0)
-		a.Ovf = 1
+		mpsetovf(a)
 		return
 	}
 
-	if a.Neg != 0 {
-		a.Neg = 0
-		mpneg(a)
-	}
-
-	if b.Neg != 0 {
-		mpneg(b)
-	}
-
-	for i := 0; i < Mpprec; i++ {
-		x = a.A[i] | b.A[i]
-		a.A[i] = x
-	}
-
-	if b.Neg != 0 {
-		mpneg(b)
-	}
-	if x&Mpsign != 0 {
-		a.Neg = 1
-		mpneg(a)
-	}
+	a.Val.Or(&a.Val, &b.Val)
 }
 
-func mpandfixfix(a *Mpint, b *Mpint) {
-	x := 0
-	if a.Ovf != 0 || b.Ovf != 0 {
+func mpandfixfix(a, b *Mpint) {
+	if a.Ovf || b.Ovf {
 		if nsavederrors+nerrors == 0 {
 			Yyerror("ovf in mpandfixfix")
 		}
-		Mpmovecfix(a, 0)
-		a.Ovf = 1
+		mpsetovf(a)
 		return
 	}
 
-	if a.Neg != 0 {
-		a.Neg = 0
-		mpneg(a)
-	}
-
-	if b.Neg != 0 {
-		mpneg(b)
-	}
-
-	for i := 0; i < Mpprec; i++ {
-		x = a.A[i] & b.A[i]
-		a.A[i] = x
-	}
-
-	if b.Neg != 0 {
-		mpneg(b)
-	}
-	if x&Mpsign != 0 {
-		a.Neg = 1
-		mpneg(a)
-	}
+	a.Val.And(&a.Val, &b.Val)
 }
 
-func mpandnotfixfix(a *Mpint, b *Mpint) {
-	x := 0
-	if a.Ovf != 0 || b.Ovf != 0 {
+func mpandnotfixfix(a, b *Mpint) {
+	if a.Ovf || b.Ovf {
 		if nsavederrors+nerrors == 0 {
 			Yyerror("ovf in mpandnotfixfix")
 		}
-		Mpmovecfix(a, 0)
-		a.Ovf = 1
+		mpsetovf(a)
 		return
 	}
 
-	if a.Neg != 0 {
-		a.Neg = 0
-		mpneg(a)
-	}
-
-	if b.Neg != 0 {
-		mpneg(b)
-	}
-
-	for i := 0; i < Mpprec; i++ {
-		x = a.A[i] &^ b.A[i]
-		a.A[i] = x
-	}
-
-	if b.Neg != 0 {
-		mpneg(b)
-	}
-	if x&Mpsign != 0 {
-		a.Neg = 1
-		mpneg(a)
-	}
+	a.Val.AndNot(&a.Val, &b.Val)
 }
 
-func mpxorfixfix(a *Mpint, b *Mpint) {
-	x := 0
-	if a.Ovf != 0 || b.Ovf != 0 {
+func mpxorfixfix(a, b *Mpint) {
+	if a.Ovf || b.Ovf {
 		if nsavederrors+nerrors == 0 {
-			Yyerror("ovf in mporfixfix")
+			Yyerror("ovf in mpxorfixfix")
 		}
-		Mpmovecfix(a, 0)
-		a.Ovf = 1
+		mpsetovf(a)
 		return
 	}
 
-	if a.Neg != 0 {
-		a.Neg = 0
-		mpneg(a)
-	}
-
-	if b.Neg != 0 {
-		mpneg(b)
-	}
-
-	for i := 0; i < Mpprec; i++ {
-		x = a.A[i] ^ b.A[i]
-		a.A[i] = x
-	}
-
-	if b.Neg != 0 {
-		mpneg(b)
-	}
-	if x&Mpsign != 0 {
-		a.Neg = 1
-		mpneg(a)
-	}
+	a.Val.Xor(&a.Val, &b.Val)
 }
 
-func mplshfixfix(a *Mpint, b *Mpint) {
-	if a.Ovf != 0 || b.Ovf != 0 {
+func mplshfixfix(a, b *Mpint) {
+	if a.Ovf || b.Ovf {
 		if nsavederrors+nerrors == 0 {
-			Yyerror("ovf in mporfixfix")
+			Yyerror("ovf in mplshfixfix")
 		}
-		Mpmovecfix(a, 0)
-		a.Ovf = 1
+		mpsetovf(a)
 		return
 	}
 
@@ -506,20 +475,19 @@
 	Mpshiftfix(a, int(s))
 }
 
-func mprshfixfix(a *Mpint, b *Mpint) {
-	if a.Ovf != 0 || b.Ovf != 0 {
+func mprshfixfix(a, b *Mpint) {
+	if a.Ovf || b.Ovf {
 		if nsavederrors+nerrors == 0 {
 			Yyerror("ovf in mprshfixfix")
 		}
-		Mpmovecfix(a, 0)
-		a.Ovf = 1
+		mpsetovf(a)
 		return
 	}
 
 	s := Mpgetfix(b)
 	if s < 0 || s >= Mpprec*Mpscale {
 		Yyerror("stupid shift: %d", s)
-		if a.Neg != 0 {
+		if a.Val.Sign() < 0 {
 			Mpmovecfix(a, -1)
 		} else {
 			Mpmovecfix(a, 0)
@@ -531,10 +499,25 @@
 }
 
 func mpnegfix(a *Mpint) {
+	a.Val.Neg(&a.Val)
+}
+
+func _mpnegfix(a *Mpfix) {
 	a.Neg ^= 1
 }
 
 func Mpgetfix(a *Mpint) int64 {
+	if a.Ovf {
+		if nsavederrors+nerrors == 0 {
+			Yyerror("constant overflow")
+		}
+		return 0
+	}
+
+	return a.Val.Int64()
+}
+
+func _Mpgetfix(a *Mpfix) int64 {
 	if a.Ovf != 0 {
 		if nsavederrors+nerrors == 0 {
 			Yyerror("constant overflow")
@@ -552,6 +535,10 @@
 }
 
 func Mpmovecfix(a *Mpint, c int64) {
+	a.Val.SetInt64(c)
+}
+
+func _Mpmovecfix(a *Mpfix, c int64) {
 	a.Neg = 0
 	a.Ovf = 0
 
@@ -567,7 +554,7 @@
 	}
 }
 
-func mpdivmodfixfix(q *Mpint, r *Mpint, n *Mpint, d *Mpint) {
+func mpdivmodfixfix(q *Mpfix, r *Mpfix, n *Mpfix, d *Mpfix) {
 	var i int
 
 	ns := int(n.Neg)
@@ -575,8 +562,8 @@
 	n.Neg = 0
 	d.Neg = 0
 
-	mpmovefixfix(r, n)
-	Mpmovecfix(q, 0)
+	_mpmovefixfix(r, n)
+	_Mpmovecfix(q, 0)
 
 	// shift denominator until it
 	// is larger than numerator
@@ -607,7 +594,7 @@
 		mprsh(d)
 		if mpcmp(d, r) <= 0 {
 			mpaddcfix(q, 1)
-			mpsubfixfix(r, d)
+			_mpsubfixfix(r, d)
 		}
 	}
 
@@ -617,7 +604,7 @@
 	q.Neg = uint8(ns ^ ds)
 }
 
-func mpiszero(a *Mpint) bool {
+func mpiszero(a *Mpfix) bool {
 	for i := Mpprec - 1; i >= 0; i-- {
 		if a.A[i] != 0 {
 			return false
@@ -626,14 +613,14 @@
 	return true
 }
 
-func mpdivfract(a *Mpint, b *Mpint) {
-	var n Mpint
-	var d Mpint
+func mpdivfract(a *Mpfix, b *Mpfix) {
+	var n Mpfix
+	var d Mpfix
 	var j int
 	var x int
 
-	mpmovefixfix(&n, a) // numerator
-	mpmovefixfix(&d, b) // denominator
+	_mpmovefixfix(&n, a) // numerator
+	_mpmovefixfix(&d, b) // denominator
 
 	neg := int(n.Neg) ^ int(d.Neg)
 
@@ -647,7 +634,7 @@
 				if !mpiszero(&d) {
 					x |= 1
 				}
-				mpsubfixfix(&n, &d)
+				_mpsubfixfix(&n, &d)
 			}
 
 			mprsh(&d)
@@ -659,10 +646,10 @@
 	a.Neg = uint8(neg)
 }
 
-func mptestfix(a *Mpint) int {
-	var b Mpint
+func mptestfix(a *Mpfix) int {
+	var b Mpfix
 
-	Mpmovecfix(&b, 0)
+	_Mpmovecfix(&b, 0)
 	r := mpcmp(a, &b)
 	if a.Neg != 0 {
 		if r > 0 {
diff --git a/src/cmd/internal/gc/mparith3.go b/src/cmd/internal/gc/mparith3.go
index 103c53d..57263a0 100644
--- a/src/cmd/internal/gc/mparith3.go
+++ b/src/cmd/internal/gc/mparith3.go
@@ -80,7 +80,7 @@
 		}
 	}
 
-	Mpshiftfix(&a.Val, s)
+	_Mpshiftfix(&a.Val, s)
 	mpsetexp(a, int(a.Exp)-s)
 }
 
@@ -110,21 +110,21 @@
 		var c Mpflt
 		mpmovefltflt(&c, b)
 
-		Mpshiftfix(&c.Val, -s)
-		mpaddfixfix(&a.Val, &c.Val, 0)
+		_Mpshiftfix(&c.Val, -s)
+		_mpaddfixfix(&a.Val, &c.Val, 0)
 		goto out
 	}
 
 	if s < 0 {
 		// b is larger, shift a right
-		Mpshiftfix(&a.Val, s)
+		_Mpshiftfix(&a.Val, s)
 
 		mpsetexp(a, int(a.Exp)-s)
-		mpaddfixfix(&a.Val, &b.Val, 0)
+		_mpaddfixfix(&a.Val, &b.Val, 0)
 		goto out
 	}
 
-	mpaddfixfix(&a.Val, &b.Val, 0)
+	_mpaddfixfix(&a.Val, &b.Val, 0)
 
 out:
 	mpnorm(a)
@@ -193,7 +193,7 @@
 	var c Mpflt
 	mpmovefltflt(&c, b)
 
-	Mpshiftfix(&c.Val, Mpscale)
+	_Mpshiftfix(&c.Val, Mpscale)
 
 	// divide
 	mpdivfract(&a.Val, &c.Val)
@@ -222,7 +222,7 @@
 	}
 
 	for a.Val.A[Mpnorm-1]&Mpsign == 0 {
-		Mpshiftfix(&a.Val, 1)
+		_Mpshiftfix(&a.Val, 1)
 		mpsetexp(a, int(a.Exp)-1) // can set 'a' to zero
 		s = sigfig(a)
 		if s == 0 {
@@ -298,7 +298,7 @@
 	if Mpdebug != 0 /*TypeKind(100016)*/ {
 		fmt.Printf("\nconst %g", c)
 	}
-	Mpmovecfix(&a.Val, 0)
+	_Mpmovecfix(&a.Val, 0)
 	a.Exp = 0
 	var f float64
 	var l int
@@ -323,7 +323,7 @@
 		if f == 0 {
 			break
 		}
-		Mpshiftfix(&a.Val, Mpscale)
+		_Mpshiftfix(&a.Val, Mpscale)
 	}
 
 out:
diff --git a/src/cmd/internal/gc/obj.go b/src/cmd/internal/gc/obj.go
index 27a1811..34c1070 100644
--- a/src/cmd/internal/gc/obj.go
+++ b/src/cmd/internal/gc/obj.go
@@ -7,6 +7,7 @@
 import (
 	"cmd/internal/obj"
 	"fmt"
+	"strconv"
 )
 
 /*
@@ -71,7 +72,7 @@
 
 	fmt.Fprintf(bout, "\n!\n")
 
-	externs := (*NodeList)(nil)
+	var externs *NodeList
 	if externdcl != nil {
 		externs = externdcl.End
 	}
@@ -101,8 +102,8 @@
 			obj.Bputc(bout, 0)
 		}
 		obj.Bseek(bout, startobj-ArhdrSize, 0)
-		namebuf = fmt.Sprintf("_go_.%c", Thearch.Thechar)
-		formathdr(arhdr[:], namebuf, size)
+		name := fmt.Sprintf("_go_.%c", Thearch.Thechar)
+		formathdr(arhdr[:], name, size)
 		obj.Bwrite(bout, arhdr[:])
 	}
 
@@ -135,7 +136,7 @@
 
 	for l := funcsyms; l != nil; l = l.Next {
 		n = l.N
-		dsymptr(n.Sym, 0, n.Sym.Def.Shortname.Sym, 0)
+		dsymptr(n.Sym, 0, n.Sym.Def.Func.Shortname.Sym, 0)
 		ggloblsym(n.Sym, int32(Widthptr), obj.DUPOK|obj.RODATA)
 	}
 
@@ -155,16 +156,18 @@
 	if s.Lsym != nil {
 		return s.Lsym
 	}
+	var name string
 	if isblanksym(s) {
-		s.Lsym = obj.Linklookup(Ctxt, "_", 0)
+		name = "_"
 	} else if s.Linkname != "" {
-		s.Lsym = obj.Linklookup(Ctxt, s.Linkname, 0)
+		name = s.Linkname
 	} else {
-		p := fmt.Sprintf("%s.%s", s.Pkg.Prefix, s.Name)
-		s.Lsym = obj.Linklookup(Ctxt, p, 0)
+		name = s.Pkg.Prefix + "." + s.Name
 	}
 
-	return s.Lsym
+	ls := obj.Linklookup(Ctxt, name, 0)
+	s.Lsym = ls
+	return ls
 }
 
 func duintxx(s *Sym, off int, v uint64, wid int) int {
@@ -199,28 +202,23 @@
 var stringsym_gen int
 
 func stringsym(s string) *Sym {
-	var tmp struct {
-		lit Strlit
-		buf string
-	}
+	var symname string
 	var pkg *Pkg
-
 	if len(s) > 100 {
 		// huge strings are made static to avoid long names
 		stringsym_gen++
-		namebuf = fmt.Sprintf(".gostring.%d", stringsym_gen)
+		symname = fmt.Sprintf(".gostring.%d", stringsym_gen)
 
 		pkg = localpkg
 	} else {
 		// small strings get named by their contents,
 		// so that multiple modules using the same string
 		// can share it.
-		tmp.lit.S = s
-		namebuf = fmt.Sprintf("\"%v\"", Zconv(&tmp.lit, 0))
+		symname = strconv.Quote(s)
 		pkg = gostringpkg
 	}
 
-	sym := Pkglookup(namebuf, pkg)
+	sym := Pkglookup(symname, pkg)
 
 	// SymUniq flag indicates that data is generated already
 	if sym.Flags&SymUniq != 0 {
@@ -258,8 +256,8 @@
 	var m int
 
 	slicebytes_gen++
-	namebuf = fmt.Sprintf(".gobytes.%d", slicebytes_gen)
-	sym := Pkglookup(namebuf, localpkg)
+	symname := fmt.Sprintf(".gobytes.%d", slicebytes_gen)
+	sym := Pkglookup(symname, localpkg)
 	sym.Def = newname(sym)
 
 	off := 0
@@ -300,9 +298,6 @@
 	return off
 }
 
-/*
- * gobj.c
- */
 func Datastring(s string, a *obj.Addr) {
 	sym := stringsym(s)
 	a.Type = obj.TYPE_MEM
@@ -313,8 +308,8 @@
 	a.Etype = Simtype[TINT]
 }
 
-func datagostring(sval *Strlit, a *obj.Addr) {
-	sym := stringsym(sval.S)
+func datagostring(sval string, a *obj.Addr) {
+	sym := stringsym(sval)
 	a.Type = obj.TYPE_MEM
 	a.Name = obj.NAME_EXTERN
 	a.Sym = Linksym(sym)
@@ -327,19 +322,13 @@
 	if str == "" {
 		return duintptr(s, off, 0)
 	}
-
-	n := len(str)
-	lit := new(Strlit)
-	lit.S = str
-	lit.S = lit.S[:n]
-	return dgostrlitptr(s, off, lit)
+	return dgostrlitptr(s, off, &str)
 }
 
-func dgostrlitptr(s *Sym, off int, lit *Strlit) int {
+func dgostrlitptr(s *Sym, off int, lit *string) int {
 	if lit == nil {
 		return duintptr(s, off, 0)
 	}
-
 	off = int(Rnd(int64(off), int64(Widthptr)))
 	p := Thearch.Gins(obj.ADATA, nil, nil)
 	p.From.Type = obj.TYPE_MEM
@@ -348,7 +337,7 @@
 	p.From.Offset = int64(off)
 	p.From3.Type = obj.TYPE_CONST
 	p.From3.Offset = int64(Widthptr)
-	datagostring(lit, &p.To)
+	datagostring(*lit, &p.To)
 	p.To.Type = obj.TYPE_ADDR
 	p.To.Etype = Simtype[TINT]
 	off += Widthptr
@@ -366,7 +355,7 @@
 	p.From3.Offset = int64(len(t))
 
 	p.To.Type = obj.TYPE_SCONST
-	p.To.U.Sval = t
+	p.To.Val = t
 	return off + len(t)
 }
 
@@ -415,28 +404,28 @@
 	p.From3.Type = obj.TYPE_CONST
 	p.From3.Offset = int64(w)
 	p.To.Type = obj.TYPE_FCONST
-	p.To.U.Dval = mpgetflt(&cval.Real)
+	p.To.Val = mpgetflt(&cval.Real)
 
 	p = Thearch.Gins(obj.ADATA, nam, nil)
 	p.From3.Type = obj.TYPE_CONST
 	p.From3.Offset = int64(w)
 	p.From.Offset += int64(w)
 	p.To.Type = obj.TYPE_FCONST
-	p.To.U.Dval = mpgetflt(&cval.Imag)
+	p.To.Val = mpgetflt(&cval.Imag)
 }
 
-func gdatastring(nam *Node, sval *Strlit) {
+func gdatastring(nam *Node, sval string) {
 	var nod1 Node
 
 	p := Thearch.Gins(obj.ADATA, nam, nil)
-	Datastring(sval.S, &p.To)
+	Datastring(sval, &p.To)
 	p.From3.Type = obj.TYPE_CONST
 	p.From3.Offset = Types[Tptr].Width
 	p.To.Type = obj.TYPE_ADDR
 
 	//print("%P\n", p);
 
-	Nodconst(&nod1, Types[TINT], int64(len(sval.S)))
+	Nodconst(&nod1, Types[TINT], int64(len(sval)))
 
 	p = Thearch.Gins(obj.ADATA, nam, &nod1)
 	p.From3.Type = obj.TYPE_CONST
diff --git a/src/cmd/internal/gc/order.go b/src/cmd/internal/gc/order.go
index e8744d7..9dc9b69 100644
--- a/src/cmd/internal/gc/order.go
+++ b/src/cmd/internal/gc/order.go
@@ -41,9 +41,9 @@
 
 // Order holds state during the ordering process.
 type Order struct {
-	out  *NodeList
-	temp *NodeList
-	free *NodeList
+	out  *NodeList // list of generated statements
+	temp *NodeList // head of stack of temporary variables
+	free *NodeList // free list of NodeList* structs (for use in temp)
 }
 
 // Order rewrites fn->nbody to apply the ordering constraints
@@ -105,8 +105,7 @@
 // and then returns tmp.
 func ordercheapexpr(n *Node, order *Order) *Node {
 	switch n.Op {
-	case ONAME,
-		OLITERAL:
+	case ONAME, OLITERAL:
 		return n
 	}
 
@@ -122,8 +121,7 @@
 // The intended use is to apply to x when rewriting x += y into x = x + y.
 func ordersafeexpr(n *Node, order *Order) *Node {
 	switch n.Op {
-	case ONAME,
-		OLITERAL:
+	case ONAME, OLITERAL:
 		return n
 
 	case ODOT:
@@ -138,8 +136,7 @@
 		typecheck(&a, Erv)
 		return a
 
-	case ODOTPTR,
-		OIND:
+	case ODOTPTR, OIND:
 		l := ordercheapexpr(n.Left, order)
 		if l == n.Left {
 			return n
@@ -151,8 +148,7 @@
 		typecheck(&a, Erv)
 		return a
 
-	case OINDEX,
-		OINDEXMAP:
+	case OINDEX, OINDEXMAP:
 		var l *Node
 		if Isfixedarray(n.Left.Type) {
 			l = ordersafeexpr(n.Left, order)
@@ -256,7 +252,7 @@
 // Orderblock orders the block of statements *l onto a new list,
 // and then replaces *l with that list.
 func orderblock(l **NodeList) {
-	order := Order{}
+	var order Order
 	mark := marktemp(&order)
 	orderstmtlist(*l, &order)
 	cleantemp(mark, &order)
@@ -267,7 +263,7 @@
 // leaves them as the init list of the final *np.
 func orderexprinplace(np **Node, outer *Order) {
 	n := *np
-	order := Order{}
+	var order Order
 	orderexpr(&n, &order)
 	addinit(&n, order.out)
 
@@ -288,7 +284,7 @@
 // and replaces it with the resulting statement list.
 func orderstmtinplace(np **Node) {
 	n := *np
-	order := Order{}
+	var order Order
 	mark := marktemp(&order)
 	orderstmt(n, &order)
 	cleantemp(mark, &order)
@@ -315,9 +311,7 @@
 	default:
 		return false
 
-	case OCALLFUNC,
-		OCALLMETH,
-		OCALLINTER:
+	case OCALLFUNC, OCALLMETH, OCALLINTER:
 		break
 	}
 
@@ -332,8 +326,8 @@
 		Fatal("copyret %v %d", Tconv(n.Type, 0), n.Left.Type.Outtuple)
 	}
 
-	l1 := (*NodeList)(nil)
-	l2 := (*NodeList)(nil)
+	var l1 *NodeList
+	var l2 *NodeList
 	var tl Iter
 	var tmp *Node
 	for t := Structfirst(&tl, &n.Type); t != nil; t = structnext(&tl) {
@@ -409,11 +403,8 @@
 			order.out = list(order.out, a)
 		}
 
-	case OAS2,
-		OAS2DOTTYPE,
-		OAS2MAPR,
-		OAS2FUNC:
-		post := (*NodeList)(nil)
+	case OAS2, OAS2DOTTYPE, OAS2MAPR, OAS2FUNC:
+		var post *NodeList
 		var m *Node
 		var a *Node
 		for l := n.List; l != nil; l = l.Next {
@@ -470,9 +461,7 @@
 		orderexprlist(n.List, order)
 		orderexprlist(n.Rlist, order)
 		switch n.Op {
-		case OAS,
-			OAS2,
-			OAS2DOTTYPE:
+		case OAS, OAS2, OAS2DOTTYPE:
 			ordermapassign(n, order)
 
 		default:
@@ -579,8 +568,7 @@
 		cleantemp(t, order)
 
 		// Special: does not save n onto out.
-	case OBLOCK,
-		OEMPTY:
+	case OBLOCK, OEMPTY:
 		orderstmtlist(n.List, order)
 
 		// Special: n->left is not an expression; save as is.
@@ -597,9 +585,7 @@
 		order.out = list(order.out, n)
 
 		// Special: handle call arguments.
-	case OCALLFUNC,
-		OCALLINTER,
-		OCALLMETH:
+	case OCALLFUNC, OCALLINTER, OCALLMETH:
 		t := marktemp(order)
 
 		ordercall(n, order)
@@ -607,8 +593,7 @@
 		cleantemp(t, order)
 
 		// Special: order arguments to inner call but not call itself.
-	case ODEFER,
-		OPROC:
+	case ODEFER, OPROC:
 		t := marktemp(order)
 
 		switch n.Left.Op {
@@ -644,7 +629,7 @@
 		t := marktemp(order)
 
 		orderexprinplace(&n.Ntest, order)
-		l := (*NodeList)(nil)
+		var l *NodeList
 		cleantempnopop(t, order, &l)
 		n.Nbody = concat(l, n.Nbody)
 		orderblock(&n.Nbody)
@@ -658,7 +643,7 @@
 		t := marktemp(order)
 
 		orderexprinplace(&n.Ntest, order)
-		l := (*NodeList)(nil)
+		var l *NodeList
 		cleantempnopop(t, order, &l)
 		n.Nbody = concat(l, n.Nbody)
 		l = nil
@@ -713,8 +698,7 @@
 			// chan, string, slice, array ranges use value multiple times.
 		// make copy.
 		// fall through
-		case TCHAN,
-			TSTRING:
+		case TCHAN, TSTRING:
 			r := n.Right
 
 			if r.Type.Etype == TSTRING && r.Type != Types[TSTRING] {
@@ -785,8 +769,7 @@
 				// the ODCL nodes to declare x and y. We want to delay that
 				// declaration (and possible allocation) until inside the case body.
 				// Delete the ODCL nodes here and recreate them inside the body below.
-				case OSELRECV,
-					OSELRECV2:
+				case OSELRECV, OSELRECV2:
 					if r.Colas != 0 {
 						t = r.Ninit
 						if t != nil && t.N.Op == ODCL && t.N.Left == r.Left {
@@ -991,7 +974,7 @@
 		haslit := false
 		for l := n.List; l != nil; l = l.Next {
 			hasbyte = hasbyte || l.N.Op == OARRAYBYTESTR
-			haslit = haslit || l.N.Op == OLITERAL && len(l.N.Val.U.Sval.S) != 0
+			haslit = haslit || l.N.Op == OLITERAL && len(l.N.Val.U.Sval) != 0
 		}
 
 		if haslit && hasbyte {
@@ -1052,15 +1035,14 @@
 			orderaddrtemp(&n.Left, order)
 		}
 
-	case OANDAND,
-		OOROR:
+	case OANDAND, OOROR:
 		mark := marktemp(order)
 		orderexpr(&n.Left, order)
 
 		// Clean temporaries from first branch at beginning of second.
 		// Leave them on the stack so that they can be killed in the outer
 		// context in case the short circuit is taken.
-		l := (*NodeList)(nil)
+		var l *NodeList
 
 		cleantempnopop(mark, order, &l)
 		n.Right.Ninit = concat(l, n.Right.Ninit)
@@ -1085,12 +1067,11 @@
 		n = ordercopyexpr(n, n.Type, order, 0)
 
 	case OCLOSURE:
-		if n.Noescape && n.Cvars != nil {
+		if n.Noescape && n.Func.Cvars != nil {
 			n.Alloc = ordertemp(Types[TUINT8], order, false) // walk will fill in correct type
 		}
 
-	case OARRAYLIT,
-		OCALLPART:
+	case OARRAYLIT, OCALLPART:
 		orderexpr(&n.Left, order)
 		orderexpr(&n.Right, order)
 		orderexprlist(n.List, order)
@@ -1108,13 +1089,20 @@
 			n.Alloc = ordertemp(n.Type.Type, order, false)
 		}
 
-	case ORECV,
-		ODOTTYPE:
+	case ODOTTYPE, ODOTTYPE2:
+		orderexpr(&n.Left, order)
+		// TODO(rsc): The Isfat is for consistency with componentgen and walkexpr.
+		// It needs to be removed in all three places.
+		// That would allow inlining x.(struct{*int}) the same as x.(*int).
+		if !isdirectiface(n.Type) || Isfat(n.Type) || flag_race != 0 {
+			n = ordercopyexpr(n, n.Type, order, 1)
+		}
+
+	case ORECV:
 		orderexpr(&n.Left, order)
 		n = ordercopyexpr(n, n.Type, order, 1)
 
-	case OEQ,
-		ONE:
+	case OEQ, ONE:
 		orderexpr(&n.Left, order)
 		orderexpr(&n.Right, order)
 		t := n.Left.Type
diff --git a/src/cmd/internal/gc/pgen.go b/src/cmd/internal/gc/pgen.go
index b3045a0..b6c9f30 100644
--- a/src/cmd/internal/gc/pgen.go
+++ b/src/cmd/internal/gc/pgen.go
@@ -6,24 +6,20 @@
 
 import (
 	"cmd/internal/obj"
+	"crypto/md5"
 	"fmt"
 	"strings"
 )
 
 // "Portable" code generation.
-// Compiled separately for 5g, 6g, and 8g, so allowed to use gg.h, opt.h.
-// Must code to the intersection of the three back ends.
-
-//#include	"opt.h"
 
 var makefuncdatasym_nsym int32
 
 func makefuncdatasym(namefmt string, funcdatakind int64) *Sym {
 	var nod Node
 
-	namebuf = fmt.Sprintf(namefmt, makefuncdatasym_nsym)
+	sym := Lookupf(namefmt, makefuncdatasym_nsym)
 	makefuncdatasym_nsym++
-	sym := Lookup(namebuf)
 	pnod := newname(sym)
 	pnod.Class = PEXTERN
 	Nodconst(&nod, Types[TINT32], funcdatakind)
@@ -97,9 +93,7 @@
 	}
 
 	switch n.Class {
-	case PAUTO,
-		PPARAM,
-		PPARAMOUT:
+	case PAUTO, PPARAM, PPARAMOUT:
 		Thearch.Gins(as, nil, n)
 	}
 }
@@ -118,8 +112,8 @@
 			p.Link = p.Link.Link
 		}
 		if p.To.Type == obj.TYPE_BRANCH {
-			for p.To.U.Branch != nil && (p.To.U.Branch.As == obj.AVARDEF || p.To.U.Branch.As == obj.AVARKILL) {
-				p.To.U.Branch = p.To.U.Branch.Link
+			for p.To.Val.(*obj.Prog) != nil && (p.To.Val.(*obj.Prog).As == obj.AVARDEF || p.To.Val.(*obj.Prog).As == obj.AVARKILL) {
+				p.To.Val = p.To.Val.(*obj.Prog).Link
 			}
 		}
 	}
@@ -130,12 +124,7 @@
 	if len(ls.R) > 0 {
 		Fatal("cannot rosymdup %s with relocations", ls.Name)
 	}
-	var d MD5
-	md5reset(&d)
-	md5write(&d, ls.P, len(ls.P))
-	var hi uint64
-	lo := md5sum(&d, &hi)
-	ls.Name = fmt.Sprintf("gclocals·%016x%016x", lo, hi)
+	ls.Name = fmt.Sprintf("gclocals·%x", md5.Sum(ls.P))
 	ls.Dupok = 1
 }
 
@@ -201,8 +190,8 @@
 		return 0
 	}
 
-	if (a.Used == 0) != (b.Used == 0) {
-		return int(b.Used) - int(a.Used)
+	if a.Used != b.Used {
+		return bool2int(b.Used) - bool2int(a.Used)
 	}
 
 	ap := bool2int(haspointers(a.Type))
@@ -211,8 +200,8 @@
 		return bp - ap
 	}
 
-	ap = int(a.Needzero)
-	bp = int(b.Needzero)
+	ap = bool2int(a.Needzero)
+	bp = bool2int(b.Needzero)
 	if ap != bp {
 		return bp - ap
 	}
@@ -232,45 +221,45 @@
 	Stksize = 0
 	stkptrsize = 0
 
-	if Curfn.Dcl == nil {
+	if Curfn.Func.Dcl == nil {
 		return
 	}
 
 	// Mark the PAUTO's unused.
-	for ll := Curfn.Dcl; ll != nil; ll = ll.Next {
+	for ll := Curfn.Func.Dcl; ll != nil; ll = ll.Next {
 		if ll.N.Class == PAUTO {
-			ll.N.Used = 0
+			ll.N.Used = false
 		}
 	}
 
 	markautoused(ptxt)
 
-	listsort(&Curfn.Dcl, cmpstackvar)
+	listsort(&Curfn.Func.Dcl, cmpstackvar)
 
 	// Unused autos are at the end, chop 'em off.
-	ll := Curfn.Dcl
+	ll := Curfn.Func.Dcl
 
 	n := ll.N
-	if n.Class == PAUTO && n.Op == ONAME && n.Used == 0 {
+	if n.Class == PAUTO && n.Op == ONAME && !n.Used {
 		// No locals used at all
-		Curfn.Dcl = nil
+		Curfn.Func.Dcl = nil
 
 		fixautoused(ptxt)
 		return
 	}
 
-	for ll := Curfn.Dcl; ll.Next != nil; ll = ll.Next {
+	for ll := Curfn.Func.Dcl; ll.Next != nil; ll = ll.Next {
 		n = ll.Next.N
-		if n.Class == PAUTO && n.Op == ONAME && n.Used == 0 {
+		if n.Class == PAUTO && n.Op == ONAME && !n.Used {
 			ll.Next = nil
-			Curfn.Dcl.End = ll
+			Curfn.Func.Dcl.End = ll
 			break
 		}
 	}
 
 	// Reassign stack offsets of the locals that are still there.
 	var w int64
-	for ll := Curfn.Dcl; ll != nil; ll = ll.Next {
+	for ll := Curfn.Func.Dcl; ll != nil; ll = ll.Next {
 		n = ll.N
 		if n.Class != PAUTO || n.Op != ONAME {
 			continue
@@ -286,7 +275,7 @@
 		if haspointers(n.Type) {
 			stkptrsize = Stksize
 		}
-		if Thearch.Thechar == '5' || Thearch.Thechar == '9' {
+		if Thearch.Thechar == '5' || Thearch.Thechar == '7' || Thearch.Thechar == '9' {
 			Stksize = Rnd(Stksize, int64(Widthptr))
 		}
 		if Stksize >= 1<<31 {
@@ -303,7 +292,7 @@
 	fixautoused(ptxt)
 
 	// The debug information needs accurate offsets on the symbols.
-	for ll := Curfn.Dcl; ll != nil; ll = ll.Next {
+	for ll := Curfn.Func.Dcl; ll != nil; ll = ll.Next {
 		if ll.N.Class != PAUTO || ll.N.Op != ONAME {
 			continue
 		}
@@ -323,7 +312,7 @@
 func movelargefn(fn *Node) {
 	var n *Node
 
-	for l := fn.Dcl; l != nil; l = l.Next {
+	for l := fn.Func.Dcl; l != nil; l = l.Next {
 		n = l.N
 		if n.Class == PAUTO && n.Type != nil && n.Type.Width > MaxStackVarSize {
 			addrescapes(n)
@@ -337,26 +326,23 @@
 	}
 
 	// Ideally we wouldn't see any integer types here, but we do.
-	if n.Type == nil || (Isptr[n.Type.Etype] == 0 && Isint[n.Type.Etype] == 0 && n.Type.Etype != TUNSAFEPTR) {
+	if n.Type == nil || (!Isptr[n.Type.Etype] && !Isint[n.Type.Etype] && n.Type.Etype != TUNSAFEPTR) {
 		Dump("checknil", n)
 		Fatal("bad checknil")
 	}
 
-	if ((Thearch.Thechar == '5' || Thearch.Thechar == '9') && n.Op != OREGISTER) || n.Addable == 0 || n.Op == OLITERAL {
+	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
 	}
 
 	Thearch.Gins(obj.ACHECKNIL, n, nil)
 }
 
-/*
- * ggen.c
- */
 func compile(fn *Node) {
 	if Newproc == nil {
 		Newproc = Sysfunc("newproc")
@@ -446,16 +432,16 @@
 		nam = nil
 	}
 	ptxt = Thearch.Gins(obj.ATEXT, nam, &nod1)
-	if fn.Dupok != 0 {
+	if fn.Func.Dupok {
 		ptxt.From3.Offset |= obj.DUPOK
 	}
-	if fn.Wrapper != 0 {
+	if fn.Func.Wrapper {
 		ptxt.From3.Offset |= obj.WRAPPER
 	}
-	if fn.Needctxt {
+	if fn.Func.Needctxt {
 		ptxt.From3.Offset |= obj.NEEDCTXT
 	}
-	if fn.Nosplit {
+	if fn.Func.Nosplit {
 		ptxt.From3.Offset |= obj.NOSPLIT
 	}
 
@@ -470,7 +456,7 @@
 
 	Afunclit(&ptxt.From, Curfn.Nname)
 
-	Thearch.Ginit()
+	ginit()
 
 	gcargs = makefuncdatasym("gcargs·%d", obj.FUNCDATA_ArgsPointerMaps)
 	gclocals = makefuncdatasym("gclocals·%d", obj.FUNCDATA_LocalsPointerMaps)
@@ -479,40 +465,38 @@
 		gtrack(tracksym(t.Type))
 	}
 
-	for l := fn.Dcl; l != nil; l = l.Next {
+	for l := fn.Func.Dcl; l != nil; l = l.Next {
 		n = l.N
 		if n.Op != ONAME { // might be OTYPE or OLITERAL
 			continue
 		}
 		switch n.Class {
-		case PAUTO,
-			PPARAM,
-			PPARAMOUT:
+		case PAUTO, PPARAM, PPARAMOUT:
 			Nodconst(&nod1, Types[TUINTPTR], l.N.Type.Width)
 			p = Thearch.Gins(obj.ATYPE, l.N, &nod1)
 			p.From.Gotype = Linksym(ngotype(l.N))
 		}
 	}
 
-	Genlist(Curfn.Enter)
+	Genlist(Curfn.Func.Enter)
 	Genlist(Curfn.Nbody)
-	Thearch.Gclean()
+	gclean()
 	checklabels()
 	if nerrors != 0 {
 		goto ret
 	}
-	if Curfn.Endlineno != 0 {
-		lineno = Curfn.Endlineno
+	if Curfn.Func.Endlineno != 0 {
+		lineno = Curfn.Func.Endlineno
 	}
 
 	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.
@@ -522,7 +506,7 @@
 		}
 	}
 
-	Thearch.Gclean()
+	gclean()
 	if nerrors != 0 {
 		goto ret
 	}
diff --git a/src/cmd/internal/gc/plive.go b/src/cmd/internal/gc/plive.go
index 86e7ea0..876f43e 100644
--- a/src/cmd/internal/gc/plive.go
+++ b/src/cmd/internal/gc/plive.go
@@ -2,6 +2,17 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
+// Garbage collector liveness bitmap generation.
+
+// The command line flag -live causes this code to print debug information.
+// The levels are:
+//
+//	-live (aka -live=1): print liveness lists as code warnings at safe points
+//	-live=2: print an assembly listing with liveness annotations
+//	-live=3: print information during each computation phase (much chattier)
+//
+// Each level includes the earlier output as well.
+
 package gc
 
 import (
@@ -34,30 +45,51 @@
 //     ...
 //   }
 type BasicBlock struct {
-	pred            []*BasicBlock
-	succ            []*BasicBlock
-	first           *obj.Prog
-	last            *obj.Prog
-	rpo             int
-	mark            int
-	lastbitmapindex int
+	pred            []*BasicBlock // predecessors; if none, probably start of CFG
+	succ            []*BasicBlock // successors; if none, probably ends in return statement
+	first           *obj.Prog     // first instruction in block
+	last            *obj.Prog     // last instruction in block
+	rpo             int           // reverse post-order number (also index in cfg)
+	mark            int           // mark bit for traversals
+	lastbitmapindex int           // for livenessepilogue
+
+	// Summary sets of block effects.
+
+	// Computed during livenessprologue using only the content of
+	// individual blocks:
+	//
+	//	uevar: upward exposed variables (used before set in block)
+	//	varkill: killed variables (set in block)
+	//	avarinit: addrtaken variables set or used (proof of initialization)
+	uevar    Bvec
+	varkill  Bvec
+	avarinit Bvec
+
+	// Computed during livenesssolve using control flow information:
+	//
+	//	livein: variables live at block entry
+	//	liveout: variables live at block exit
+	//	avarinitany: addrtaken variables possibly initialized at block exit
+	//		(initialized in block or at exit from any predecessor block)
+	//	avarinitall: addrtaken variables certainly initialized at block exit
+	//		(initialized in block or at exit from all predecessor blocks)
+	livein      Bvec
+	liveout     Bvec
+	avarinitany Bvec
+	avarinitall Bvec
 }
 
 // A collection of global state used by liveness analysis.
 type Liveness struct {
-	fn               *Node
-	ptxt             *obj.Prog
-	vars             []*Node
-	cfg              []*BasicBlock
-	uevar            []*Bvec
-	varkill          []*Bvec
-	livein           []*Bvec
-	liveout          []*Bvec
-	avarinit         []*Bvec
-	avarinitany      []*Bvec
-	avarinitall      []*Bvec
-	argslivepointers []*Bvec
-	livepointers     []*Bvec
+	fn   *Node
+	ptxt *obj.Prog
+	vars []*Node
+	cfg  []*BasicBlock
+
+	// An array with a bit vector for each safe point tracking live pointers
+	// in the arguments and locals area, indexed by bb.rpo.
+	argslivepointers []Bvec
+	livepointers     []Bvec
 }
 
 func xmalloc(size uint32) interface{} {
@@ -143,23 +175,16 @@
 
 // A pretty printer for basic blocks.
 func printblock(bb *BasicBlock) {
-	var pred *BasicBlock
-
 	fmt.Printf("basic block %d\n", bb.rpo)
 	fmt.Printf("\tpred:")
-	for i := 0; i < len(bb.pred); i++ {
-		pred = bb.pred[i]
+	for _, pred := range bb.pred {
 		fmt.Printf(" %d", pred.rpo)
 	}
-
 	fmt.Printf("\n")
 	fmt.Printf("\tsucc:")
-	var succ *BasicBlock
-	for i := 0; i < len(bb.succ); i++ {
-		succ = bb.succ[i]
+	for _, succ := range bb.succ {
 		fmt.Printf(" %d", succ.rpo)
 	}
-
 	fmt.Printf("\n")
 	fmt.Printf("\tprog:\n")
 	for prog := bb.first; ; prog = prog.Link {
@@ -187,7 +212,7 @@
 // variables.
 func getvariables(fn *Node) []*Node {
 	result := make([]*Node, 0, 0)
-	for ll := fn.Dcl; ll != nil; ll = ll.Next {
+	for ll := fn.Func.Dcl; ll != nil; ll = ll.Next {
 		if ll.N.Op == ONAME {
 			// In order for GODEBUG=gcdead=1 to work, each bitmap needs
 			// to contain information about all variables covered by the bitmap.
@@ -218,8 +243,7 @@
 					result = append(result, ll.N)
 				}
 
-			case PPARAM,
-				PPARAMOUT:
+			case PPARAM, PPARAMOUT:
 				ll.N.Opt = int32(len(result))
 				result = append(result, ll.N)
 			}
@@ -231,10 +255,7 @@
 
 // A pretty printer for control flow graphs.  Takes an array of BasicBlock*s.
 func printcfg(cfg []*BasicBlock) {
-	var bb *BasicBlock
-
-	for i := int32(0); i < int32(len(cfg)); i++ {
-		bb = cfg[i]
+	for _, bb := range cfg {
 		printblock(bb)
 	}
 }
@@ -242,16 +263,12 @@
 // Assigns a reverse post order number to each connected basic block using the
 // standard algorithm.  Unconnected blocks will not be affected.
 func reversepostorder(root *BasicBlock, rpo *int32) {
-	var bb *BasicBlock
-
 	root.mark = VISITED
-	for i := 0; i < len(root.succ); i++ {
-		bb = root.succ[i]
+	for _, bb := range root.succ {
 		if bb.mark == UNVISITED {
 			reversepostorder(bb, rpo)
 		}
 	}
-
 	*rpo -= 1
 	root.rpo = int(*rpo)
 }
@@ -282,18 +299,18 @@
 // Returns true for instructions that call a runtime function implementing a
 // select communication clause.
 
-var isselectcommcasecall_names [5]*obj.LSym
+var selectNames [4]*obj.LSym
 
 func isselectcommcasecall(prog *obj.Prog) bool {
-	if isselectcommcasecall_names[0] == nil {
-		isselectcommcasecall_names[0] = Linksym(Pkglookup("selectsend", Runtimepkg))
-		isselectcommcasecall_names[1] = Linksym(Pkglookup("selectrecv", Runtimepkg))
-		isselectcommcasecall_names[2] = Linksym(Pkglookup("selectrecv2", Runtimepkg))
-		isselectcommcasecall_names[3] = Linksym(Pkglookup("selectdefault", Runtimepkg))
+	if selectNames[0] == nil {
+		selectNames[0] = Linksym(Pkglookup("selectsend", Runtimepkg))
+		selectNames[1] = Linksym(Pkglookup("selectrecv", Runtimepkg))
+		selectNames[2] = Linksym(Pkglookup("selectrecv2", Runtimepkg))
+		selectNames[3] = Linksym(Pkglookup("selectdefault", Runtimepkg))
 	}
 
-	for i := int32(0); isselectcommcasecall_names[i] != nil; i++ {
-		if iscall(prog, isselectcommcasecall_names[i]) {
+	for _, name := range selectNames {
+		if iscall(prog, name) {
 			return true
 		}
 	}
@@ -374,10 +391,7 @@
 // The entry point for the missing selectgo control flow algorithm.  Takes an
 // array of BasicBlock*s containing selectgo calls.
 func fixselectgo(selectgo []*BasicBlock) {
-	var bb *BasicBlock
-
-	for i := int32(0); i < int32(len(selectgo)); i++ {
-		bb = selectgo[i]
+	for _, bb := range selectgo {
 		addselectgosucc(bb)
 	}
 }
@@ -407,13 +421,14 @@
 	bb := newblock(firstp)
 	cfg = append(cfg, bb)
 	for p := firstp; p != nil; p = p.Link {
+		Thearch.Proginfo(p)
 		if p.To.Type == obj.TYPE_BRANCH {
-			if p.To.U.Branch == nil {
+			if p.To.Val == nil {
 				Fatal("prog branch to nil")
 			}
-			if p.To.U.Branch.Opt == nil {
-				p.To.U.Branch.Opt = newblock(p.To.U.Branch)
-				cfg = append(cfg, p.To.U.Branch.Opt.(*BasicBlock))
+			if p.To.Val.(*obj.Prog).Opt == nil {
+				p.To.Val.(*obj.Prog).Opt = newblock(p.To.Val.(*obj.Prog))
+				cfg = append(cfg, p.To.Val.(*obj.Prog).Opt.(*BasicBlock))
 			}
 
 			if p.As != obj.AJMP && p.Link != nil && p.Link.Opt == nil {
@@ -432,10 +447,8 @@
 	// Loop through all basic blocks maximally growing the list of
 	// contained instructions until a label is reached.  Add edges
 	// for branches and fall-through instructions.
-	var p *obj.Prog
-	for i := int32(0); i < int32(len(cfg)); i++ {
-		bb = cfg[i]
-		for p = bb.last; p != nil; p = p.Link {
+	for _, bb := range cfg {
+		for p := bb.last; p != nil; p = p.Link {
 			if p.Opt != nil && p != bb.last {
 				break
 			}
@@ -454,7 +467,7 @@
 		}
 
 		if bb.last.To.Type == obj.TYPE_BRANCH {
-			addedge(bb, bb.last.To.U.Branch.Opt.(*BasicBlock))
+			addedge(bb, bb.last.To.Val.(*obj.Prog).Opt.(*BasicBlock))
 		}
 		if bb.last.Link != nil {
 			// Add a fall-through when the instruction is
@@ -467,11 +480,9 @@
 
 	// Add back links so the instructions in a basic block can be traversed
 	// backward.  This is the final state of the instruction opt field.
-	var prev *obj.Prog
-	for i := int32(0); i < int32(len(cfg)); i++ {
-		bb = cfg[i]
-		p = bb.first
-		prev = nil
+	for _, bb := range cfg {
+		p := bb.first
+		var prev *obj.Prog
 		for {
 			p.Opt = prev
 			if p == bb.last {
@@ -489,11 +500,9 @@
 
 	// Find a depth-first order and assign a depth-first number to
 	// all basic blocks.
-	for i := int32(0); i < int32(len(cfg)); i++ {
-		bb = cfg[i]
+	for _, bb := range cfg {
 		bb.mark = UNVISITED
 	}
-
 	bb = cfg[0]
 	rpo := int32(len(cfg))
 	reversepostorder(bb, &rpo)
@@ -503,11 +512,10 @@
 	// node being the root.
 	sort.Sort(blockrpocmp(cfg))
 
-	bb = cfg[0]
-
 	// Unreachable control flow nodes are indicated by a -1 in the rpo
 	// field.  If we see these nodes something must have gone wrong in an
 	// upstream compilation phase.
+	bb = cfg[0]
 	if bb.rpo == -1 {
 		fmt.Printf("newcfg: unreachable basic block for %v\n", bb.last)
 		printcfg(cfg)
@@ -520,18 +528,11 @@
 // Frees a control flow graph (an array of BasicBlock*s) and all of its leaf
 // data structures.
 func freecfg(cfg []*BasicBlock) {
-	n := int32(len(cfg))
-	if n > 0 {
+	if len(cfg) > 0 {
 		bb0 := cfg[0]
 		for p := bb0.first; p != nil; p = p.Link {
 			p.Opt = nil
 		}
-
-		var bb *BasicBlock
-		for i := int32(0); i < n; i++ {
-			bb = cfg[i]
-			freeblock(bb)
-		}
 	}
 }
 
@@ -555,14 +556,11 @@
 // The avarinit output serves as a signal that the data has been
 // initialized, because any use of a variable must come after its
 // initialization.
-func progeffects(prog *obj.Prog, vars []*Node, uevar *Bvec, varkill *Bvec, avarinit *Bvec) {
-	var info ProgInfo
-
+func progeffects(prog *obj.Prog, vars []*Node, uevar Bvec, varkill Bvec, avarinit Bvec) {
 	bvresetall(uevar)
 	bvresetall(varkill)
 	bvresetall(avarinit)
 
-	Thearch.Proginfo(&info, prog)
 	if prog.As == obj.ARET {
 		// Return instructions implicitly read all the arguments.  For
 		// the sake of correctness, out arguments must be read.  For the
@@ -574,12 +572,10 @@
 		// all the parameters for correctness, and similarly it must not
 		// read the out arguments - they won't be set until the new
 		// function runs.
-		var node *Node
-		for i := int32(0); i < int32(len(vars)); i++ {
-			node = vars[i]
+		for i, node := range vars {
 			switch node.Class &^ PHEAP {
 			case PPARAM:
-				bvset(uevar, i)
+				bvset(uevar, int32(i))
 
 				// If the result had its address taken, it is being tracked
 			// by the avarinit code, which does not use uevar.
@@ -590,8 +586,8 @@
 			// non-tail-call return instructions; see note above
 			// the for loop for details.
 			case PPARAMOUT:
-				if node.Addrtaken == 0 && prog.To.Type == obj.TYPE_NONE {
-					bvset(uevar, i)
+				if !node.Addrtaken && prog.To.Type == obj.TYPE_NONE {
+					bvset(uevar, int32(i))
 				}
 			}
 		}
@@ -602,28 +598,24 @@
 	if prog.As == obj.ATEXT {
 		// A text instruction marks the entry point to a function and
 		// the definition point of all in arguments.
-		var node *Node
-		for i := int32(0); i < int32(len(vars)); i++ {
-			node = vars[i]
+		for i, node := range vars {
 			switch node.Class &^ PHEAP {
 			case PPARAM:
-				if node.Addrtaken != 0 {
-					bvset(avarinit, i)
+				if node.Addrtaken {
+					bvset(avarinit, int32(i))
 				}
-				bvset(varkill, i)
+				bvset(varkill, int32(i))
 			}
 		}
 
 		return
 	}
 
-	if info.Flags&(LeftRead|LeftWrite|LeftAddr) != 0 {
+	if prog.Info.Flags&(LeftRead|LeftWrite|LeftAddr) != 0 {
 		from := &prog.From
 		if from.Node != nil && from.Sym != nil && ((from.Node).(*Node)).Curfn == Curfn {
 			switch ((from.Node).(*Node)).Class &^ PHEAP {
-			case PAUTO,
-				PPARAM,
-				PPARAMOUT:
+			case PAUTO, PPARAM, PPARAMOUT:
 				pos, ok := from.Node.(*Node).Opt.(int32) // index in vars
 				if !ok {
 					goto Next
@@ -631,13 +623,13 @@
 				if pos >= int32(len(vars)) || vars[pos] != from.Node {
 					Fatal("bad bookkeeping in liveness %v %d", Nconv(from.Node.(*Node), 0), pos)
 				}
-				if ((from.Node).(*Node)).Addrtaken != 0 {
+				if ((from.Node).(*Node)).Addrtaken {
 					bvset(avarinit, pos)
 				} else {
-					if info.Flags&(LeftRead|LeftAddr) != 0 {
+					if prog.Info.Flags&(LeftRead|LeftAddr) != 0 {
 						bvset(uevar, pos)
 					}
-					if info.Flags&LeftWrite != 0 {
+					if prog.Info.Flags&LeftWrite != 0 {
 						if from.Node != nil && !Isfat(((from.Node).(*Node)).Type) {
 							bvset(varkill, pos)
 						}
@@ -648,21 +640,19 @@
 	}
 
 Next:
-	if info.Flags&(RightRead|RightWrite|RightAddr) != 0 {
+	if prog.Info.Flags&(RightRead|RightWrite|RightAddr) != 0 {
 		to := &prog.To
 		if to.Node != nil && to.Sym != nil && ((to.Node).(*Node)).Curfn == Curfn {
 			switch ((to.Node).(*Node)).Class &^ PHEAP {
-			case PAUTO,
-				PPARAM,
-				PPARAMOUT:
+			case PAUTO, PPARAM, PPARAMOUT:
 				pos, ok := to.Node.(*Node).Opt.(int32) // index in vars
 				if !ok {
-					goto Next1
+					return
 				}
 				if pos >= int32(len(vars)) || vars[pos] != to.Node {
 					Fatal("bad bookkeeping in liveness %v %d", Nconv(to.Node.(*Node), 0), pos)
 				}
-				if ((to.Node).(*Node)).Addrtaken != 0 {
+				if ((to.Node).(*Node)).Addrtaken {
 					if prog.As != obj.AVARKILL {
 						bvset(avarinit, pos)
 					}
@@ -678,10 +668,10 @@
 					// It is not a read. It is equivalent to RightWrite except that
 					// having the RightAddr bit set keeps the registerizer from
 					// trying to substitute a register for the memory location.
-					if (info.Flags&RightRead != 0) || info.Flags&(RightAddr|RightWrite) == RightAddr {
+					if (prog.Info.Flags&RightRead != 0) || prog.Info.Flags&(RightAddr|RightWrite) == RightAddr {
 						bvset(uevar, pos)
 					}
-					if info.Flags&RightWrite != 0 {
+					if prog.Info.Flags&RightWrite != 0 {
 						if to.Node != nil && (!Isfat(((to.Node).(*Node)).Type) || prog.As == obj.AVARDEF) {
 							bvset(varkill, pos)
 						}
@@ -690,8 +680,6 @@
 			}
 		}
 	}
-
-Next1:
 }
 
 // Constructs a new liveness structure used to hold the global state of the
@@ -705,27 +693,20 @@
 	result.vars = vars
 
 	nblocks := int32(len(cfg))
-	result.uevar = make([]*Bvec, nblocks)
-	result.varkill = make([]*Bvec, nblocks)
-	result.livein = make([]*Bvec, nblocks)
-	result.liveout = make([]*Bvec, nblocks)
-	result.avarinit = make([]*Bvec, nblocks)
-	result.avarinitany = make([]*Bvec, nblocks)
-	result.avarinitall = make([]*Bvec, nblocks)
-
 	nvars := int32(len(vars))
-	for i := int32(0); i < nblocks; i++ {
-		result.uevar[i] = bvalloc(nvars)
-		result.varkill[i] = bvalloc(nvars)
-		result.livein[i] = bvalloc(nvars)
-		result.liveout[i] = bvalloc(nvars)
-		result.avarinit[i] = bvalloc(nvars)
-		result.avarinitany[i] = bvalloc(nvars)
-		result.avarinitall[i] = bvalloc(nvars)
+	bulk := bvbulkalloc(nvars, nblocks*7)
+	for _, bb := range cfg {
+		bb.uevar = bulk.next()
+		bb.varkill = bulk.next()
+		bb.livein = bulk.next()
+		bb.liveout = bulk.next()
+		bb.avarinit = bulk.next()
+		bb.avarinitany = bulk.next()
+		bb.avarinitall = bulk.next()
 	}
 
-	result.livepointers = make([]*Bvec, 0, 0)
-	result.argslivepointers = make([]*Bvec, 0, 0)
+	result.livepointers = make([]Bvec, 0, 0)
+	result.argslivepointers = make([]Bvec, 0, 0)
 	return result
 }
 
@@ -734,18 +715,9 @@
 	if lv == nil {
 		Fatal("freeliveness: cannot free nil")
 	}
-
-	for i := int32(0); i < int32(len(lv.livepointers)); i++ {
-	}
-
-	for i := int32(0); i < int32(len(lv.argslivepointers)); i++ {
-	}
-
-	for i := int32(0); i < int32(len(lv.cfg)); i++ {
-	}
 }
 
-func printeffects(p *obj.Prog, uevar *Bvec, varkill *Bvec, avarinit *Bvec) {
+func printeffects(p *obj.Prog, uevar Bvec, varkill Bvec, avarinit Bvec) {
 	fmt.Printf("effects of %v", p)
 	fmt.Printf("\nuevar: ")
 	bvprint(uevar)
@@ -765,18 +737,18 @@
 		p = "^"
 	}
 	a := ""
-	if node.Addrtaken != 0 {
+	if node.Addrtaken {
 		a = "@"
 	}
 	fmt.Printf(" %v%s%s", Nconv(node, 0), p, a)
 }
 
 // Pretty print a list of variables.  The vars argument is an array of Node*s.
-func printvars(name string, bv *Bvec, vars []*Node) {
+func printvars(name string, bv Bvec, vars []*Node) {
 	fmt.Printf("%s:", name)
-	for i := int32(0); i < int32(len(vars)); i++ {
-		if bvget(bv, i) != 0 {
-			printnode(vars[i])
+	for i, node := range vars {
+		if bvget(bv, int32(i)) != 0 {
+			printnode(node)
 		}
 	}
 	fmt.Printf("\n")
@@ -785,43 +757,34 @@
 // Prints a basic block annotated with the information computed by liveness
 // analysis.
 func livenessprintblock(lv *Liveness, bb *BasicBlock) {
-	var pred *BasicBlock
-
 	fmt.Printf("basic block %d\n", bb.rpo)
 
 	fmt.Printf("\tpred:")
-	for i := 0; i < len(bb.pred); i++ {
-		pred = bb.pred[i]
+	for _, pred := range bb.pred {
 		fmt.Printf(" %d", pred.rpo)
 	}
-
 	fmt.Printf("\n")
 
 	fmt.Printf("\tsucc:")
-	var succ *BasicBlock
-	for i := 0; i < len(bb.succ); i++ {
-		succ = bb.succ[i]
+	for _, succ := range bb.succ {
 		fmt.Printf(" %d", succ.rpo)
 	}
-
 	fmt.Printf("\n")
 
-	printvars("\tuevar", lv.uevar[bb.rpo], []*Node(lv.vars))
-	printvars("\tvarkill", lv.varkill[bb.rpo], []*Node(lv.vars))
-	printvars("\tlivein", lv.livein[bb.rpo], []*Node(lv.vars))
-	printvars("\tliveout", lv.liveout[bb.rpo], []*Node(lv.vars))
-	printvars("\tavarinit", lv.avarinit[bb.rpo], []*Node(lv.vars))
-	printvars("\tavarinitany", lv.avarinitany[bb.rpo], []*Node(lv.vars))
-	printvars("\tavarinitall", lv.avarinitall[bb.rpo], []*Node(lv.vars))
+	printvars("\tuevar", bb.uevar, []*Node(lv.vars))
+	printvars("\tvarkill", bb.varkill, []*Node(lv.vars))
+	printvars("\tlivein", bb.livein, []*Node(lv.vars))
+	printvars("\tliveout", bb.liveout, []*Node(lv.vars))
+	printvars("\tavarinit", bb.avarinit, []*Node(lv.vars))
+	printvars("\tavarinitany", bb.avarinitany, []*Node(lv.vars))
+	printvars("\tavarinitall", bb.avarinitall, []*Node(lv.vars))
 
 	fmt.Printf("\tprog:\n")
-	var live *Bvec
-	var pos int32
 	for prog := bb.first; ; prog = prog.Link {
 		fmt.Printf("\t\t%v", prog)
 		if prog.As == obj.APCDATA && prog.From.Offset == obj.PCDATA_StackMapIndex {
-			pos = int32(prog.To.Offset)
-			live = lv.livepointers[pos]
+			pos := int32(prog.To.Offset)
+			live := lv.livepointers[pos]
 			fmt.Printf(" ")
 			bvprint(live)
 		}
@@ -836,16 +799,13 @@
 // Prints a control flow graph annotated with any information computed by
 // liveness analysis.
 func livenessprintcfg(lv *Liveness) {
-	var bb *BasicBlock
-
-	for i := int32(0); i < int32(len(lv.cfg)); i++ {
-		bb = lv.cfg[i]
+	for _, bb := range lv.cfg {
 		livenessprintblock(lv, bb)
 	}
 }
 
 func checkauto(fn *Node, p *obj.Prog, n *Node) {
-	for l := fn.Dcl; l != nil; l = l.Next {
+	for l := fn.Func.Dcl; l != nil; l = l.Next {
 		if l.N.Op == ONAME && l.N.Class == PAUTO && l.N == n {
 			return
 		}
@@ -857,7 +817,7 @@
 	}
 
 	fmt.Printf("checkauto %v: %v (%p; class=%d) not found in %v\n", Nconv(Curfn, 0), Nconv(n, 0), n, n.Class, p)
-	for l := fn.Dcl; l != nil; l = l.Next {
+	for l := fn.Func.Dcl; l != nil; l = l.Next {
 		fmt.Printf("\t%v (%p; class=%d)\n", Nconv(l.N, 0), l.N, l.N.Class)
 	}
 	Yyerror("checkauto: invariant lost")
@@ -869,7 +829,7 @@
 	}
 	var a *Node
 	var class int
-	for l := fn.Dcl; l != nil; l = l.Next {
+	for l := fn.Func.Dcl; l != nil; l = l.Next {
 		a = l.N
 		class = int(a.Class) &^ PHEAP
 		if a.Op == ONAME && (class == PPARAM || class == PPARAMOUT) && a == n {
@@ -878,7 +838,7 @@
 	}
 
 	fmt.Printf("checkparam %v: %v (%p; class=%d) not found in %v\n", Nconv(Curfn, 0), Nconv(n, 0), n, n.Class, p)
-	for l := fn.Dcl; l != nil; l = l.Next {
+	for l := fn.Func.Dcl; l != nil; l = l.Next {
 		fmt.Printf("\t%v (%p; class=%d)\n", Nconv(l.N, 0), l.N, l.N.Class)
 	}
 	Yyerror("checkparam: invariant lost")
@@ -923,7 +883,7 @@
 // and then simply copied into bv at the correct offset on future calls with
 // the same type t. On https://rsc.googlecode.com/hg/testdata/slow.go, twobitwalktype1
 // accounts for 40% of the 6g execution time.
-func twobitwalktype1(t *Type, xoffset *int64, bv *Bvec) {
+func twobitwalktype1(t *Type, xoffset *int64, bv Bvec) {
 	if t.Align > 0 && *xoffset&int64(t.Align-1) != 0 {
 		Fatal("twobitwalktype1: invalid initial alignment, %v", Tconv(t, 0))
 	}
@@ -1031,7 +991,7 @@
 // Generates live pointer value maps for arguments and local variables.  The
 // this argument and the in arguments are always assumed live.  The vars
 // argument is an array of Node*s.
-func twobitlivepointermap(lv *Liveness, liveout *Bvec, vars []*Node, args *Bvec, locals *Bvec) {
+func twobitlivepointermap(lv *Liveness, liveout Bvec, vars []*Node, args Bvec, locals Bvec) {
 	var node *Node
 	var xoffset int64
 
@@ -1046,8 +1006,7 @@
 			xoffset = node.Xoffset + stkptrsize
 			twobitwalktype1(node.Type, &xoffset, locals)
 
-		case PPARAM,
-			PPARAMOUT:
+		case PPARAM, PPARAMOUT:
 			xoffset = node.Xoffset
 			twobitwalktype1(node.Type, &xoffset, args)
 		}
@@ -1089,8 +1048,8 @@
 	Nodconst(&to, Types[TINT32], int64(index))
 	pcdata := unlinkedprog(obj.APCDATA)
 	pcdata.Lineno = prog.Lineno
-	Naddr(&from, &pcdata.From, 0)
-	Naddr(&to, &pcdata.To, 0)
+	Naddr(&pcdata.From, &from)
+	Naddr(&pcdata.To, &to)
 	return pcdata
 }
 
@@ -1104,39 +1063,34 @@
 // instructions in each basic block to summarizes the information at each basic
 // block
 func livenessprologue(lv *Liveness) {
-	var bb *BasicBlock
-	var p *obj.Prog
-
 	nvars := int32(len(lv.vars))
 	uevar := bvalloc(nvars)
 	varkill := bvalloc(nvars)
 	avarinit := bvalloc(nvars)
-	for i := int32(0); i < int32(len(lv.cfg)); i++ {
-		bb = lv.cfg[i]
-
+	for _, bb := range lv.cfg {
 		// Walk the block instructions backward and update the block
 		// effects with the each prog effects.
-		for p = bb.last; p != nil; p = p.Opt.(*obj.Prog) {
+		for p := bb.last; p != nil; p = p.Opt.(*obj.Prog) {
 			progeffects(p, []*Node(lv.vars), uevar, varkill, avarinit)
 			if debuglive >= 3 {
 				printeffects(p, uevar, varkill, avarinit)
 			}
-			bvor(lv.varkill[i], lv.varkill[i], varkill)
-			bvandnot(lv.uevar[i], lv.uevar[i], varkill)
-			bvor(lv.uevar[i], lv.uevar[i], uevar)
+			bvor(bb.varkill, bb.varkill, varkill)
+			bvandnot(bb.uevar, bb.uevar, varkill)
+			bvor(bb.uevar, bb.uevar, uevar)
 		}
 
 		// Walk the block instructions forward to update avarinit bits.
 		// avarinit describes the effect at the end of the block, not the beginning.
 		bvresetall(varkill)
 
-		for p = bb.first; ; p = p.Link {
+		for p := bb.first; ; p = p.Link {
 			progeffects(p, []*Node(lv.vars), uevar, varkill, avarinit)
 			if debuglive >= 3 {
 				printeffects(p, uevar, varkill, avarinit)
 			}
-			bvandnot(lv.avarinit[i], lv.avarinit[i], varkill)
-			bvor(lv.avarinit[i], lv.avarinit[i], avarinit)
+			bvandnot(bb.avarinit, bb.avarinit, varkill)
+			bvor(bb.avarinit, bb.avarinit, avarinit)
 			if p == bb.last {
 				break
 			}
@@ -1146,9 +1100,6 @@
 
 // Solve the liveness dataflow equations.
 func livenesssolve(lv *Liveness) {
-	var bb *BasicBlock
-	var rpo int32
-
 	// These temporary bitvectors exist to avoid successive allocations and
 	// frees within the loop.
 	newlivein := bvalloc(int32(len(lv.vars)))
@@ -1160,53 +1111,44 @@
 	// Push avarinitall, avarinitany forward.
 	// avarinitall says the addressed var is initialized along all paths reaching the block exit.
 	// avarinitany says the addressed var is initialized along some path reaching the block exit.
-	for i := int32(0); i < int32(len(lv.cfg)); i++ {
-		bb = lv.cfg[i]
-		rpo = int32(bb.rpo)
+	for i, bb := range lv.cfg {
 		if i == 0 {
-			bvcopy(lv.avarinitall[rpo], lv.avarinit[rpo])
+			bvcopy(bb.avarinitall, bb.avarinit)
 		} else {
-			bvresetall(lv.avarinitall[rpo])
-			bvnot(lv.avarinitall[rpo])
+			bvresetall(bb.avarinitall)
+			bvnot(bb.avarinitall)
 		}
-
-		bvcopy(lv.avarinitany[rpo], lv.avarinit[rpo])
+		bvcopy(bb.avarinitany, bb.avarinit)
 	}
 
 	change := int32(1)
-	var j int32
-	var i int32
-	var pred *BasicBlock
 	for change != 0 {
 		change = 0
-		for i = 0; i < int32(len(lv.cfg)); i++ {
-			bb = lv.cfg[i]
-			rpo = int32(bb.rpo)
+		for _, bb := range lv.cfg {
 			bvresetall(any)
 			bvresetall(all)
-			for j = 0; j < int32(len(bb.pred)); j++ {
-				pred = bb.pred[j]
+			for j, pred := range bb.pred {
 				if j == 0 {
-					bvcopy(any, lv.avarinitany[pred.rpo])
-					bvcopy(all, lv.avarinitall[pred.rpo])
+					bvcopy(any, pred.avarinitany)
+					bvcopy(all, pred.avarinitall)
 				} else {
-					bvor(any, any, lv.avarinitany[pred.rpo])
-					bvand(all, all, lv.avarinitall[pred.rpo])
+					bvor(any, any, pred.avarinitany)
+					bvand(all, all, pred.avarinitall)
 				}
 			}
 
-			bvandnot(any, any, lv.varkill[rpo])
-			bvandnot(all, all, lv.varkill[rpo])
-			bvor(any, any, lv.avarinit[rpo])
-			bvor(all, all, lv.avarinit[rpo])
-			if bvcmp(any, lv.avarinitany[rpo]) != 0 {
+			bvandnot(any, any, bb.varkill)
+			bvandnot(all, all, bb.varkill)
+			bvor(any, any, bb.avarinit)
+			bvor(all, all, bb.avarinit)
+			if bvcmp(any, bb.avarinitany) != 0 {
 				change = 1
-				bvcopy(lv.avarinitany[rpo], any)
+				bvcopy(bb.avarinitany, any)
 			}
 
-			if bvcmp(all, lv.avarinitall[rpo]) != 0 {
+			if bvcmp(all, bb.avarinitall) != 0 {
 				change = 1
-				bvcopy(lv.avarinitall[rpo], all)
+				bvcopy(bb.avarinitall, all)
 			}
 		}
 	}
@@ -1216,29 +1158,26 @@
 	// so low that it hardly seems to be worth the complexity.
 	change = 1
 
-	var succ *BasicBlock
 	for change != 0 {
 		change = 0
 
 		// Walk blocks in the general direction of propagation.  This
 		// improves convergence.
-		for i = int32(len(lv.cfg)) - 1; i >= 0; i-- {
+		for i := len(lv.cfg) - 1; i >= 0; i-- {
+			bb := lv.cfg[i]
+
 			// A variable is live on output from this block
 			// if it is live on input to some successor.
 			//
 			// out[b] = \bigcup_{s \in succ[b]} in[s]
-			bb = lv.cfg[i]
-
-			rpo = int32(bb.rpo)
 			bvresetall(newliveout)
-			for j = 0; j < int32(len(bb.succ)); j++ {
-				succ = bb.succ[j]
-				bvor(newliveout, newliveout, lv.livein[succ.rpo])
+			for _, succ := range bb.succ {
+				bvor(newliveout, newliveout, succ.livein)
 			}
 
-			if bvcmp(lv.liveout[rpo], newliveout) != 0 {
+			if bvcmp(bb.liveout, newliveout) != 0 {
 				change = 1
-				bvcopy(lv.liveout[rpo], newliveout)
+				bvcopy(bb.liveout, newliveout)
 			}
 
 			// A variable is live on input to this block
@@ -1246,19 +1185,18 @@
 			// not set by the code in this block.
 			//
 			// in[b] = uevar[b] \cup (out[b] \setminus varkill[b])
-			bvandnot(newlivein, lv.liveout[rpo], lv.varkill[rpo])
+			bvandnot(newlivein, bb.liveout, bb.varkill)
 
-			bvor(lv.livein[rpo], newlivein, lv.uevar[rpo])
+			bvor(bb.livein, newlivein, bb.uevar)
 		}
 	}
 }
 
 // This function is slow but it is only used for generating debug prints.
 // Check whether n is marked live in args/locals.
-func islive(n *Node, args *Bvec, locals *Bvec) bool {
+func islive(n *Node, args Bvec, locals Bvec) bool {
 	switch n.Class {
-	case PPARAM,
-		PPARAMOUT:
+	case PPARAM, PPARAMOUT:
 		for i := 0; int64(i) < n.Type.Width/int64(Widthptr)*obj.BitsPerPointer; i++ {
 			if bvget(args, int32(n.Xoffset/int64(Widthptr)*obj.BitsPerPointer+int64(i))) != 0 {
 				return true
@@ -1279,10 +1217,9 @@
 // Visits all instructions in a basic block and computes a bit vector of live
 // variables at each safe point locations.
 func livenessepilogue(lv *Liveness) {
-	var bb *BasicBlock
 	var pred *BasicBlock
-	var args *Bvec
-	var locals *Bvec
+	var args Bvec
+	var locals Bvec
 	var n *Node
 	var p *obj.Prog
 	var j int32
@@ -1298,13 +1235,10 @@
 	any := bvalloc(nvars)
 	all := bvalloc(nvars)
 	ambig := bvalloc(localswords() * obj.BitsPerPointer)
-	msg := []string(nil)
 	nmsg := int32(0)
 	startmsg := int32(0)
 
-	for i := int32(0); i < int32(len(lv.cfg)); i++ {
-		bb = lv.cfg[i]
-
+	for _, bb := range lv.cfg {
 		// Compute avarinitany and avarinitall for entry to block.
 		// This duplicates information known during livenesssolve
 		// but avoids storing two more vectors for each block.
@@ -1314,11 +1248,11 @@
 		for j = 0; j < int32(len(bb.pred)); j++ {
 			pred = bb.pred[j]
 			if j == 0 {
-				bvcopy(any, lv.avarinitany[pred.rpo])
-				bvcopy(all, lv.avarinitall[pred.rpo])
+				bvcopy(any, pred.avarinitany)
+				bvcopy(all, pred.avarinitall)
 			} else {
-				bvor(any, any, lv.avarinitany[pred.rpo])
-				bvand(all, all, lv.avarinitall[pred.rpo])
+				bvor(any, any, pred.avarinitany)
+				bvand(all, all, pred.avarinitall)
 			}
 		}
 
@@ -1346,8 +1280,8 @@
 						}
 						bvset(all, pos) // silence future warnings in this block
 						n = lv.vars[pos]
-						if n.Needzero == 0 {
-							n.Needzero = 1
+						if !n.Needzero {
+							n.Needzero = true
 							if debuglive >= 1 {
 								Warnl(int(p.Lineno), "%v: %v is ambiguously live", Nconv(Curfn.Nname, 0), Nconv(n, obj.FmtLong))
 							}
@@ -1394,9 +1328,8 @@
 	var fmt_ string
 	var next *obj.Prog
 	var numlive int32
-	for i := int32(0); i < int32(len(lv.cfg)); i++ {
-		bb = lv.cfg[i]
-
+	var msg []string
+	for _, bb := range lv.cfg {
 		if debuglive >= 1 && Curfn.Nname.Sym.Name != "init" && Curfn.Nname.Sym.Name[0] != '.' {
 			nmsg = int32(len(lv.livepointers))
 			startmsg = nmsg
@@ -1415,7 +1348,7 @@
 			Fatal("livenessepilogue")
 		}
 
-		bvcopy(livein, lv.liveout[bb.rpo])
+		bvcopy(livein, bb.liveout)
 		for p = bb.last; p != nil; p = next {
 			next = p.Opt.(*obj.Prog) // splicebefore modifies p->opt
 
@@ -1539,7 +1472,7 @@
 	Hp = 16777619
 )
 
-func hashbitmap(h uint32, bv *Bvec) uint32 {
+func hashbitmap(h uint32, bv Bvec) uint32 {
 	var w uint32
 
 	n := int((bv.n + 31) / 32)
@@ -1593,12 +1526,12 @@
 	// record in remap, record in lv->livepointers and lv->argslivepointers
 	// under the new index, and add entry to hash table.
 	// If already seen, record earlier index in remap and free bitmaps.
-	var jarg *Bvec
+	var jarg Bvec
 	var j int
 	var h uint32
-	var arg *Bvec
-	var jlocal *Bvec
-	var local *Bvec
+	var arg Bvec
+	var jlocal Bvec
+	var local Bvec
 	for i := 0; i < n; i++ {
 		local = lv.livepointers[i]
 		arg = lv.argslivepointers[i]
@@ -1636,8 +1569,8 @@
 	// array so that we can tell where the coalesced bitmaps stop
 	// and so that we don't double-free when cleaning up.
 	for j := uniq; j < n; j++ {
-		lv.livepointers[j] = nil
-		lv.argslivepointers[j] = nil
+		lv.livepointers[j] = Bvec{}
+		lv.argslivepointers[j] = Bvec{}
 	}
 
 	// Rewrite PCDATA instructions to use new numbering.
@@ -1652,11 +1585,9 @@
 	}
 }
 
-func printbitset(printed int, name string, vars []*Node, bits *Bvec) int {
-	var n *Node
-
+func printbitset(printed int, name string, vars []*Node, bits Bvec) int {
 	started := 0
-	for i := 0; i < len(vars); i++ {
+	for i, n := range vars {
 		if bvget(bits, int32(i)) == 0 {
 			continue
 		}
@@ -1673,7 +1604,6 @@
 			fmt.Printf(",")
 		}
 
-		n = vars[i]
 		fmt.Printf("%s", n.Sym.Name)
 	}
 
@@ -1686,10 +1616,9 @@
 func livenessprintdebug(lv *Liveness) {
 	var j int
 	var printed int
-	var bb *BasicBlock
 	var p *obj.Prog
-	var args *Bvec
-	var locals *Bvec
+	var args Bvec
+	var locals Bvec
 	var n *Node
 
 	fmt.Printf("liveness: %s\n", Curfn.Nname.Sym.Name)
@@ -1699,11 +1628,10 @@
 	avarinit := bvalloc(int32(len(lv.vars)))
 
 	pcdata := 0
-	for i := 0; i < len(lv.cfg); i++ {
+	for i, bb := range lv.cfg {
 		if i > 0 {
 			fmt.Printf("\n")
 		}
-		bb = lv.cfg[i]
 
 		// bb#0 pred=1,2 succ=3,4
 		fmt.Printf("bb#%d pred=", i)
@@ -1728,8 +1656,8 @@
 		// initial settings
 		printed = 0
 
-		printed = printbitset(printed, "uevar", lv.vars, lv.uevar[bb.rpo])
-		printed = printbitset(printed, "livein", lv.vars, lv.livein[bb.rpo])
+		printed = printbitset(printed, "uevar", lv.vars, bb.uevar)
+		printed = printbitset(printed, "livein", lv.vars, bb.livein)
 		if printed != 0 {
 			fmt.Printf("\n")
 		}
@@ -1776,11 +1704,11 @@
 		// bb bitsets
 		fmt.Printf("end\n")
 
-		printed = printbitset(printed, "varkill", lv.vars, lv.varkill[bb.rpo])
-		printed = printbitset(printed, "liveout", lv.vars, lv.liveout[bb.rpo])
-		printed = printbitset(printed, "avarinit", lv.vars, lv.avarinit[bb.rpo])
-		printed = printbitset(printed, "avarinitany", lv.vars, lv.avarinitany[bb.rpo])
-		printed = printbitset(printed, "avarinitall", lv.vars, lv.avarinitall[bb.rpo])
+		printed = printbitset(printed, "varkill", lv.vars, bb.varkill)
+		printed = printbitset(printed, "liveout", lv.vars, bb.liveout)
+		printed = printbitset(printed, "avarinit", lv.vars, bb.avarinit)
+		printed = printbitset(printed, "avarinitany", lv.vars, bb.avarinitany)
+		printed = printbitset(printed, "avarinitall", lv.vars, bb.avarinitall)
 		if printed != 0 {
 			fmt.Printf("\n")
 		}
@@ -1794,7 +1722,7 @@
 // length of the bitmaps.  All bitmaps are assumed to be of equal length.  The
 // words that are followed are the raw bitmap words.  The arr argument is an
 // array of Node*s.
-func twobitwritesymbol(arr []*Bvec, sym *Sym) {
+func twobitwritesymbol(arr []Bvec, sym *Sym) {
 	var i int
 	var j int
 	var word uint32
@@ -1808,7 +1736,7 @@
 		// bitmap words
 		bv = arr[i]
 
-		if bv == nil {
+		if bv.b == nil {
 			break
 		}
 		for j = 0; int32(j) < bv.n; j += 32 {
@@ -1888,7 +1816,7 @@
 	twobitwritesymbol(lv.argslivepointers, argssym)
 
 	// Free everything.
-	for l := fn.Dcl; l != nil; l = l.Next {
+	for l := fn.Func.Dcl; l != nil; l = l.Next {
 		if l.N != nil {
 			l.N.Opt = nil
 		}
diff --git a/src/cmd/internal/gc/popt.go b/src/cmd/internal/gc/popt.go
index 756f8eb..099a0b6 100644
--- a/src/cmd/internal/gc/popt.go
+++ b/src/cmd/internal/gc/popt.go
@@ -1,46 +1,3 @@
-// Derived from Inferno utils/6c/reg.c
-// http://code.google.com/p/inferno-os/source/browse/utils/6c/reg.c
-//
-//	Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
-//	Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
-//	Portions Copyright © 1997-1999 Vita Nuova Limited
-//	Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
-//	Portions Copyright © 2004,2006 Bruce Ellis
-//	Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
-//	Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
-//	Portions Copyright © 2009 The Go Authors.  All rights reserved.
-//
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files (the "Software"), to deal
-// in the Software without restriction, including without limitation the rights
-// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-// copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-// THE SOFTWARE.
-
-package gc
-
-import (
-	"cmd/internal/obj"
-	"fmt"
-	"sort"
-	"strings"
-)
-
-// "Portable" optimizations.
-// Compiled separately for 5g, 6g, and 8g, so allowed to use gg.h, opt.h.
-// Must code to the intersection of the three back ends.
-
 // Derived from Inferno utils/6c/gc.h
 // http://code.google.com/p/inferno-os/source/browse/utils/6c/gc.h
 //
@@ -71,83 +28,17 @@
 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 // THE SOFTWARE.
 
-const (
-	CLOAD = 5
-	CREF  = 5
-	CINF  = 1000
-	LOOP  = 3
+// "Portable" optimizations.
+
+package gc
+
+import (
+	"cmd/internal/obj"
+	"fmt"
+	"sort"
+	"strings"
 )
 
-type Reg struct {
-	set       Bits
-	use1      Bits
-	use2      Bits
-	refbehind Bits
-	refahead  Bits
-	calbehind Bits
-	calahead  Bits
-	regdiff   Bits
-	act       Bits
-	regu      uint64
-}
-
-type Rgn struct {
-	enter *Flow
-	cost  int16
-	varno int16
-	regno int16
-}
-
-var Z *Node
-
-// A Reg is a wrapper around a single Prog (one instruction) that holds
-// register optimization information while the optimizer runs.
-// r->prog is the instruction.
-
-var R *Reg
-
-const (
-	NRGN = 600
-)
-
-// A Rgn represents a single regopt variable over a region of code
-// where a register could potentially be dedicated to that variable.
-// The code encompassed by a Rgn is defined by the flow graph,
-// starting at enter, flood-filling forward while varno is refahead
-// and backward while varno is refbehind, and following branches.  A
-// single variable may be represented by multiple disjoint Rgns and
-// each Rgn may choose a different register for that variable.
-// Registers are allocated to regions greedily in order of descending
-// cost.
-
-var zreg Reg
-
-var region [NRGN]Rgn
-
-var rgp *Rgn
-
-var nregion int
-
-var nvar int
-
-var regbits uint64
-
-var externs Bits
-
-var params Bits
-
-var consts Bits
-
-var addrs Bits
-
-var ivar Bits
-
-var ovar Bits
-
-var change int
-
-var maxnr int32
-
 type OptStats struct {
 	Ncvtreg int32
 	Nspill  int32
@@ -159,26 +50,9 @@
 
 var Ostats OptStats
 
-/*
- * reg.c
- */
-
-/*
- * peep.c
-void	peep(Prog*);
-void	excise(Flow*);
-int	copyu(Prog*, Adr*, Adr*);
-*/
-
-/*
- * prog.c
-
-void proginfo(ProgInfo*, Prog*);
-*/
-// p is a call instruction. Does the call fail to return?
-
 var noreturn_symlist [10]*Sym
 
+// p is a call instruction. Does the call fail to return?
 func Noreturn(p *obj.Prog) bool {
 	if noreturn_symlist[0] == nil {
 		noreturn_symlist[0] = Pkglookup("panicindex", Runtimepkg)
@@ -224,7 +98,7 @@
 			break
 		}
 
-		p = p.To.U.Branch
+		p = p.To.Val.(*obj.Prog)
 	}
 
 	return p
@@ -244,8 +118,8 @@
 			break
 		}
 		p.Opt = alive
-		if p.As != obj.ACALL && p.To.Type == obj.TYPE_BRANCH && p.To.U.Branch != nil {
-			mark(p.To.U.Branch)
+		if p.As != obj.ACALL && p.To.Type == obj.TYPE_BRANCH && p.To.Val.(*obj.Prog) != nil {
+			mark(p.To.Val.(*obj.Prog))
 		}
 		if p.As == obj.AJMP || p.As == obj.ARET || p.As == obj.AUNDEF {
 			break
@@ -265,8 +139,8 @@
 		if Debug['R'] != 0 && Debug['v'] != 0 {
 			fmt.Printf("%v\n", p)
 		}
-		if p.As != obj.ACALL && p.To.Type == obj.TYPE_BRANCH && p.To.U.Branch != nil && p.To.U.Branch.As == obj.AJMP {
-			p.To.U.Branch = chasejmp(p.To.U.Branch, &jmploop)
+		if p.As != obj.ACALL && p.To.Type == obj.TYPE_BRANCH && p.To.Val.(*obj.Prog) != nil && p.To.Val.(*obj.Prog).As == obj.AJMP {
+			p.To.Val = chasejmp(p.To.Val.(*obj.Prog), &jmploop)
 			if Debug['R'] != 0 && Debug['v'] != 0 {
 				fmt.Printf("->%v\n", p)
 			}
@@ -283,7 +157,7 @@
 	mark(firstp)
 
 	// pass 3: delete dead code (mostly JMPs).
-	last := (*obj.Prog)(nil)
+	var last *obj.Prog
 
 	for p := firstp; p != nil; p = p.Link {
 		if p.Opt == dead {
@@ -315,9 +189,9 @@
 	// pass 4: elide JMP to next instruction.
 	// only safe if there are no jumps to JMPs anymore.
 	if jmploop == 0 {
-		last := (*obj.Prog)(nil)
+		var last *obj.Prog
 		for p := firstp; p != nil; p = p.Link {
-			if p.As == obj.AJMP && p.To.Type == obj.TYPE_BRANCH && p.To.U.Branch == p.Link {
+			if p.As == obj.AJMP && p.To.Type == obj.TYPE_BRANCH && p.To.Val == p.Link {
 				if Debug['R'] != 0 && Debug['v'] != 0 {
 					fmt.Printf("del %v\n", p)
 				}
@@ -362,19 +236,24 @@
 // to allocate in every f->data field, for use by the client.
 // If size == 0, f->data will be nil.
 
-func Flowstart(firstp *obj.Prog, newData func() interface{}) *Graph {
-	var info ProgInfo
+var flowmark int
 
+// MaxFlowProg is the maximum size program (counted in instructions)
+// for which the flow code will build a graph. Functions larger than this limit
+// will not have flow graphs and consequently will not be optimized.
+const MaxFlowProg = 50000
+
+func Flowstart(firstp *obj.Prog, newData func() interface{}) *Graph {
 	// Count and mark instructions to annotate.
 	nf := 0
 
 	for p := firstp; p != nil; p = p.Link {
 		p.Opt = nil // should be already, but just in case
-		Thearch.Proginfo(&info, p)
-		if info.Flags&Skip != 0 {
+		Thearch.Proginfo(p)
+		if p.Info.Flags&Skip != 0 {
 			continue
 		}
-		p.Opt = interface{}(1)
+		p.Opt = &flowmark
 		nf++
 	}
 
@@ -382,8 +261,10 @@
 		return nil
 	}
 
-	if nf >= 20000 {
-		// fatal("%S is too big (%d instructions)", curfn->nname->sym, nf);
+	if nf >= MaxFlowProg {
+		if Debug['v'] != 0 {
+			Warn("%v is too big (%d instructions)", Sconv(Curfn.Nname.Sym, 0), nf)
+		}
 		return nil
 	}
 
@@ -417,20 +298,19 @@
 	var p *obj.Prog
 	for f := start; f != nil; f = f.Link {
 		p = f.Prog
-		Thearch.Proginfo(&info, p)
-		if info.Flags&Break == 0 {
+		if p.Info.Flags&Break == 0 {
 			f1 = f.Link
 			f.S1 = f1
 			f1.P1 = f
 		}
 
 		if p.To.Type == obj.TYPE_BRANCH {
-			if p.To.U.Branch == nil {
+			if p.To.Val == nil {
 				Fatal("pnil %v", p)
 			}
-			f1 = p.To.U.Branch.Opt.(*Flow)
+			f1 = p.To.Val.(*obj.Prog).Opt.(*Flow)
 			if f1 == nil {
-				Fatal("fnil %v / %v", p, p.To.U.Branch)
+				Fatal("fnil %v / %v", p, p.To.Val.(*obj.Prog))
 			}
 			if f1 == f {
 				//fatal("self loop %P", p);
@@ -450,6 +330,7 @@
 
 func Flowend(graph *Graph) {
 	for f := graph.Start; f != nil; f = f.Link {
+		f.Prog.Info.Flags = 0 // drop cached proginfo
 		f.Prog.Opt = nil
 	}
 }
@@ -637,14 +518,14 @@
 
 type TempVar struct {
 	node     *Node
-	def      *Flow
-	use      *Flow
-	freelink *TempVar
-	merge    *TempVar
-	start    int64
-	end      int64
-	addr     uint8
-	removed  uint8
+	def      *Flow    // definition of temp var
+	use      *Flow    // use list, chained through Flow.data
+	freelink *TempVar // next free temp in Type.opt list
+	merge    *TempVar // merge var with this one
+	start    int64    // smallest Prog.pc in live range
+	end      int64    // largest Prog.pc in live range
+	addr     uint8    // address taken - no accurate end
+	removed  uint8    // removed from program
 }
 
 type startcmp []*TempVar
@@ -688,7 +569,7 @@
 
 func mergetemp(firstp *obj.Prog) {
 	const (
-		debugmerge = 1
+		debugmerge = 0
 	)
 
 	g := Flowstart(firstp, nil)
@@ -698,7 +579,7 @@
 
 	// Build list of all mergeable variables.
 	nvar := 0
-	for l := Curfn.Dcl; l != nil; l = l.Next {
+	for l := Curfn.Func.Dcl; l != nil; l = l.Next {
 		if canmerge(l.N) {
 			nvar++
 		}
@@ -708,7 +589,7 @@
 	nvar = 0
 	var n *Node
 	var v *TempVar
-	for l := Curfn.Dcl; l != nil; l = l.Next {
+	for l := Curfn.Func.Dcl; l != nil; l = l.Next {
 		n = l.N
 		if canmerge(n) {
 			v = &var_[nvar]
@@ -722,12 +603,8 @@
 	// We assume that the earliest reference to a temporary is its definition.
 	// This is not true of variables in general but our temporaries are all
 	// single-use (that's why we have so many!).
-	var p *obj.Prog
-	var info ProgInfo
 	for f := g.Start; f != nil; f = f.Link {
-		p = f.Prog
-		Thearch.Proginfo(&info, p)
-
+		p := f.Prog
 		if p.From.Node != nil && ((p.From.Node).(*Node)).Opt != nil && p.To.Node != nil && ((p.To.Node).(*Node)).Opt != nil {
 			Fatal("double node %v", p)
 		}
@@ -748,7 +625,7 @@
 			}
 			f.Data = v.use
 			v.use = f
-			if n == p.From.Node && (info.Flags&LeftAddr != 0) {
+			if n == p.From.Node && (p.Info.Flags&LeftAddr != 0) {
 				v.addr = 1
 			}
 		}
@@ -761,9 +638,6 @@
 	nkill := 0
 
 	// Special case.
-	var p1 *obj.Prog
-	var info1 ProgInfo
-	var f *Flow
 	for i := 0; i < len(var_); i++ {
 		v = &var_[i]
 		if v.addr != 0 {
@@ -771,11 +645,10 @@
 		}
 
 		// Used in only one instruction, which had better be a write.
-		f = v.use
+		f := v.use
 		if f != nil && f.Data.(*Flow) == nil {
-			p = f.Prog
-			Thearch.Proginfo(&info, p)
-			if p.To.Node == v.node && (info.Flags&RightWrite != 0) && info.Flags&RightRead == 0 {
+			p := f.Prog
+			if p.To.Node == v.node && (p.Info.Flags&RightWrite != 0) && p.Info.Flags&RightRead == 0 {
 				p.As = obj.ANOP
 				p.To = obj.Addr{}
 				v.removed = 1
@@ -793,14 +666,12 @@
 		// no jumps to the next instruction. Happens mainly in 386 compiler.
 		f = v.use
 		if f != nil && f.Link == f.Data.(*Flow) && (f.Data.(*Flow)).Data.(*Flow) == nil && Uniqp(f.Link) == f {
-			p = f.Prog
-			Thearch.Proginfo(&info, p)
-			p1 = f.Link.Prog
-			Thearch.Proginfo(&info1, p1)
+			p := f.Prog
+			p1 := f.Link.Prog
 			const (
 				SizeAny = SizeB | SizeW | SizeL | SizeQ | SizeF | SizeD
 			)
-			if p.From.Node == v.node && p1.To.Node == v.node && (info.Flags&Move != 0) && (info.Flags|info1.Flags)&(LeftAddr|RightAddr) == 0 && info.Flags&SizeAny == info1.Flags&SizeAny {
+			if p.From.Node == v.node && p1.To.Node == v.node && (p.Info.Flags&Move != 0) && (p.Info.Flags|p1.Info.Flags)&(LeftAddr|RightAddr) == 0 && p.Info.Flags&SizeAny == p1.Info.Flags&SizeAny {
 				p1.From = p.From
 				Thearch.Excise(f)
 				v.removed = 1
@@ -822,12 +693,12 @@
 	for i := 0; i < len(var_); i++ {
 		v = &var_[i]
 		gen++
-		for f = v.use; f != nil; f = f.Data.(*Flow) {
+		for f := v.use; f != nil; f = f.Data.(*Flow) {
 			mergewalk(v, f, uint32(gen))
 		}
 		if v.addr != 0 {
 			gen++
-			for f = v.use; f != nil; f = f.Data.(*Flow) {
+			for f := v.use; f != nil; f = f.Data.(*Flow) {
 				varkillwalk(v, f, uint32(gen))
 			}
 		}
@@ -882,7 +753,7 @@
 		for j = nfree; j < len(var_); j++ {
 			v1 = inuse[j]
 			if debugmerge > 0 && Debug['v'] != 0 {
-				fmt.Printf("consider %v: maybe %v: type=%v,%v addrtaken=%d,%d\n", Nconv(v.node, obj.FmtSharp), Nconv(v1.node, obj.FmtSharp), Tconv(t, 0), Tconv(v1.node.Type, 0), v.node.Addrtaken, v1.node.Addrtaken)
+				fmt.Printf("consider %v: maybe %v: type=%v,%v addrtaken=%v,%v\n", Nconv(v.node, obj.FmtSharp), Nconv(v1.node, obj.FmtSharp), Tconv(t, 0), Tconv(v1.node.Type, 0), v.node.Addrtaken, v1.node.Addrtaken)
 			}
 
 			// Require the types to match but also require the addrtaken bits to match.
@@ -943,7 +814,7 @@
 
 	// Update node references to use merged temporaries.
 	for f := g.Start; f != nil; f = f.Link {
-		p = f.Prog
+		p := f.Prog
 		n, _ = p.From.Node.(*Node)
 		if n != nil {
 			v, _ = n.Opt.(*TempVar)
@@ -962,13 +833,13 @@
 
 	// Delete merged nodes from declaration list.
 	var l *NodeList
-	for lp := &Curfn.Dcl; ; {
+	for lp := &Curfn.Func.Dcl; ; {
 		l = *lp
 		if l == nil {
 			break
 		}
 
-		Curfn.Dcl.End = l
+		Curfn.Func.Dcl.End = l
 		n = l.N
 		v, _ = n.Opt.(*TempVar)
 		if v != nil && (v.merge != nil || v.removed != 0) {
@@ -1053,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
 
@@ -1117,13 +986,9 @@
 }
 
 func nilwalkback(fcheck *Flow) {
-	var p *obj.Prog
-	var info ProgInfo
-
 	for f := fcheck; f != nil; f = Uniqp(f) {
-		p = f.Prog
-		Thearch.Proginfo(&info, p)
-		if (info.Flags&RightWrite != 0) && Thearch.Sameaddr(&p.To, &fcheck.Prog.From) {
+		p := f.Prog
+		if (p.Info.Flags&RightWrite != 0) && Thearch.Sameaddr(&p.To, &fcheck.Prog.From) {
 			// Found initialization of value we're checking for nil.
 			// without first finding the check, so this one is unchecked.
 			return
@@ -1154,8 +1019,7 @@
 	if(f1 != fcheck && p->as == ACHECKNIL && thearch.sameaddr(&p->from, &fcheck->prog->from))
 		break;
 
-	thearch.proginfo(&info, p);
-	if((info.flags & RightWrite) && thearch.sameaddr(&p->to, &fcheck->prog->from)) {
+	if((p.Info.flags & RightWrite) && thearch.sameaddr(&p->to, &fcheck->prog->from)) {
 		// Found initialization of value we're checking for nil.
 		// without first finding the check, so this one is unchecked.
 		fcheck->kill = 0;
@@ -1176,10 +1040,8 @@
 	for(f2 = f->p2; f2 != nil; f2 = f2->p2link)
 		nilwalkback(fcheck, f2, gen);
 */
-func nilwalkfwd(fcheck *Flow) {
-	var p *obj.Prog
-	var info ProgInfo
 
+func nilwalkfwd(fcheck *Flow) {
 	// If the path down from rcheck dereferences the address
 	// (possibly with a small offset) before writing to memory
 	// and before any subsequent checks, it's okay to wait for
@@ -1187,18 +1049,16 @@
 	// avoid problems like:
 	//	_ = *x // should panic
 	//	for {} // no writes but infinite loop may be considered visible
-	last := (*Flow)(nil)
 
+	var last *Flow
 	for f := Uniqs(fcheck); f != nil; f = Uniqs(f) {
-		p = f.Prog
-		Thearch.Proginfo(&info, p)
-
-		if (info.Flags&LeftRead != 0) && Thearch.Smallindir(&p.From, &fcheck.Prog.From) {
+		p := f.Prog
+		if (p.Info.Flags&LeftRead != 0) && Thearch.Smallindir(&p.From, &fcheck.Prog.From) {
 			fcheck.Data = &killed
 			return
 		}
 
-		if (info.Flags&(RightRead|RightWrite) != 0) && Thearch.Smallindir(&p.To, &fcheck.Prog.From) {
+		if (p.Info.Flags&(RightRead|RightWrite) != 0) && Thearch.Smallindir(&p.To, &fcheck.Prog.From) {
 			fcheck.Data = &killed
 			return
 		}
@@ -1209,12 +1069,12 @@
 		}
 
 		// Stop if value is lost.
-		if (info.Flags&RightWrite != 0) && Thearch.Sameaddr(&p.To, &fcheck.Prog.From) {
+		if (p.Info.Flags&RightWrite != 0) && Thearch.Sameaddr(&p.To, &fcheck.Prog.From) {
 			return
 		}
 
 		// Stop if memory write.
-		if (info.Flags&RightWrite != 0) && !Thearch.Regtyp(&p.To) {
+		if (p.Info.Flags&RightWrite != 0) && !Thearch.Regtyp(&p.To) {
 			return
 		}
 
diff --git a/src/cmd/internal/gc/racewalk.go b/src/cmd/internal/gc/racewalk.go
index 3619fed..85225c3 100644
--- a/src/cmd/internal/gc/racewalk.go
+++ b/src/cmd/internal/gc/racewalk.go
@@ -60,7 +60,7 @@
 		racewalklist(fn.Nbody, nil)
 
 		// nothing interesting for race detector in fn->enter
-		racewalklist(fn.Exit, nil)
+		racewalklist(fn.Func.Exit, nil)
 	}
 
 	// nodpc is the PC of the caller as extracted by
@@ -72,17 +72,17 @@
 	nodpc.Type = Types[TUINTPTR]
 	nodpc.Xoffset = int64(-Widthptr)
 	nd := mkcall("racefuncenter", nil, nil, nodpc)
-	fn.Enter = concat(list1(nd), fn.Enter)
+	fn.Func.Enter = concat(list1(nd), fn.Func.Enter)
 	nd = mkcall("racefuncexit", nil, nil)
-	fn.Exit = list(fn.Exit, nd)
+	fn.Func.Exit = list(fn.Func.Exit, nd)
 
 	if Debug['W'] != 0 {
 		s := fmt.Sprintf("after racewalk %v", Sconv(fn.Nname.Sym, 0))
 		dumplist(s, fn.Nbody)
 		s = fmt.Sprintf("enter %v", Sconv(fn.Nname.Sym, 0))
-		dumplist(s, fn.Enter)
+		dumplist(s, fn.Func.Enter)
 		s = fmt.Sprintf("exit %v", Sconv(fn.Nname.Sym, 0))
-		dumplist(s, fn.Exit)
+		dumplist(s, fn.Func.Exit)
 	}
 }
 
@@ -137,15 +137,13 @@
 	default:
 		Fatal("racewalk: unknown node type %v", Oconv(int(n.Op), 0))
 
-	case OAS,
-		OAS2FUNC:
+	case OAS, OAS2FUNC:
 		racewalknode(&n.Left, init, 1, 0)
 		racewalknode(&n.Right, init, 0, 0)
 		goto ret
 
 		// can't matter
-	case OCFUNC,
-		OVARKILL:
+	case OCFUNC, OVARKILL:
 		goto ret
 
 	case OBLOCK:
@@ -158,12 +156,10 @@
 		// x, y := f() becomes BLOCK{CALL f, AS x [SP+0], AS y [SP+n]}
 		// We don't want to instrument between the statements because it will
 		// smash the results.
-		case OCALLFUNC,
-			OCALLMETH,
-			OCALLINTER:
+		case OCALLFUNC, OCALLMETH, OCALLINTER:
 			racewalknode(&n.List.N, &n.List.N.Ninit, 0, 0)
 
-			fini := (*NodeList)(nil)
+			var fini *NodeList
 			racewalklist(n.List.Next, &fini)
 			n.List = concat(n.List, fini)
 
@@ -248,9 +244,7 @@
 		callinstr(&n, init, wr, skip)
 		goto ret
 
-	case OSPTR,
-		OLEN,
-		OCAP:
+	case OSPTR, OLEN, OCAP:
 		racewalknode(&n.Left, init, 0, 0)
 		if Istype(n.Left.Type, TMAP) {
 			n1 := Nod(OCONVNOP, n.Left, nil)
@@ -284,8 +278,7 @@
 		racewalknode(&n.Right, init, wr, 0)
 		goto ret
 
-	case OANDAND,
-		OOROR:
+	case OANDAND, OOROR:
 		racewalknode(&n.Left, init, wr, 0)
 
 		// walk has ensured the node has moved to a location where
@@ -308,8 +301,7 @@
 		racewalknode(&n.Left, init, wr, 0)
 		goto ret
 
-	case ODIV,
-		OMOD:
+	case ODIV, OMOD:
 		racewalknode(&n.Left, init, wr, 0)
 		racewalknode(&n.Right, init, wr, 0)
 		goto ret
@@ -333,10 +325,7 @@
 
 		// Seems to only lead to double instrumentation.
 	//racewalknode(&n->left, init, 0, 0);
-	case OSLICE,
-		OSLICEARR,
-		OSLICE3,
-		OSLICE3ARR:
+	case OSLICE, OSLICEARR, OSLICE3, OSLICE3ARR:
 		goto ret
 
 	case OADDR:
@@ -399,8 +388,7 @@
 		goto ret
 
 		// impossible nodes: only appear in backend.
-	case ORROTC,
-		OEXTEND:
+	case ORROTC, OEXTEND:
 		Yyerror("racewalk: %v cannot exist now", Oconv(int(n.Op), 0))
 
 		goto ret
@@ -559,8 +547,7 @@
 		}
 
 		// Turn T(v).Field into v.Field
-	case ODOT,
-		OXDOT:
+	case ODOT, OXDOT:
 		if n.Left.Op == OCONVNOP {
 			n.Left = n.Left.Left
 		}
@@ -621,15 +608,12 @@
 
 func hascallspred(n *Node, c interface{}) {
 	switch n.Op {
-	case OCALL,
-		OCALLFUNC,
-		OCALLMETH,
-		OCALLINTER:
+	case OCALL, OCALLFUNC, OCALLMETH, OCALLINTER:
 		(*c.(*int))++
 	}
 }
 
-// appendinit is like addinit in subr.c
+// appendinit is like addinit in subr.go
 // but appends rather than prepends.
 func appendinit(np **Node, init *NodeList) {
 	if init == nil {
@@ -640,8 +624,7 @@
 	switch n.Op {
 	// There may be multiple refs to this node;
 	// introduce OCONVNOP to hold init list.
-	case ONAME,
-		OLITERAL:
+	case ONAME, OLITERAL:
 		n = Nod(OCONVNOP, n, nil)
 
 		n.Type = n.Left.Type
diff --git a/src/cmd/internal/gc/range.go b/src/cmd/internal/gc/range.go
index 616c859..979c76a 100644
--- a/src/cmd/internal/gc/range.go
+++ b/src/cmd/internal/gc/range.go
@@ -41,7 +41,7 @@
 		}
 	}
 
-	if Isptr[t.Etype] != 0 && Isfixedarray(t.Type) {
+	if Isptr[t.Etype] && Isfixedarray(t.Type) {
 		t = t.Type
 	}
 	n.Type = t
@@ -135,17 +135,23 @@
 }
 
 func walkrange(n *Node) {
+	// variable name conventions:
+	//	ohv1, hv1, hv2: hidden (old) val 1, 2
+	//	ha, hit: hidden aggregate, iterator
+	//	hn, hp: hidden len, pointer
+	//	hb: hidden bool
+	//	a, v1, v2: not hidden aggregate, val 1, 2
+
 	t := n.Type
-	init := (*NodeList)(nil)
 
 	a := n.Right
 	lno := int(setlineno(a))
 
-	v1 := (*Node)(nil)
+	var v1 *Node
 	if n.List != nil {
 		v1 = n.List.N
 	}
-	v2 := (*Node)(nil)
+	var v2 *Node
 	if n.List != nil && n.List.Next != nil && !isblank(n.List.Next.N) {
 		v2 = n.List.Next.N
 	}
@@ -154,9 +160,8 @@
 	// to avoid erroneous processing by racewalk.
 	n.List = nil
 
-	hv2 := (*Node)(nil)
-
 	var body *NodeList
+	var init *NodeList
 	switch t.Etype {
 	default:
 		Fatal("walkrange")
@@ -250,7 +255,7 @@
 
 		hv1 := temp(Types[TINT])
 		hn := temp(Types[TINT])
-		hp := (*Node)(nil)
+		var hp *Node
 
 		init = list(init, Nod(OAS, hv1, nil))
 		init = list(init, Nod(OAS, hn, Nod(OLEN, ha, nil)))
@@ -301,19 +306,17 @@
 		hit := n.Alloc
 		hit.Type = th
 		n.Left = nil
-		keyname := newname(th.Type.Sym)      // depends on layout of iterator struct.  See reflect.c:hiter
+		keyname := newname(th.Type.Sym)      // depends on layout of iterator struct.  See reflect.go:hiter
 		valname := newname(th.Type.Down.Sym) // ditto
 
 		fn := syslook("mapiterinit", 1)
 
-		argtype(fn, t.Down)
-		argtype(fn, t.Type)
-		argtype(fn, th)
+		substArgTypes(fn, t.Down, t.Type, th)
 		init = list(init, mkcall1(fn, nil, nil, typename(t), ha, Nod(OADDR, hit, nil)))
 		n.Ntest = Nod(ONE, Nod(ODOT, hit, keyname), nodnil())
 
 		fn = syslook("mapiternext", 1)
-		argtype(fn, th)
+		substArgTypes(fn, th)
 		n.Nincr = mkcall1(fn, nil, nil, Nod(OADDR, hit, nil))
 
 		key := Nod(ODOT, hit, keyname)
@@ -366,6 +369,7 @@
 		init = list(init, Nod(OAS, hv1, nil))
 
 		var a *Node
+		var hv2 *Node
 		if v2 == nil {
 			a = Nod(OAS, hv1, mkcall("stringiter", Types[TINT], nil, ha, hv1))
 		} else {
diff --git a/src/cmd/internal/gc/reflect.go b/src/cmd/internal/gc/reflect.go
index 6059e35..bd5be0f 100644
--- a/src/cmd/internal/gc/reflect.go
+++ b/src/cmd/internal/gc/reflect.go
@@ -28,7 +28,7 @@
 	if b.pkg == nil {
 		return +1
 	}
-	return stringsCompare(a.pkg.Path.S, b.pkg.Path.S)
+	return stringsCompare(a.pkg.Path, b.pkg.Path)
 }
 
 func lsort(l *Sig, f func(*Sig, *Sig) int) *Sig {
@@ -107,7 +107,7 @@
 // the given map type.  This type is not visible to users -
 // we include only enough information to generate a correct GC
 // program for it.
-// Make sure this stays in sync with ../../runtime/hashmap.c!
+// Make sure this stays in sync with ../../runtime/hashmap.go!
 const (
 	BUCKETSIZE = 8
 	MAXKEYSIZE = 128
@@ -236,7 +236,7 @@
 	//    bucket uintptr
 	//    checkBucket uintptr
 	// }
-	// must match ../../runtime/hashmap.c:hash_iter.
+	// must match ../../runtime/hashmap.go:hash_iter.
 	var field [12]*Type
 	field[0] = makefield("key", Ptrto(t.Down))
 
@@ -275,7 +275,7 @@
  * return function type, receiver as first argument (or not).
  */
 func methodfunc(f *Type, receiver *Type) *Type {
-	in := (*NodeList)(nil)
+	var in *NodeList
 	if receiver != nil {
 		d := Nod(ODCLFIELD, nil, nil)
 		d.Type = receiver
@@ -290,7 +290,7 @@
 		in = list(in, d)
 	}
 
-	out := (*NodeList)(nil)
+	var out *NodeList
 	for t := getoutargx(f).Type; t != nil; t = t.Down {
 		d = Nod(ODCLFIELD, nil, nil)
 		d.Type = t.Type
@@ -328,7 +328,7 @@
 
 	// make list of methods for t,
 	// generating code if necessary.
-	a := (*Sig)(nil)
+	var a *Sig
 
 	var this *Type
 	var b *Sig
@@ -358,10 +358,10 @@
 		// method does not apply.
 		this = getthisx(f.Type).Type.Type
 
-		if Isptr[this.Etype] != 0 && this.Type == t {
+		if Isptr[this.Etype] && this.Type == t {
 			continue
 		}
-		if Isptr[this.Etype] != 0 && Isptr[t.Etype] == 0 && f.Embedded != 2 && !isifacemethod(f.Type) {
+		if Isptr[this.Etype] && !Isptr[t.Etype] && f.Embedded != 2 && !isifacemethod(f.Type) {
 			continue
 		}
 
@@ -412,8 +412,8 @@
 	var method *Sym
 	var isym *Sym
 
-	all := (*Sig)(nil)
-	last := (*Sig)(nil)
+	var all *Sig
+	var last *Sig
 	for f := t.Type; f != nil; f = f.Down {
 		if f.Etype != TFIELD {
 			Fatal("imethods: not field")
@@ -472,12 +472,25 @@
 		return
 	}
 
+	// If we are compiling the runtime package, there are two runtime packages around
+	// -- localpkg and Runtimepkg.  We don't want to produce import path symbols for
+	// both of them, so just produce one for localpkg.
+	if myimportpath == "runtime" && p == Runtimepkg {
+		return
+	}
+
 	if dimportpath_gopkg == nil {
-		dimportpath_gopkg = mkpkg(newstrlit("go"))
+		dimportpath_gopkg = mkpkg("go")
 		dimportpath_gopkg.Name = "go"
 	}
 
-	nam := fmt.Sprintf("importpath.%s.", p.Prefix)
+	var nam string
+	if p == localpkg {
+		// Note: myimportpath != "", or else dgopkgpath won't call dimportpath.
+		nam = "importpath." + pathtoprefix(myimportpath) + "."
+	} else {
+		nam = "importpath." + p.Prefix + "."
+	}
 
 	n := Nod(ONAME, nil, nil)
 	n.Sym = Pkglookup(nam, dimportpath_gopkg)
@@ -495,14 +508,15 @@
 		return dgostringptr(s, ot, "")
 	}
 
-	// Emit reference to go.importpath.""., which 6l will
-	// rewrite using the correct import path.  Every package
-	// that imports this one directly defines the symbol.
-	if pkg == localpkg {
+	if pkg == localpkg && myimportpath == "" {
+		// If we don't know the full path of the package being compiled (i.e. -p
+		// was not passed on the compiler command line), emit reference to
+		// go.importpath.""., which 6l will rewrite using the correct import path.
+		// Every package that imports this one directly defines the symbol.
 		var ns *Sym
 
 		if ns == nil {
-			ns = Pkglookup("importpath.\"\".", mkpkg(newstrlit("go")))
+			ns = Pkglookup("importpath.\"\".", mkpkg("go"))
 		}
 		return dsymptr(s, ot, ns, 0)
 	}
@@ -687,13 +701,13 @@
 	}
 	dowidth(t)
 	alg := algtype(t)
-	algsym := (*Sym)(nil)
+	var algsym *Sym
 	if alg < 0 || alg == AMEM {
 		algsym = dalgsym(t)
 	}
 
 	var sptr *Sym
-	if t.Sym != nil && Isptr[t.Etype] == 0 {
+	if t.Sym != nil && !Isptr[t.Etype] {
 		sptr = dtypesym(Ptrto(t))
 	} else {
 		sptr = weaktypesym(Ptrto(t))
@@ -808,7 +822,7 @@
 		ot = duintptr(s, ot, 0)
 	}
 
-	p := fmt.Sprintf("%v", Tconv(t, obj.FmtLeft|obj.FmtUnsigned))
+	p := Tconv(t, obj.FmtLeft|obj.FmtUnsigned)
 
 	//print("dcommontype: %s\n", p);
 	ot = dgostringptr(s, ot, p) // string
@@ -825,19 +839,11 @@
 }
 
 func typesym(t *Type) *Sym {
-	p := fmt.Sprintf("%v", Tconv(t, obj.FmtLeft))
-	s := Pkglookup(p, typepkg)
-
-	//print("typesym: %s -> %+S\n", p, s);
-
-	return s
+	return Pkglookup(Tconv(t, obj.FmtLeft), typepkg)
 }
 
 func tracksym(t *Type) *Sym {
-	p := fmt.Sprintf("%v.%s", Tconv(t.Outer, obj.FmtLeft), t.Sym.Name)
-	s := Pkglookup(p, trackpkg)
-
-	return s
+	return Pkglookup(Tconv(t.Outer, obj.FmtLeft)+"."+t.Sym.Name, trackpkg)
 }
 
 func typelinksym(t *Type) *Sym {
@@ -849,7 +855,7 @@
 	// disambiguate. The names are a little long but they are
 	// discarded by the linker and do not end up in the symbol
 	// table of the final binary.
-	p := fmt.Sprintf("%v/%v", Tconv(t, obj.FmtLeft|obj.FmtUnsigned), Tconv(t, obj.FmtLeft))
+	p := Tconv(t, obj.FmtLeft|obj.FmtUnsigned) + "/" + Tconv(t, obj.FmtLeft)
 
 	s := Pkglookup(p, typelinkpkg)
 
@@ -859,7 +865,7 @@
 }
 
 func typesymprefix(prefix string, t *Type) *Sym {
-	p := fmt.Sprintf("%s.%v", prefix, Tconv(t, obj.FmtLeft))
+	p := prefix + "." + Tconv(t, obj.FmtLeft)
 	s := Pkglookup(p, typepkg)
 
 	//print("algsym: %s -> %+S\n", p, s);
@@ -868,7 +874,7 @@
 }
 
 func typenamesym(t *Type) *Sym {
-	if t == nil || (Isptr[t.Etype] != 0 && t.Type == nil) || isideal(t) {
+	if t == nil || (Isptr[t.Etype] && t.Type == nil) || isideal(t) {
 		Fatal("typename %v", Tconv(t, 0))
 	}
 	s := typesym(t)
@@ -900,7 +906,7 @@
 }
 
 func weaktypesym(t *Type) *Sym {
-	p := fmt.Sprintf("%v", Tconv(t, obj.FmtLeft))
+	p := Tconv(t, obj.FmtLeft)
 	s := Pkglookup(p, weaktypepkg)
 
 	//print("weaktypesym: %s -> %+S\n", p, s);
@@ -962,9 +968,6 @@
 }
 
 func dtypesym(t *Type) *Sym {
-	var n int
-	var t1 *Type
-
 	// Replace byte, rune aliases with real type.
 	// They've been separate internally to make error messages
 	// better, but we have to merge them in the reflect tables.
@@ -987,7 +990,7 @@
 	// emit the type structures for int, float, etc.
 	tbase := t
 
-	if Isptr[t.Etype] != 0 && t.Sym == nil && t.Type.Sym != nil {
+	if Isptr[t.Etype] && t.Sym == nil && t.Type.Sym != nil {
 		tbase = t.Type
 	}
 	dupok := 0
@@ -1000,10 +1003,10 @@
 	}
 
 	// named types from other files are defined only by those files
-	if tbase.Sym != nil && tbase.Local == 0 {
+	if tbase.Sym != nil && !tbase.Local {
 		return s
 	}
-	if isforw[tbase.Etype] != 0 {
+	if isforw[tbase.Etype] {
 		return s
 	}
 
@@ -1048,28 +1051,28 @@
 		ot = duintptr(s, ot, uint64(t.Chan))
 
 	case TFUNC:
-		for t1 = getthisx(t).Type; t1 != nil; t1 = t1.Down {
+		for t1 := getthisx(t).Type; t1 != nil; t1 = t1.Down {
 			dtypesym(t1.Type)
 		}
-		isddd := 0
-		for t1 = getinargx(t).Type; t1 != nil; t1 = t1.Down {
-			isddd = int(t1.Isddd)
+		isddd := false
+		for t1 := getinargx(t).Type; t1 != nil; t1 = t1.Down {
+			isddd = t1.Isddd
 			dtypesym(t1.Type)
 		}
 
-		for t1 = getoutargx(t).Type; t1 != nil; t1 = t1.Down {
+		for t1 := getoutargx(t).Type; t1 != nil; t1 = t1.Down {
 			dtypesym(t1.Type)
 		}
 
 		ot = dcommontype(s, ot, t)
 		xt = ot - 3*Widthptr
-		ot = duint8(s, ot, uint8(isddd))
+		ot = duint8(s, ot, uint8(bool2int(isddd)))
 
 		// two slice headers: in and out.
 		ot = int(Rnd(int64(ot), int64(Widthptr)))
 
 		ot = dsymptr(s, ot, s, ot+2*(Widthptr+2*Widthint))
-		n = t.Thistuple + t.Intuple
+		n := t.Thistuple + t.Intuple
 		ot = duintxx(s, ot, uint64(n), Widthint)
 		ot = duintxx(s, ot, uint64(n), Widthint)
 		ot = dsymptr(s, ot, s, ot+1*(Widthptr+2*Widthint)+n*Widthptr)
@@ -1077,19 +1080,22 @@
 		ot = duintxx(s, ot, uint64(t.Outtuple), Widthint)
 
 		// slice data
-		for t1 = getthisx(t).Type; t1 != nil; (func() { t1 = t1.Down; n++ })() {
+		for t1 := getthisx(t).Type; t1 != nil; t1 = t1.Down {
 			ot = dsymptr(s, ot, dtypesym(t1.Type), 0)
+			n++
 		}
-		for t1 = getinargx(t).Type; t1 != nil; (func() { t1 = t1.Down; n++ })() {
+		for t1 := getinargx(t).Type; t1 != nil; t1 = t1.Down {
 			ot = dsymptr(s, ot, dtypesym(t1.Type), 0)
+			n++
 		}
-		for t1 = getoutargx(t).Type; t1 != nil; (func() { t1 = t1.Down; n++ })() {
+		for t1 := getoutargx(t).Type; t1 != nil; t1 = t1.Down {
 			ot = dsymptr(s, ot, dtypesym(t1.Type), 0)
+			n++
 		}
 
 	case TINTER:
 		m := imethods(t)
-		n = 0
+		n := 0
 		for a := m; a != nil; a = a.link {
 			dtypesym(a.type_)
 			n++
@@ -1142,8 +1148,7 @@
 		ot = duint16(s, ot, uint16(mapbucket(t).Width))
 		ot = duint8(s, ot, uint8(bool2int(isreflexive(t.Down))))
 
-	case TPTR32,
-		TPTR64:
+	case TPTR32, TPTR64:
 		if t.Type.Etype == TANY {
 			// ../../runtime/type.go:/UnsafePointerType
 			ot = dcommontype(s, ot, t)
@@ -1161,9 +1166,9 @@
 		// ../../runtime/type.go:/StructType
 	// for security, only the exported fields.
 	case TSTRUCT:
-		n = 0
+		n := 0
 
-		for t1 = t.Type; t1 != nil; t1 = t1.Down {
+		for t1 := t.Type; t1 != nil; t1 = t1.Down {
 			dtypesym(t1.Type)
 			n++
 		}
@@ -1173,7 +1178,7 @@
 		ot = dsymptr(s, ot, s, ot+Widthptr+2*Widthint)
 		ot = duintxx(s, ot, uint64(n), Widthint)
 		ot = duintxx(s, ot, uint64(n), Widthint)
-		for t1 = t.Type; t1 != nil; t1 = t1.Down {
+		for t1 := t.Type; t1 != nil; t1 = t1.Down {
 			// ../../runtime/type.go:/structField
 			if t1.Sym != nil && t1.Embedded == 0 {
 				ot = dgostringptr(s, ot, t1.Sym.Name)
@@ -1207,9 +1212,7 @@
 	// we want be able to find.
 	if t.Sym == nil {
 		switch t.Etype {
-		case TARRAY,
-			TCHAN,
-			TMAP:
+		case TARRAY, TCHAN, TMAP:
 			slink := typelinksym(t)
 			dsymptr(slink, 0, s, 0)
 			ggloblsym(slink, int32(Widthptr), int8(dupok|obj.RODATA))
@@ -1246,12 +1249,9 @@
 	}
 
 	// generate import strings for imported packages
-	var p *Pkg
-	for i := 0; i < len(phash); i++ {
-		for p = phash[i]; p != nil; p = p.Link {
-			if p.Direct != 0 {
-				dimportpath(p)
-			}
+	for _, p := range pkgs {
+		if p.Direct != 0 {
+			dimportpath(p)
 		}
 	}
 
@@ -1280,7 +1280,7 @@
 		if flag_race != 0 {
 			dimportpath(racepkg)
 		}
-		dimportpath(mkpkg(newstrlit("main")))
+		dimportpath(mkpkg("main"))
 	}
 }
 
@@ -1479,11 +1479,9 @@
 
 // Emit insArray instruction.
 func proggenarray(g *ProgGen, len int64) {
-	var i int32
-
 	proggendataflush(g)
 	proggenemit(g, obj.InsArray)
-	for i = 0; i < int32(Widthptr); (func() { i++; len >>= 8 })() {
+	for i := int32(0); i < int32(Widthptr); i, len = i+1, len>>8 {
 		proggenemit(g, uint8(len))
 	}
 }
diff --git a/src/cmd/internal/gc/reg.go b/src/cmd/internal/gc/reg.go
index 5f9586b..66982ef 100644
--- a/src/cmd/internal/gc/reg.go
+++ b/src/cmd/internal/gc/reg.go
@@ -31,14 +31,111 @@
 package gc
 
 import (
+	"bytes"
 	"cmd/internal/obj"
 	"fmt"
 	"sort"
+	"strings"
 )
 
-var firstf *Flow
+// A Var represents a single variable that may be stored in a register.
+// That variable may itself correspond to a hardware register,
+// to represent the use of registers in the unoptimized instruction stream.
+type Var struct {
+	offset     int64
+	node       *Node
+	nextinnode *Var
+	width      int
+	id         int // index in vars
+	name       int8
+	etype      int8
+	addr       int8
+}
 
-var first int = 1
+// Bits represents a set of Vars, stored as a bit set of var numbers
+// (the index in vars, or equivalently v.id).
+type Bits struct {
+	b [BITS]uint64
+}
+
+const (
+	BITS = 3
+	NVAR = BITS * 64
+)
+
+var (
+	vars [NVAR]Var // variables under consideration
+	nvar int       // number of vars
+
+	regbits uint64 // bits for hardware registers
+
+	zbits   Bits // zero
+	externs Bits // global variables
+	params  Bits // function parameters and results
+	ivar    Bits // function parameters (inputs)
+	ovar    Bits // function results (outputs)
+	consts  Bits // constant values
+	addrs   Bits // variables with address taken
+)
+
+// A Reg is a wrapper around a single Prog (one instruction) that holds
+// register optimization information while the optimizer runs.
+// r->prog is the instruction.
+type Reg struct {
+	set  Bits // regopt variables written by this instruction.
+	use1 Bits // regopt variables read by prog->from.
+	use2 Bits // regopt variables read by prog->to.
+
+	// refahead/refbehind are the regopt variables whose current
+	// value may be used in the following/preceding instructions
+	// up to a CALL (or the value is clobbered).
+	refbehind Bits
+	refahead  Bits
+
+	// calahead/calbehind are similar, but for variables in
+	// instructions that are reachable after hitting at least one
+	// CALL.
+	calbehind Bits
+	calahead  Bits
+
+	regdiff Bits
+	act     Bits
+	regu    uint64 // register used bitmap
+}
+
+// A Rgn represents a single regopt variable over a region of code
+// where a register could potentially be dedicated to that variable.
+// The code encompassed by a Rgn is defined by the flow graph,
+// starting at enter, flood-filling forward while varno is refahead
+// and backward while varno is refbehind, and following branches.
+// A single variable may be represented by multiple disjoint Rgns and
+// each Rgn may choose a different register for that variable.
+// Registers are allocated to regions greedily in order of descending
+// cost.
+type Rgn struct {
+	enter *Flow
+	cost  int16
+	varno int16
+	regno int16
+}
+
+// The Plan 9 C compilers used a limit of 600 regions,
+// but the yacc-generated parser in y.go has 3100 regions.
+// We set MaxRgn large enough to handle that.
+// There's not a huge cost to having too many regions:
+// the main processing traces the live area for each variable,
+// which is limited by the number of variables times the area,
+// not the raw region count. If there are many regions, they
+// are almost certainly small and easy to trace.
+// The only operation that scales with region count is the
+// sorting by cost, which uses sort.Sort and is therefore
+// guaranteed n log n.
+const MaxRgn = 6000
+
+var (
+	region  []Rgn
+	nregion int
+)
 
 type rcmp []Rgn
 
@@ -75,13 +172,13 @@
 		// convert each bit to a variable
 		i = bnum(bit)
 
-		node = var_[i].node
-		n = int(var_[i].name)
+		node = vars[i].node
+		n = int(vars[i].name)
 		biclr(&bit, uint(i))
 
 		// disable all pieces of that variable
 		for i = 0; i < nvar; i++ {
-			v = &var_[i:][0]
+			v = &vars[i]
 			if v.node == node && int(v.name) == n {
 				v.addr = 2
 			}
@@ -135,7 +232,7 @@
 	p.Link = p1
 	p1.Lineno = p.Lineno
 
-	v := &var_[bn:][0]
+	v := &vars[bn]
 
 	a := &p1.To
 	a.Offset = v.offset
@@ -154,7 +251,7 @@
 	p1.As = int16(Thearch.Optoas(OAS, Types[uint8(v.etype)]))
 
 	// TODO(rsc): Remove special case here.
-	if (Thearch.Thechar == '9' || Thearch.Thechar == '5') && v.etype == TBOOL {
+	if (Thearch.Thechar == '5' || Thearch.Thechar == '7' || Thearch.Thechar == '9') && v.etype == TBOOL {
 		p1.As = int16(Thearch.Optoas(OAS, Types[TUINT8]))
 	}
 	p1.From.Type = obj.TYPE_REG
@@ -185,32 +282,22 @@
 }
 
 func mkvar(f *Flow, a *obj.Addr) Bits {
-	var v *Var
-	var i int
-	var n int
-	var et int
-	var flag int
-	var w int64
-	var o int64
-	var bit Bits
-	var node *Node
-	var r *Reg
-
 	/*
 	 * mark registers used
 	 */
 	if a.Type == obj.TYPE_NONE {
-		goto none
+		return zbits
 	}
 
-	r = f.Data.(*Reg)
+	r := f.Data.(*Reg)
 	r.use1.b[0] |= Thearch.Doregbits(int(a.Index)) // TODO: Use RtoB
 
+	var n int
 	switch a.Type {
 	default:
 		regu := Thearch.Doregbits(int(a.Reg)) | Thearch.RtoB(int(a.Reg)) // TODO: Use RtoB
 		if regu == 0 {
-			goto none
+			return zbits
 		}
 		bit := zbits
 		bit.b[0] = regu
@@ -219,7 +306,7 @@
 		// TODO(rsc): Remove special case here.
 	case obj.TYPE_ADDR:
 		var bit Bits
-		if Thearch.Thechar == '9' || Thearch.Thechar == '5' {
+		if Thearch.Thechar == '5' || Thearch.Thechar == '7' || Thearch.Thechar == '9' {
 			goto memcase
 		}
 		a.Type = obj.TYPE_MEM
@@ -227,13 +314,13 @@
 		setaddrs(bit)
 		a.Type = obj.TYPE_ADDR
 		Ostats.Naddr++
-		goto none
+		return zbits
 
 	memcase:
 		fallthrough
 
 	case obj.TYPE_MEM:
-		if r != R {
+		if r != nil {
 			r.use1.b[0] |= Thearch.RtoB(int(a.Reg))
 		}
 
@@ -243,37 +330,43 @@
 		*/
 		switch a.Name {
 		default:
-			goto none
+			// Note: This case handles NAME_EXTERN and NAME_STATIC.
+			// We treat these as requiring eager writes to memory, due to
+			// the possibility of a fault handler looking at them, so there is
+			// not much point in registerizing the loads.
+			// If we later choose the set of candidate variables from a
+			// larger list, these cases could be deprioritized instead of
+			// removed entirely.
+			return zbits
 
-		case obj.NAME_EXTERN,
-			obj.NAME_STATIC,
-			obj.NAME_PARAM,
+		case obj.NAME_PARAM,
 			obj.NAME_AUTO:
 			n = int(a.Name)
 		}
 	}
 
-	node, _ = a.Node.(*Node)
+	node, _ := a.Node.(*Node)
 	if node == nil || node.Op != ONAME || node.Orig == nil {
-		goto none
+		return zbits
 	}
 	node = node.Orig
 	if node.Orig != node {
 		Fatal("%v: bad node", Ctxt.Dconv(a))
 	}
 	if node.Sym == nil || node.Sym.Name[0] == '.' {
-		goto none
+		return zbits
 	}
-	et = int(a.Etype)
-	o = a.Offset
-	w = a.Width
+	et := int(a.Etype)
+	o := a.Offset
+	w := a.Width
 	if w < 0 {
 		Fatal("bad width %d for %v", w, Ctxt.Dconv(a))
 	}
 
-	flag = 0
+	flag := 0
+	var v *Var
 	for i := 0; i < nvar; i++ {
-		v = &var_[i:][0]
+		v = &vars[i]
 		if v.node == node && int(v.name) == n {
 			if v.offset == o {
 				if int(v.etype) == et {
@@ -297,15 +390,17 @@
 	}
 
 	switch et {
-	case 0,
-		TFUNC:
-		goto none
+	case 0, TFUNC:
+		return zbits
 	}
 
 	if nvar >= NVAR {
 		if Debug['w'] > 1 && node != nil {
 			Fatal("variable not optimized: %v", Nconv(node, obj.FmtSharp))
 		}
+		if Debug['v'] > 0 {
+			Warn("variable not optimized: %v", Nconv(node, obj.FmtSharp))
+		}
 
 		// If we're not tracking a word in a variable, mark the rest as
 		// having its address taken, so that we keep the whole thing
@@ -313,18 +408,18 @@
 		// a variable but not all of it.
 		var v *Var
 		for i := 0; i < nvar; i++ {
-			v = &var_[i:][0]
+			v = &vars[i]
 			if v.node == node {
 				v.addr = 1
 			}
 		}
 
-		goto none
+		return zbits
 	}
 
-	i = nvar
+	i := nvar
 	nvar++
-	v = &var_[i:][0]
+	v = &vars[i]
 	v.id = i
 	v.offset = o
 	v.name = int8(n)
@@ -341,7 +436,7 @@
 
 	node.Opt = v
 
-	bit = blsh(uint(i))
+	bit := blsh(uint(i))
 	if n == obj.NAME_EXTERN || n == obj.NAME_STATIC {
 		for z := 0; z < BITS; z++ {
 			externs.b[z] |= bit.b[z]
@@ -379,7 +474,7 @@
 	// If we were better about _ elision, _ = &x would suffice too.
 	// The broader := in a closure problem is mentioned in a comment in
 	// closure.c:/^typecheckclosure and dcl.c:/^oldname.
-	if node.Addrtaken != 0 {
+	if node.Addrtaken {
 		v.addr = 1
 	}
 
@@ -401,11 +496,10 @@
 	Ostats.Nvar++
 
 	return bit
-
-none:
-	return zbits
 }
 
+var change int
+
 func prop(f *Flow, ref Bits, cal Bits) {
 	var f1 *Flow
 	var r1 *Reg
@@ -420,13 +514,13 @@
 			ref.b[z] |= r1.refahead.b[z]
 			if ref.b[z] != r1.refahead.b[z] {
 				r1.refahead.b[z] = ref.b[z]
-				change++
+				change = 1
 			}
 
 			cal.b[z] |= r1.calahead.b[z]
 			if cal.b[z] != r1.calahead.b[z] {
 				r1.calahead.b[z] = cal.b[z]
-				change++
+				change = 1
 			}
 		}
 
@@ -468,7 +562,7 @@
 					if z*64+i >= nvar || (cal.b[z]>>uint(i))&1 == 0 {
 						continue
 					}
-					v = &var_[z*64+i:][0]
+					v = &vars[z*64+i]
 					if v.node.Opt == nil { // v represents fixed register, not Go variable
 						continue
 					}
@@ -539,7 +633,7 @@
 			dif.b[z] = dif.b[z]&^(^r1.refbehind.b[z]&r1.refahead.b[z]) | r1.set.b[z] | r1.regdiff.b[z]
 			if dif.b[z] != r1.regdiff.b[z] {
 				r1.regdiff.b[z] = dif.b[z]
-				change++
+				change = 1
 			}
 		}
 
@@ -557,7 +651,7 @@
 }
 
 func allreg(b uint64, r *Rgn) uint64 {
-	v := &var_[r.varno:][0]
+	v := &vars[r.varno]
 	r.regno = 0
 	switch v.etype {
 	default:
@@ -583,8 +677,7 @@
 			return Thearch.RtoB(i)
 		}
 
-	case TFLOAT32,
-		TFLOAT64:
+	case TFLOAT32, TFLOAT64:
 		i := Thearch.BtoF(^b)
 		if i != 0 && r.cost > 0 {
 			r.regno = int16(i)
@@ -603,6 +696,13 @@
 	return ^r.calbehind.b[z] & r.calahead.b[z]
 }
 
+// Cost parameters
+const (
+	CLOAD = 5 // cost of load
+	CREF  = 5 // cost of reference if not registerized
+	LOOP  = 3 // loop execution count (applied in popt.go)
+)
+
 func paint1(f *Flow, bn int) {
 	z := bn / 64
 	bb := uint64(1 << uint(bn%64))
@@ -867,31 +967,31 @@
 		if bany(&bit) {
 			fmt.Printf("\t")
 			if bany(&r.set) {
-				fmt.Printf(" s:%v", Qconv(r.set, 0))
+				fmt.Printf(" s:%v", &r.set)
 			}
 			if bany(&r.use1) {
-				fmt.Printf(" u1:%v", Qconv(r.use1, 0))
+				fmt.Printf(" u1:%v", &r.use1)
 			}
 			if bany(&r.use2) {
-				fmt.Printf(" u2:%v", Qconv(r.use2, 0))
+				fmt.Printf(" u2:%v", &r.use2)
 			}
 			if bany(&r.refbehind) {
-				fmt.Printf(" rb:%v ", Qconv(r.refbehind, 0))
+				fmt.Printf(" rb:%v ", &r.refbehind)
 			}
 			if bany(&r.refahead) {
-				fmt.Printf(" ra:%v ", Qconv(r.refahead, 0))
+				fmt.Printf(" ra:%v ", &r.refahead)
 			}
 			if bany(&r.calbehind) {
-				fmt.Printf(" cb:%v ", Qconv(r.calbehind, 0))
+				fmt.Printf(" cb:%v ", &r.calbehind)
 			}
 			if bany(&r.calahead) {
-				fmt.Printf(" ca:%v ", Qconv(r.calahead, 0))
+				fmt.Printf(" ca:%v ", &r.calahead)
 			}
 			if bany(&r.regdiff) {
-				fmt.Printf(" d:%v ", Qconv(r.regdiff, 0))
+				fmt.Printf(" d:%v ", &r.regdiff)
 			}
 			if bany(&r.act) {
-				fmt.Printf(" a:%v ", Qconv(r.act, 0))
+				fmt.Printf(" a:%v ", &r.act)
 			}
 		}
 	}
@@ -934,10 +1034,6 @@
 }
 
 func regopt(firstp *obj.Prog) {
-	if first != 0 {
-		first = 0
-	}
-
 	mergetemp(firstp)
 
 	/*
@@ -950,13 +1046,13 @@
 
 	nvar = nreg
 	for i := 0; i < nreg; i++ {
-		var_[i] = Var{}
+		vars[i] = Var{}
 	}
 	for i := 0; i < nreg; i++ {
 		if regnodes[i] == nil {
 			regnodes[i] = newname(Lookup(regnames[i]))
 		}
-		var_[i].node = regnodes[i]
+		vars[i].node = regnodes[i]
 	}
 
 	regbits = Thearch.Excludedregs()
@@ -974,27 +1070,20 @@
 	 * find use and set of variables
 	 */
 	g := Flowstart(firstp, func() interface{} { return new(Reg) })
-
 	if g == nil {
 		for i := 0; i < nvar; i++ {
-			var_[i].node.Opt = nil
+			vars[i].node.Opt = nil
 		}
 		return
 	}
 
-	firstf = g.Start
+	firstf := g.Start
 
-	var r *Reg
-	var info ProgInfo
-	var p *obj.Prog
-	var bit Bits
-	var z int
 	for f := firstf; f != nil; f = f.Link {
-		p = f.Prog
+		p := f.Prog
 		if p.As == obj.AVARDEF || p.As == obj.AVARKILL {
 			continue
 		}
-		Thearch.Proginfo(&info, p)
 
 		// Avoid making variables for direct-called functions.
 		if p.As == obj.ACALL && p.To.Type == obj.TYPE_MEM && p.To.Name == obj.NAME_EXTERN {
@@ -1002,30 +1091,29 @@
 		}
 
 		// from vs to doesn't matter for registers.
-		r = f.Data.(*Reg)
+		r := f.Data.(*Reg)
+		r.use1.b[0] |= p.Info.Reguse | p.Info.Regindex
+		r.set.b[0] |= p.Info.Regset
 
-		r.use1.b[0] |= info.Reguse | info.Regindex
-		r.set.b[0] |= info.Regset
-
-		bit = mkvar(f, &p.From)
+		bit := mkvar(f, &p.From)
 		if bany(&bit) {
-			if info.Flags&LeftAddr != 0 {
+			if p.Info.Flags&LeftAddr != 0 {
 				setaddrs(bit)
 			}
-			if info.Flags&LeftRead != 0 {
-				for z = 0; z < BITS; z++ {
+			if p.Info.Flags&LeftRead != 0 {
+				for z := 0; z < BITS; z++ {
 					r.use1.b[z] |= bit.b[z]
 				}
 			}
-			if info.Flags&LeftWrite != 0 {
-				for z = 0; z < BITS; z++ {
+			if p.Info.Flags&LeftWrite != 0 {
+				for z := 0; z < BITS; z++ {
 					r.set.b[z] |= bit.b[z]
 				}
 			}
 		}
 
 		// Compute used register for reg
-		if info.Flags&RegRead != 0 {
+		if p.Info.Flags&RegRead != 0 {
 			r.use1.b[0] |= Thearch.RtoB(int(p.Reg))
 		}
 
@@ -1037,16 +1125,16 @@
 
 		bit = mkvar(f, &p.To)
 		if bany(&bit) {
-			if info.Flags&RightAddr != 0 {
+			if p.Info.Flags&RightAddr != 0 {
 				setaddrs(bit)
 			}
-			if info.Flags&RightRead != 0 {
-				for z = 0; z < BITS; z++ {
+			if p.Info.Flags&RightRead != 0 {
+				for z := 0; z < BITS; z++ {
 					r.use2.b[z] |= bit.b[z]
 				}
 			}
-			if info.Flags&RightWrite != 0 {
-				for z = 0; z < BITS; z++ {
+			if p.Info.Flags&RightWrite != 0 {
+				for z := 0; z < BITS; z++ {
 					r.set.b[z] |= bit.b[z]
 				}
 			}
@@ -1054,10 +1142,10 @@
 	}
 
 	for i := 0; i < nvar; i++ {
-		v := &var_[i:][0]
+		v := &vars[i]
 		if v.addr != 0 {
-			bit = blsh(uint(i))
-			for z = 0; z < BITS; z++ {
+			bit := blsh(uint(i))
+			for z := 0; z < BITS; z++ {
 				addrs.b[z] |= bit.b[z]
 			}
 		}
@@ -1092,12 +1180,12 @@
 
 	for f := firstf; f != nil; f = f.Link {
 		f.Active = 0
-		r = f.Data.(*Reg)
+		r := f.Data.(*Reg)
 		r.act = zbits
 	}
 
 	for f := firstf; f != nil; f = f.Link {
-		p = f.Prog
+		p := f.Prog
 		if p.As == obj.AVARDEF && Isfat(((p.To.Node).(*Node)).Type) && ((p.To.Node).(*Node)).Opt != nil {
 			active++
 			walkvardef(p.To.Node.(*Node), f, active)
@@ -1173,7 +1261,7 @@
 	 */
 	mask := uint64((1 << uint(nreg)) - 1)
 	for f := firstf; f != nil; f = f.Link {
-		r = f.Data.(*Reg)
+		r := f.Data.(*Reg)
 		r.regu = (r.refbehind.b[0] | r.set.b[0]) & mask
 		r.set.b[0] &^= mask
 		r.use1.b[0] &^= mask
@@ -1195,9 +1283,8 @@
 	 * isolate regions
 	 * calculate costs (paint1)
 	 */
-	f = firstf
-
-	if f != nil {
+	var bit Bits
+	if f := firstf; f != nil {
 		r := f.Data.(*Reg)
 		for z := 0; z < BITS; z++ {
 			bit.b[z] = (r.refahead.b[z] | r.calahead.b[z]) &^ (externs.b[z] | params.b[z] | addrs.b[z] | consts.b[z])
@@ -1205,7 +1292,7 @@
 		if bany(&bit) && f.Refset == 0 {
 			// should never happen - all variables are preset
 			if Debug['w'] != 0 {
-				fmt.Printf("%v: used and not set: %v\n", f.Prog.Line(), Qconv(bit, 0))
+				fmt.Printf("%v: used and not set: %v\n", f.Prog.Line(), &bit)
 			}
 			f.Refset = 1
 		}
@@ -1215,21 +1302,22 @@
 		(f.Data.(*Reg)).act = zbits
 	}
 	nregion = 0
+	region = region[:0]
 	var rgp *Rgn
 	for f := firstf; f != nil; f = f.Link {
-		r = f.Data.(*Reg)
-		for z = 0; z < BITS; z++ {
+		r := f.Data.(*Reg)
+		for z := 0; z < BITS; z++ {
 			bit.b[z] = r.set.b[z] &^ (r.refahead.b[z] | r.calahead.b[z] | addrs.b[z])
 		}
 		if bany(&bit) && f.Refset == 0 {
 			if Debug['w'] != 0 {
-				fmt.Printf("%v: set and not used: %v\n", f.Prog.Line(), Qconv(bit, 0))
+				fmt.Printf("%v: set and not used: %v\n", f.Prog.Line(), &bit)
 			}
 			f.Refset = 1
 			Thearch.Excise(f)
 		}
 
-		for z = 0; z < BITS; z++ {
+		for z := 0; z < BITS; z++ {
 			bit.b[z] = LOAD(r, z) &^ (r.act.b[z] | addrs.b[z])
 		}
 		for bany(&bit) {
@@ -1240,22 +1328,30 @@
 			if change <= 0 {
 				continue
 			}
-			if nregion >= NRGN {
-				if Debug['R'] != 0 && Debug['v'] != 0 {
-					fmt.Printf("too many regions\n")
-				}
-				goto brk
+			if nregion >= MaxRgn {
+				nregion++
+				continue
 			}
 
-			rgp = &region[nregion]
-			rgp.enter = f
-			rgp.varno = int16(i)
-			rgp.cost = int16(change)
+			region = append(region, Rgn{
+				enter: f,
+				cost:  int16(change),
+				varno: int16(i),
+			})
 			nregion++
 		}
 	}
 
-brk:
+	if false && Debug['v'] != 0 && strings.Contains(Curfn.Nname.Sym.Name, "Parse") {
+		Warn("regions: %d\n", nregion)
+	}
+	if nregion >= MaxRgn {
+		if Debug['v'] != 0 {
+			Warn("too many regions: %d\n", nregion)
+		}
+		nregion = MaxRgn
+	}
+
 	sort.Sort(rcmp(region[:nregion]))
 
 	if Debug['R'] != 0 && Debug['v'] != 0 {
@@ -1282,7 +1378,7 @@
 		vreg = allreg(usedreg, rgp)
 		if rgp.regno != 0 {
 			if Debug['R'] != 0 && Debug['v'] != 0 {
-				v := &var_[rgp.varno:][0]
+				v := &vars[rgp.varno]
 				fmt.Printf("registerize %v+%d (bit=%2d et=%v) in %v usedreg=%#x vreg=%#x\n", Nconv(v.node, 0), v.offset, rgp.varno, Econv(int(v.etype), 0), obj.Rconv(int(rgp.regno)), usedreg, vreg)
 			}
 
@@ -1294,7 +1390,7 @@
 	 * free aux structures. peep allocates new ones.
 	 */
 	for i := 0; i < nvar; i++ {
-		var_[i].node.Opt = nil
+		vars[i].node.Opt = nil
 	}
 	Flowend(g)
 	firstf = nil
@@ -1302,7 +1398,6 @@
 	if Debug['R'] != 0 && Debug['v'] != 0 {
 		// Rebuild flow graph, since we inserted instructions
 		g := Flowstart(firstp, nil)
-
 		firstf = g.Start
 		Dumpit("pass6", firstf, 0)
 		Flowend(g)
@@ -1325,8 +1420,8 @@
 			p.Link = p.Link.Link
 		}
 		if p.To.Type == obj.TYPE_BRANCH {
-			for p.To.U.Branch != nil && p.To.U.Branch.As == obj.ANOP {
-				p.To.U.Branch = p.To.U.Branch.Link
+			for p.To.Val.(*obj.Prog) != nil && p.To.Val.(*obj.Prog).As == obj.ANOP {
+				p.To.Val = p.To.Val.(*obj.Prog).Link
 			}
 		}
 	}
@@ -1358,3 +1453,107 @@
 		Ostats = OptStats{}
 	}
 }
+
+// bany reports whether any bits in a are set.
+func bany(a *Bits) bool {
+	for _, x := range &a.b { // & to avoid making a copy of a.b
+		if x != 0 {
+			return true
+		}
+	}
+	return false
+}
+
+// bnum reports the lowest index of a 1 bit in a.
+func bnum(a Bits) int {
+	for i, x := range &a.b { // & to avoid making a copy of a.b
+		if x != 0 {
+			return 64*i + Bitno(x)
+		}
+	}
+
+	Fatal("bad in bnum")
+	return 0
+}
+
+// blsh returns a Bits with 1 at index n, 0 elsewhere (1<<n).
+func blsh(n uint) Bits {
+	c := zbits
+	c.b[n/64] = 1 << (n % 64)
+	return c
+}
+
+// btest reports whether bit n is 1.
+func btest(a *Bits, n uint) bool {
+	return a.b[n/64]&(1<<(n%64)) != 0
+}
+
+// biset sets bit n to 1.
+func biset(a *Bits, n uint) {
+	a.b[n/64] |= 1 << (n % 64)
+}
+
+// biclr sets bit n to 0.
+func biclr(a *Bits, n uint) {
+	a.b[n/64] &^= (1 << (n % 64))
+}
+
+// Bitno reports the lowest index of a 1 bit in b.
+// It calls Fatal if there is no 1 bit.
+func Bitno(b uint64) int {
+	if b == 0 {
+		Fatal("bad in bitno")
+	}
+	n := 0
+	if b&(1<<32-1) == 0 {
+		n += 32
+		b >>= 32
+	}
+	if b&(1<<16-1) == 0 {
+		n += 16
+		b >>= 16
+	}
+	if b&(1<<8-1) == 0 {
+		n += 8
+		b >>= 8
+	}
+	if b&(1<<4-1) == 0 {
+		n += 4
+		b >>= 4
+	}
+	if b&(1<<2-1) == 0 {
+		n += 2
+		b >>= 2
+	}
+	if b&1 == 0 {
+		n++
+	}
+	return n
+}
+
+// String returns a space-separated list of the variables represented by bits.
+func (bits Bits) String() string {
+	// Note: This method takes a value receiver, both for convenience
+	// and to make it safe to modify the bits as we process them.
+	// Even so, most prints above use &bits, because then the value
+	// being stored in the interface{} is a pointer and does not require
+	// an allocation and copy to create the interface{}.
+	var buf bytes.Buffer
+	sep := ""
+	for bany(&bits) {
+		i := bnum(bits)
+		buf.WriteString(sep)
+		sep = " "
+		v := &vars[i]
+		if v.node == nil || v.node.Sym == nil {
+			fmt.Fprintf(&buf, "$%d", i)
+		} else {
+			fmt.Fprintf(&buf, "%s(%d)", v.node.Sym.Name, i)
+			if v.offset != 0 {
+				fmt.Fprintf(&buf, "%+d", int64(v.offset))
+			}
+		}
+		biclr(&bits, uint(i))
+	}
+	return buf.String()
+}
diff --git a/src/cmd/internal/gc/select.go b/src/cmd/internal/gc/select.go
index ca6a21d..3a28ea3 100644
--- a/src/cmd/internal/gc/select.go
+++ b/src/cmd/internal/gc/select.go
@@ -11,7 +11,7 @@
 	var ncase *Node
 	var n *Node
 
-	def := (*Node)(nil)
+	var def *Node
 	lno := int(setlineno(sel))
 	count := 0
 	typechecklist(sel.Ninit, Etop)
@@ -45,7 +45,7 @@
 			// remove implicit conversions; the eventual assignment
 			// will reintroduce them.
 			case OAS:
-				if (n.Right.Op == OCONVNOP || n.Right.Op == OCONVIFACE) && n.Right.Implicit != 0 {
+				if (n.Right.Op == OCONVNOP || n.Right.Op == OCONVIFACE) && n.Right.Implicit {
 					n.Right = n.Right.Left
 				}
 
@@ -129,8 +129,7 @@
 			case OSEND:
 				ch = n.Left
 
-			case OSELRECV,
-				OSELRECV2:
+			case OSELRECV, OSELRECV2:
 				ch = n.Right.Left
 				if n.Op == OSELRECV || n.Ntest == nil {
 					if n.Left == nil {
@@ -185,8 +184,7 @@
 			n.Right = Nod(OADDR, n.Right, nil)
 			typecheck(&n.Right, Erv)
 
-		case OSELRECV,
-			OSELRECV2:
+		case OSELRECV, OSELRECV2:
 			if n.Op == OSELRECV2 && n.Ntest == nil {
 				n.Op = OSELRECV
 			}
@@ -324,7 +322,7 @@
 	lineno = int32(lno)
 }
 
-// Keep in sync with src/runtime/chan.h.
+// Keep in sync with src/runtime/runtime2.go and src/runtime/select.go.
 func selecttype(size int32) *Type {
 	// TODO(dvyukov): it's possible to generate SudoG and Scase only once
 	// and then cache; and also cache Select per size.
@@ -340,7 +338,7 @@
 	sudog.List = list(sudog.List, Nod(ODCLFIELD, newname(Lookup("waitlink")), typenod(Ptrto(Types[TUINT8]))))
 	typecheck(&sudog, Etype)
 	sudog.Type.Noalg = 1
-	sudog.Type.Local = 1
+	sudog.Type.Local = true
 
 	scase := Nod(OTSTRUCT, nil, nil)
 	scase.List = list(scase.List, Nod(ODCLFIELD, newname(Lookup("elem")), typenod(Ptrto(Types[TUINT8]))))
@@ -352,7 +350,7 @@
 	scase.List = list(scase.List, Nod(ODCLFIELD, newname(Lookup("releasetime")), typenod(Types[TUINT64])))
 	typecheck(&scase, Etype)
 	scase.Type.Noalg = 1
-	scase.Type.Local = 1
+	scase.Type.Local = true
 
 	sel := Nod(OTSTRUCT, nil, nil)
 	sel.List = list(sel.List, Nod(ODCLFIELD, newname(Lookup("tcase")), typenod(Types[TUINT16])))
@@ -367,7 +365,7 @@
 	sel.List = list(sel.List, Nod(ODCLFIELD, newname(Lookup("pollorderarr")), arr))
 	typecheck(&sel, Etype)
 	sel.Type.Noalg = 1
-	sel.Type.Local = 1
+	sel.Type.Local = true
 
 	return sel.Type
 }
diff --git a/src/cmd/internal/gc/sinit.go b/src/cmd/internal/gc/sinit.go
index ca8db418..f716736 100644
--- a/src/cmd/internal/gc/sinit.go
+++ b/src/cmd/internal/gc/sinit.go
@@ -42,8 +42,7 @@
 		return
 	}
 	switch n.Class {
-	case PEXTERN,
-		PFUNC:
+	case PEXTERN, PFUNC:
 		break
 
 	default:
@@ -172,10 +171,7 @@
 				*out = list(*out, n.Defn)
 			}
 
-		case OAS2FUNC,
-			OAS2MAPR,
-			OAS2DOTTYPE,
-			OAS2RECV:
+		case OAS2FUNC, OAS2MAPR, OAS2DOTTYPE, OAS2RECV:
 			if n.Defn.Initorder != InitNotStarted {
 				break
 			}
@@ -244,9 +240,7 @@
 	for ; l != nil; l = l.Next {
 		n = l.N
 		switch n.Op {
-		case ODCLFUNC,
-			ODCLCONST,
-			ODCLTYPE:
+		case ODCLFUNC, ODCLCONST, ODCLTYPE:
 			continue
 		}
 
@@ -260,7 +254,7 @@
 // declarations and outputs the corresponding list of statements
 // to include in the init() function body.
 func initfix(l *NodeList) *NodeList {
-	lout := (*NodeList)(nil)
+	var lout *NodeList
 	lno := int(lineno)
 	initreorder(l, &lout)
 	lineno = int32(lno)
@@ -285,7 +279,14 @@
 // like staticassign but we are copying an already
 // initialized value r.
 func staticcopy(l *Node, r *Node, out **NodeList) bool {
-	if r.Op != ONAME || r.Class != PEXTERN || r.Sym.Pkg != localpkg {
+	if r.Op != ONAME {
+		return false
+	}
+	if r.Class == PFUNC {
+		gdata(l, r, Widthptr)
+		return true
+	}
+	if r.Class != PEXTERN || r.Sym.Pkg != localpkg {
 		return false
 	}
 	if r.Defn == nil { // probably zeroed but perhaps supplied externally and of unknown value
@@ -326,9 +327,7 @@
 			break
 
 			// copy pointer
-		case OARRAYLIT,
-			OSTRUCTLIT,
-			OMAPLIT:
+		case OARRAYLIT, OSTRUCTLIT, OMAPLIT:
 			gdata(l, Nod(OADDR, r.Nname, nil), int(l.Type.Width))
 
 			return true
@@ -397,9 +396,7 @@
 		break
 
 	case ONAME:
-		if r.Class == PEXTERN && r.Sym.Pkg == localpkg {
-			return staticcopy(l, r, out)
-		}
+		return staticcopy(l, r, out)
 
 	case OLITERAL:
 		if iszero(r) {
@@ -425,9 +422,7 @@
 			break
 
 			// Init pointer.
-		case OARRAYLIT,
-			OMAPLIT,
-			OSTRUCTLIT:
+		case OARRAYLIT, OMAPLIT, OSTRUCTLIT:
 			a := staticname(r.Left.Type, 1)
 
 			r.Nname = a
@@ -443,7 +438,7 @@
 	case OSTRARRAYBYTE:
 		if l.Class == PEXTERN && r.Left.Op == OLITERAL {
 			sval := r.Left.Val.U.Sval
-			slicebytes(l, sval.S, len(sval.S))
+			slicebytes(l, sval, len(sval))
 			return true
 		}
 
@@ -512,11 +507,10 @@
  * part of the composite literal.
  */
 func staticname(t *Type, ctxt int) *Node {
-	namebuf = fmt.Sprintf("statictmp_%.4d", statuniqgen)
+	n := newname(Lookupf("statictmp_%.4d", statuniqgen))
 	statuniqgen++
-	n := newname(Lookup(namebuf))
 	if ctxt == 0 {
-		n.Readonly = 1
+		n.Readonly = true
 	}
 	addvar(n, t, PEXTERN)
 	return n
@@ -533,21 +527,18 @@
 
 func simplename(n *Node) bool {
 	if n.Op != ONAME {
-		goto no
+		return false
 	}
 	if n.Addable == 0 {
-		goto no
+		return false
 	}
 	if n.Class&PHEAP != 0 {
-		goto no
+		return false
 	}
 	if n.Class == PPARAMREF {
-		goto no
+		return false
 	}
 	return true
-
-no:
-	return false
 }
 
 func litas(l *Node, r *Node, init **NodeList) {
@@ -775,7 +766,7 @@
 
 	// if the literal contains constants,
 	// make static initialized array (1),(2)
-	vstat := (*Node)(nil)
+	var vstat *Node
 
 	mode := getdyn(n, 1)
 	if mode&MODECONST != 0 {
@@ -1014,9 +1005,9 @@
 	}
 
 	// put in dynamic entries one-at-a-time
-	key := (*Node)(nil)
+	var key *Node
 
-	val := (*Node)(nil)
+	var val *Node
 	for l := n.List; l != nil; l = l.Next {
 		r = l.N
 
@@ -1073,7 +1064,7 @@
 		Fatal("anylit: not lit")
 
 	case OPTRLIT:
-		if Isptr[t.Etype] == 0 {
+		if !Isptr[t.Etype] {
 			Fatal("anylit: not ptr")
 		}
 
@@ -1191,48 +1182,46 @@
 }
 
 func oaslit(n *Node, init **NodeList) bool {
-	var ctxt int
-
 	if n.Left == nil || n.Right == nil {
-		goto no
+		// not a special composit literal assignment
+		return false
 	}
 	if n.Left.Type == nil || n.Right.Type == nil {
-		goto no
+		// not a special composit literal assignment
+		return false
 	}
 	if !simplename(n.Left) {
-		goto no
+		// not a special composit literal assignment
+		return false
 	}
 	if !Eqtype(n.Left.Type, n.Right.Type) {
-		goto no
+		// not a special composit literal assignment
+		return false
 	}
 
 	// context is init() function.
 	// implies generated data executed
 	// exactly once and not subject to races.
-	ctxt = 0
+	ctxt := 0
 
 	//	if(n->dodata == 1)
 	//		ctxt = 1;
 
 	switch n.Right.Op {
 	default:
-		goto no
+		// not a special composit literal assignment
+		return false
 
-	case OSTRUCTLIT,
-		OARRAYLIT,
-		OMAPLIT:
+	case OSTRUCTLIT, OARRAYLIT, OMAPLIT:
 		if vmatch1(n.Left, n.Right) {
-			goto no
+			// not a special composit literal assignment
+			return false
 		}
 		anylit(ctxt, n.Right, n.Left, init)
 	}
 
 	n.Op = OEMPTY
 	return true
-
-	// not a special composit literal assignment
-no:
-	return false
 }
 
 func getlit(lit *Node) int {
@@ -1244,7 +1233,7 @@
 
 func stataddr(nam *Node, n *Node) bool {
 	if n == nil {
-		goto no
+		return false
 	}
 
 	switch n.Op {
@@ -1281,7 +1270,6 @@
 		return true
 	}
 
-no:
 	return false
 }
 
@@ -1372,13 +1360,12 @@
 			return true
 
 		case CTSTR:
-			return n.Val.U.Sval == nil || len(n.Val.U.Sval.S) == 0
+			return n.Val.U.Sval == ""
 
 		case CTBOOL:
 			return n.Val.U.Bval == 0
 
-		case CTINT,
-			CTRUNE:
+		case CTINT, CTRUNE:
 			return mpcmpfixc(n.Val.U.Xval, 0) == 0
 
 		case CTFLT:
@@ -1420,7 +1407,6 @@
 	var nr *Node
 	var nl *Node
 	var nam Node
-	var nod1 Node
 
 	if n.Dodata == 0 {
 		goto no
@@ -1436,7 +1422,7 @@
 		if nam.Class != PEXTERN {
 			goto no
 		}
-		goto yes
+		return true
 	}
 
 	if nr.Type == nil || !Eqtype(nl.Type, nr.Type) {
@@ -1466,7 +1452,33 @@
 	case OSLICEARR:
 		if nr.Right.Op == OKEY && nr.Right.Left == nil && nr.Right.Right == nil {
 			nr = nr.Left
-			goto slice
+			gused(nil) // in case the data is the dest of a goto
+			nl := nr
+			if nr == nil || nr.Op != OADDR {
+				goto no
+			}
+			nr = nr.Left
+			if nr == nil || nr.Op != ONAME {
+				goto no
+			}
+
+			// nr is the array being converted to a slice
+			if nr.Type == nil || nr.Type.Etype != TARRAY || nr.Type.Bound < 0 {
+				goto no
+			}
+
+			nam.Xoffset += int64(Array_array)
+			gdata(&nam, nl, int(Types[Tptr].Width))
+
+			nam.Xoffset += int64(Array_nel) - int64(Array_array)
+			var nod1 Node
+			Nodconst(&nod1, Types[TINT], nr.Type.Bound)
+			gdata(&nam, &nod1, Widthint)
+
+			nam.Xoffset += int64(Array_cap) - int64(Array_nel)
+			gdata(&nam, &nod1, Widthint)
+
+			return true
 		}
 
 		goto no
@@ -1497,45 +1509,15 @@
 		TFLOAT64:
 		gdata(&nam, nr, int(nr.Type.Width))
 
-	case TCOMPLEX64,
-		TCOMPLEX128:
+	case TCOMPLEX64, TCOMPLEX128:
 		gdatacomplex(&nam, nr.Val.U.Cval)
 
 	case TSTRING:
 		gdatastring(&nam, nr.Val.U.Sval)
 	}
 
-yes:
 	return true
 
-slice:
-	gused(nil) // in case the data is the dest of a goto
-	nl = nr
-	if nr == nil || nr.Op != OADDR {
-		goto no
-	}
-	nr = nr.Left
-	if nr == nil || nr.Op != ONAME {
-		goto no
-	}
-
-	// nr is the array being converted to a slice
-	if nr.Type == nil || nr.Type.Etype != TARRAY || nr.Type.Bound < 0 {
-		goto no
-	}
-
-	nam.Xoffset += int64(Array_array)
-	gdata(&nam, nl, int(Types[Tptr].Width))
-
-	nam.Xoffset += int64(Array_nel) - int64(Array_array)
-	Nodconst(&nod1, Types[TINT], nr.Type.Bound)
-	gdata(&nam, &nod1, Widthint)
-
-	nam.Xoffset += int64(Array_cap) - int64(Array_nel)
-	gdata(&nam, &nod1, Widthint)
-
-	goto yes
-
 no:
 	if n.Dodata == 2 {
 		Dump("\ngen_as_init", n)
diff --git a/src/cmd/internal/gc/subr.go b/src/cmd/internal/gc/subr.go
index 1c59e59..5508e07 100644
--- a/src/cmd/internal/gc/subr.go
+++ b/src/cmd/internal/gc/subr.go
@@ -7,6 +7,8 @@
 import (
 	"bytes"
 	"cmd/internal/obj"
+	"crypto/md5"
+	"encoding/binary"
 	"fmt"
 	"os"
 	"sort"
@@ -255,10 +257,7 @@
 	lno := lineno
 	if n != nil {
 		switch n.Op {
-		case ONAME,
-			OTYPE,
-			OPACK,
-			OLITERAL:
+		case ONAME, OTYPE, OPACK, OLITERAL:
 			break
 
 		default:
@@ -275,54 +274,57 @@
 	return lno
 }
 
-func stringhash(p string) uint32 {
-	var c int
-
-	h := uint32(0)
-	for {
-		c, p = intstarstringplusplus(p)
-		if c == 0 {
-			break
-		}
-		h = h*PRIME1 + uint32(c)
-	}
-
-	if int32(h) < 0 {
-		h = -h
-		if int32(h) < 0 {
-			h = 0
-		}
-	}
-
-	return h
+func Lookup(name string) *Sym {
+	return localpkg.Lookup(name)
 }
 
-func Lookup(name string) *Sym {
-	return Pkglookup(name, localpkg)
+func Lookupf(format string, a ...interface{}) *Sym {
+	return Lookup(fmt.Sprintf(format, a...))
+}
+
+func LookupBytes(name []byte) *Sym {
+	return localpkg.LookupBytes(name)
+}
+
+var initSyms []*Sym
+
+var nopkg = &Pkg{
+	Syms: make(map[string]*Sym),
+}
+
+func (pkg *Pkg) Lookup(name string) *Sym {
+	if pkg == nil {
+		pkg = nopkg
+	}
+	if s := pkg.Syms[name]; s != nil {
+		return s
+	}
+
+	s := &Sym{
+		Name:    name,
+		Pkg:     pkg,
+		Lexical: LNAME,
+	}
+	if name == "init" {
+		initSyms = append(initSyms, s)
+	}
+	pkg.Syms[name] = s
+	return s
+}
+
+func (pkg *Pkg) LookupBytes(name []byte) *Sym {
+	if pkg == nil {
+		pkg = nopkg
+	}
+	if s := pkg.Syms[string(name)]; s != nil {
+		return s
+	}
+	str := internString(name)
+	return pkg.Lookup(str)
 }
 
 func Pkglookup(name string, pkg *Pkg) *Sym {
-	h := stringhash(name) % NHASH
-	c := int(name[0])
-	for s := hash[h]; s != nil; s = s.Link {
-		if int(s.Name[0]) != c || s.Pkg != pkg {
-			continue
-		}
-		if s.Name == name {
-			return s
-		}
-	}
-
-	s := new(Sym)
-	s.Name = name
-
-	s.Pkg = pkg
-
-	s.Link = hash[h]
-	hash[h] = s
-	s.Lexical = LNAME
-
-	return s
+	return pkg.Lookup(name)
 }
 
 func restrictlookup(name string, pkg *Pkg) *Sym {
@@ -335,40 +337,34 @@
 // find all the exported symbols in package opkg
 // and make them available in the current package
 func importdot(opkg *Pkg, pack *Node) {
-	var s *Sym
 	var s1 *Sym
 	var pkgerror string
 
 	n := 0
-	for h := uint32(0); h < NHASH; h++ {
-		for s = hash[h]; s != nil; s = s.Link {
-			if s.Pkg != opkg {
-				continue
-			}
-			if s.Def == nil {
-				continue
-			}
-			if !exportname(s.Name) || strings.ContainsRune(s.Name, 0xb7) { // 0xb7 = center dot
-				continue
-			}
-			s1 = Lookup(s.Name)
-			if s1.Def != nil {
-				pkgerror = fmt.Sprintf("during import \"%v\"", Zconv(opkg.Path, 0))
-				redeclare(s1, pkgerror)
-				continue
-			}
-
-			s1.Def = s.Def
-			s1.Block = s.Block
-			s1.Def.Pack = pack
-			s1.Origpkg = opkg
-			n++
+	for _, s := range opkg.Syms {
+		if s.Def == nil {
+			continue
 		}
+		if !exportname(s.Name) || strings.ContainsRune(s.Name, 0xb7) { // 0xb7 = center dot
+			continue
+		}
+		s1 = Lookup(s.Name)
+		if s1.Def != nil {
+			pkgerror = fmt.Sprintf("during import %q", opkg.Path)
+			redeclare(s1, pkgerror)
+			continue
+		}
+
+		s1.Def = s.Def
+		s1.Block = s.Block
+		s1.Def.Pack = pack
+		s1.Origpkg = opkg
+		n++
 	}
 
 	if n == 0 {
 		// can't possibly be used - there were no symbols
-		yyerrorl(int(pack.Lineno), "imported and not used: \"%v\"", Zconv(opkg.Path, 0))
+		yyerrorl(int(pack.Lineno), "imported and not used: %q", opkg.Path)
 	}
 }
 
@@ -398,6 +394,10 @@
 	n.Xoffset = BADWIDTH
 	n.Orig = n
 	n.Curfn = Curfn
+	switch op {
+	case OCLOSURE, ODCLFUNC:
+		n.Func = new(Func)
+	}
 	return n
 }
 
@@ -436,8 +436,7 @@
 
 	switch t.Etype {
 	// will be defined later.
-	case TANY,
-		TFORW:
+	case TANY, TFORW:
 		*bad = t
 
 		return -1
@@ -460,8 +459,7 @@
 		TUNSAFEPTR:
 		return AMEM
 
-	case TFUNC,
-		TMAP:
+	case TFUNC, TMAP:
 		if bad != nil {
 			*bad = t
 		}
@@ -642,7 +640,7 @@
 		return k < 0
 	}
 	if !exportname(a.Sym.Name) {
-		k := stringsCompare(a.Sym.Pkg.Path.S, b.Sym.Pkg.Path.S)
+		k := stringsCompare(a.Sym.Pkg.Path, b.Sym.Pkg.Path)
 		if k != 0 {
 			return k < 0
 		}
@@ -714,7 +712,7 @@
 	n.Val.Ctype = CTINT
 	n.Type = t
 
-	if Isfloat[t.Etype] != 0 {
+	if Isfloat[t.Etype] {
 		Fatal("nodconst: bad type %v", Tconv(t, 0))
 	}
 }
@@ -742,8 +740,7 @@
 		default:
 			Yyerror("array bound must be an integer expression")
 
-		case CTINT,
-			CTRUNE:
+		case CTINT, CTRUNE:
 			bound = Mpgetfix(b.Val.U.Xval)
 			if bound < 0 {
 				Yyerror("array bound must be non negative")
@@ -792,9 +789,7 @@
 		fallthrough
 
 		// fall through
-	case ONAME,
-		OLITERAL,
-		OTYPE:
+	case ONAME, OLITERAL, OTYPE:
 		m = n
 	}
 
@@ -818,7 +813,7 @@
 	if t == nil {
 		return false
 	}
-	if Isptr[t.Etype] == 0 {
+	if !Isptr[t.Etype] {
 		return false
 	}
 	t = t.Type
@@ -876,8 +871,7 @@
 		return true
 	}
 	switch t.Etype {
-	case TNIL,
-		TIDEAL:
+	case TNIL, TIDEAL:
 		return true
 	}
 
@@ -894,7 +888,7 @@
 	}
 
 	// strip away pointer if it's there
-	if Isptr[t.Etype] != 0 {
+	if Isptr[t.Etype] {
 		if t.Sym != nil {
 			return nil
 		}
@@ -910,7 +904,7 @@
 	}
 
 	// check types
-	if issimple[t.Etype] == 0 {
+	if !issimple[t.Etype] {
 		switch t.Etype {
 		default:
 			return nil
@@ -941,8 +935,8 @@
 	return 0
 }
 
-func eqnote(a, b *Strlit) bool {
-	return a == b || a != nil && b != nil && a.S == b.S
+func eqnote(a, b *string) bool {
+	return a == b || a != nil && b != nil && *a == *b
 }
 
 type TypePairList struct {
@@ -986,8 +980,7 @@
 				return true
 			}
 
-		case TINT,
-			TINT32:
+		case TINT, TINT32:
 			if (t1 == Types[runetype.Etype] || t1 == runetype) && (t2 == Types[runetype.Etype] || t2 == runetype) {
 				return true
 			}
@@ -1005,78 +998,68 @@
 	l.t2 = t2
 
 	switch t1.Etype {
-	case TINTER,
-		TSTRUCT:
+	case TINTER, TSTRUCT:
 		t1 = t1.Type
 		t2 = t2.Type
-		for ; t1 != nil && t2 != nil; (func() { t1 = t1.Down; t2 = t2.Down })() {
+		for ; t1 != nil && t2 != nil; t1, t2 = t1.Down, t2.Down {
 			if t1.Etype != TFIELD || t2.Etype != TFIELD {
 				Fatal("struct/interface missing field: %v %v", Tconv(t1, 0), Tconv(t2, 0))
 			}
 			if t1.Sym != t2.Sym || t1.Embedded != t2.Embedded || !eqtype1(t1.Type, t2.Type, &l) || !eqnote(t1.Note, t2.Note) {
-				goto no
+				return false
 			}
 		}
 
 		if t1 == nil && t2 == nil {
-			goto yes
+			return true
 		}
-		goto no
+		return false
 
 		// Loop over structs: receiver, in, out.
 	case TFUNC:
 		t1 = t1.Type
 		t2 = t2.Type
-		for ; t1 != nil && t2 != nil; (func() { t1 = t1.Down; t2 = t2.Down })() {
-			var ta *Type
-			var tb *Type
-
+		for ; t1 != nil && t2 != nil; t1, t2 = t1.Down, t2.Down {
 			if t1.Etype != TSTRUCT || t2.Etype != TSTRUCT {
 				Fatal("func missing struct: %v %v", Tconv(t1, 0), Tconv(t2, 0))
 			}
 
 			// Loop over fields in structs, ignoring argument names.
-			ta = t1.Type
-			tb = t2.Type
-			for ; ta != nil && tb != nil; (func() { ta = ta.Down; tb = tb.Down })() {
+			ta := t1.Type
+			tb := t2.Type
+			for ; ta != nil && tb != nil; ta, tb = ta.Down, tb.Down {
 				if ta.Etype != TFIELD || tb.Etype != TFIELD {
 					Fatal("func struct missing field: %v %v", Tconv(ta, 0), Tconv(tb, 0))
 				}
 				if ta.Isddd != tb.Isddd || !eqtype1(ta.Type, tb.Type, &l) {
-					goto no
+					return false
 				}
 			}
 
 			if ta != nil || tb != nil {
-				goto no
+				return false
 			}
 		}
 
 		if t1 == nil && t2 == nil {
-			goto yes
+			return true
 		}
-		goto no
+		return false
 
 	case TARRAY:
 		if t1.Bound != t2.Bound {
-			goto no
+			return false
 		}
 
 	case TCHAN:
 		if t1.Chan != t2.Chan {
-			goto no
+			return false
 		}
 	}
 
 	if eqtype1(t1.Down, t2.Down, &l) && eqtype1(t1.Type, t2.Type, &l) {
-		goto yes
+		return true
 	}
-	goto no
-
-yes:
-	return true
-
-no:
 	return false
 }
 
@@ -1265,14 +1248,14 @@
 
 	// 3. src and dst are unnamed pointer types
 	// and their base types have identical underlying types.
-	if Isptr[src.Etype] != 0 && Isptr[dst.Etype] != 0 && src.Sym == nil && dst.Sym == nil {
+	if Isptr[src.Etype] && Isptr[dst.Etype] && src.Sym == nil && dst.Sym == nil {
 		if Eqtype(src.Type.Orig, dst.Type.Orig) {
 			return OCONVNOP
 		}
 	}
 
 	// 4. src and dst are both integer or floating point types.
-	if (Isint[src.Etype] != 0 || Isfloat[src.Etype] != 0) && (Isint[dst.Etype] != 0 || Isfloat[dst.Etype] != 0) {
+	if (Isint[src.Etype] || Isfloat[src.Etype]) && (Isint[dst.Etype] || Isfloat[dst.Etype]) {
 		if Simtype[src.Etype] == Simtype[dst.Etype] {
 			return OCONVNOP
 		}
@@ -1280,7 +1263,7 @@
 	}
 
 	// 5. src and dst are both complex types.
-	if Iscomplex[src.Etype] != 0 && Iscomplex[dst.Etype] != 0 {
+	if Iscomplex[src.Etype] && Iscomplex[dst.Etype] {
 		if Simtype[src.Etype] == Simtype[dst.Etype] {
 			return OCONVNOP
 		}
@@ -1289,7 +1272,7 @@
 
 	// 6. src is an integer or has type []byte or []rune
 	// and dst is a string type.
-	if Isint[src.Etype] != 0 && dst.Etype == TSTRING {
+	if Isint[src.Etype] && dst.Etype == TSTRING {
 		return ORUNESTR
 	}
 
@@ -1314,20 +1297,24 @@
 	}
 
 	// 8. src is a pointer or uintptr and dst is unsafe.Pointer.
-	if (Isptr[src.Etype] != 0 || src.Etype == TUINTPTR) && dst.Etype == TUNSAFEPTR {
+	if (Isptr[src.Etype] || src.Etype == TUINTPTR) && dst.Etype == TUNSAFEPTR {
 		return OCONVNOP
 	}
 
 	// 9. src is unsafe.Pointer and dst is a pointer or uintptr.
-	if src.Etype == TUNSAFEPTR && (Isptr[dst.Etype] != 0 || dst.Etype == TUINTPTR) {
+	if src.Etype == TUNSAFEPTR && (Isptr[dst.Etype] || dst.Etype == TUINTPTR) {
 		return OCONVNOP
 	}
 
 	return 0
 }
 
-// Convert node n for assignment to type t.
 func assignconv(n *Node, t *Type, context string) *Node {
+	return assignconvfn(n, t, func() string { return context })
+}
+
+// Convert node n for assignment to type t.
+func assignconvfn(n *Node, t *Type, context func() string) *Node {
 	if n == nil || n.Type == nil || n.Type.Broke != 0 {
 		return n
 	}
@@ -1351,7 +1338,7 @@
 			r := Nod(OCONVNOP, n, nil)
 			r.Type = Types[TBOOL]
 			r.Typecheck = 1
-			r.Implicit = 1
+			r.Implicit = true
 			n = r
 		}
 	}
@@ -1363,80 +1350,69 @@
 	var why string
 	op := assignop(n.Type, t, &why)
 	if op == 0 {
-		Yyerror("cannot use %v as type %v in %s%s", Nconv(n, obj.FmtLong), Tconv(t, 0), context, why)
+		Yyerror("cannot use %v as type %v in %s%s", Nconv(n, obj.FmtLong), Tconv(t, 0), context(), why)
 		op = OCONV
 	}
 
 	r := Nod(op, n, nil)
 	r.Type = t
 	r.Typecheck = 1
-	r.Implicit = 1
+	r.Implicit = true
 	r.Orig = n.Orig
 	return r
 }
 
-func subtype(stp **Type, t *Type, d int) bool {
-	var st *Type
-
-loop:
-	st = *stp
-	if st == nil {
-		return false
+// substArgTypes substitutes the given list of types for
+// successive occurrences of the "any" placeholder in the
+// type syntax expression n.Type.
+func substArgTypes(n *Node, types ...*Type) {
+	for _, t := range types {
+		dowidth(t)
 	}
-
-	d++
-	if d >= 10 {
-		return false
+	substAny(&n.Type, &types)
+	if len(types) > 0 {
+		Fatal("substArgTypes: too many argument types")
 	}
+}
 
-	switch st.Etype {
-	default:
-		return false
-
-	case TPTR32,
-		TPTR64,
-		TCHAN,
-		TARRAY:
-		stp = &st.Type
-		goto loop
-
-	case TANY:
-		if st.Copyany == 0 {
-			return false
+// substAny walks *tp, replacing instances of "any" with successive
+// elements removed from types.
+func substAny(tp **Type, types *[]*Type) {
+	for {
+		t := *tp
+		if t == nil {
+			return
 		}
-		*stp = t
-
-	case TMAP:
-		if subtype(&st.Down, t, d) {
-			break
-		}
-		stp = &st.Type
-		goto loop
-
-	case TFUNC:
-		for {
-			if subtype(&st.Type, t, d) {
-				break
+		if t.Etype == TANY && t.Copyany != 0 {
+			if len(*types) == 0 {
+				Fatal("substArgTypes: not enough argument types")
 			}
-			if subtype(&st.Type.Down.Down, t, d) {
-				break
-			}
-			if subtype(&st.Type.Down, t, d) {
-				break
-			}
-			return false
+			*tp = (*types)[0]
+			*types = (*types)[1:]
 		}
 
-	case TSTRUCT:
-		for st = st.Type; st != nil; st = st.Down {
-			if subtype(&st.Type, t, d) {
-				return true
+		switch t.Etype {
+		case TPTR32, TPTR64, TCHAN, TARRAY:
+			tp = &t.Type
+			continue
+
+		case TMAP:
+			substAny(&t.Down, types)
+			tp = &t.Type
+			continue
+
+		case TFUNC:
+			substAny(&t.Type, types)
+			substAny(&t.Type.Down.Down, types)
+			substAny(&t.Type.Down, types)
+
+		case TSTRUCT:
+			for t = t.Type; t != nil; t = t.Down {
+				substAny(&t.Type, types)
 			}
 		}
-		return false
+		return
 	}
-
-	return true
 }
 
 /*
@@ -1447,9 +1423,7 @@
 		return false
 	}
 	switch Simtype[t.Etype] {
-	case TINT64,
-		TUINT64,
-		TPTR64:
+	case TINT64, TUINT64, TPTR64:
 		return true
 	}
 
@@ -1464,22 +1438,16 @@
 	e2 := int(Simtype[t2.Etype])
 
 	switch e1 {
-	case TINT8,
-		TUINT8:
+	case TINT8, TUINT8:
 		return e2 == TINT8 || e2 == TUINT8
 
-	case TINT16,
-		TUINT16:
+	case TINT16, TUINT16:
 		return e2 == TINT16 || e2 == TUINT16
 
-	case TINT32,
-		TUINT32,
-		TPTR32:
+	case TINT32, TUINT32, TPTR32:
 		return e2 == TINT32 || e2 == TUINT32 || e2 == TPTR32
 
-	case TINT64,
-		TUINT64,
-		TPTR64:
+	case TINT64, TUINT64, TPTR64:
 		return e2 == TINT64 || e2 == TUINT64 || e2 == TPTR64
 
 	case TFLOAT32:
@@ -1492,13 +1460,6 @@
 	return false
 }
 
-func argtype(on *Node, t *Type) {
-	dowidth(t)
-	if !subtype(&on.Type, t, 0) {
-		Fatal("argtype: failed %v %v\n", Nconv(on, 0), Tconv(t, 0))
-	}
-}
-
 func shallow(t *Type) *Type {
 	if t == nil {
 		return nil
@@ -1525,10 +1486,7 @@
 		nt = shallow(t)
 		nt.Copyany = 1
 
-	case TPTR32,
-		TPTR64,
-		TCHAN,
-		TARRAY:
+	case TPTR32, TPTR64, TCHAN, TARRAY:
 		nt = shallow(t)
 		nt.Type = deep(t.Type)
 
@@ -1594,19 +1552,15 @@
 		// hide method receiver from Tpretty
 		t.Thistuple = 0
 
-		p = fmt.Sprintf("%v", Tconv(t, obj.FmtLeft|obj.FmtUnsigned))
+		p = Tconv(t, obj.FmtLeft|obj.FmtUnsigned)
 		t.Thistuple = 1
 	} else {
-		p = fmt.Sprintf("%v", Tconv(t, obj.FmtLeft|obj.FmtUnsigned))
+		p = Tconv(t, obj.FmtLeft|obj.FmtUnsigned)
 	}
 
 	//print("typehash: %s\n", p);
-	var d MD5
-	md5reset(&d)
-
-	md5write(&d, []byte(p), len(p))
-
-	return uint32(md5sum(&d, nil))
+	h := md5.Sum([]byte(p))
+	return binary.LittleEndian.Uint32(h[:4])
 }
 
 func Ptrto(t *Type) *Type {
@@ -1628,7 +1582,7 @@
 		l = externdcl
 	} else if Curfn != nil {
 		fmt.Printf("--- %v frame ---\n", Sconv(Curfn.Nname.Sym, 0))
-		l = Curfn.Dcl
+		l = Curfn.Func.Dcl
 	} else {
 		return
 	}
@@ -1670,25 +1624,19 @@
 	}
 
 	switch n.Op {
-	case OREGISTER,
-		OLITERAL,
-		ONAME:
+	case OREGISTER, OLITERAL, ONAME:
 		ul = 1
 		if n.Class == PPARAMREF || (n.Class&PHEAP != 0) {
 			ul++
 		}
 		goto out
 
-	case OCALL,
-		OCALLFUNC,
-		OCALLMETH,
-		OCALLINTER:
+	case OCALL, OCALLFUNC, OCALLMETH, OCALLINTER:
 		ul = UINF
 		goto out
 
 		// hard with race detector
-	case OANDAND,
-		OOROR:
+	case OANDAND, OOROR:
 		if flag_race != 0 {
 			ul = UINF
 			goto out
@@ -1727,7 +1675,7 @@
 	}
 
 	// common mistake: *struct and *interface.
-	if tl != nil && tr != nil && Isptr[tl.Etype] != 0 && Isptr[tr.Etype] != 0 {
+	if tl != nil && tr != nil && Isptr[tl.Etype] && Isptr[tr.Etype] {
 		if tl.Type.Etype == TSTRUCT && tr.Type.Etype == TINTER {
 			fmt_ += "\n\t(*struct vs *interface)"
 		} else if tl.Type.Etype == TINTER && tr.Type.Etype == TSTRUCT {
@@ -1754,15 +1702,13 @@
 	default:
 		goto bad
 
-	case TSTRUCT,
-		TINTER,
-		TFUNC:
+	case TSTRUCT, TINTER, TFUNC:
 		break
 	}
 
 	t = n.Type
 	if t == nil {
-		goto rnil
+		return nil
 	}
 
 	if t.Etype != TFIELD {
@@ -1775,7 +1721,6 @@
 bad:
 	Fatal("structfirst: not struct %v", Tconv(n, 0))
 
-rnil:
 	return nil
 }
 
@@ -1783,21 +1728,17 @@
 	n := s.T
 	t := n.Down
 	if t == nil {
-		goto rnil
+		return nil
 	}
 
 	if t.Etype != TFIELD {
-		goto bad
+		Fatal("structnext: not struct %v", Tconv(n, 0))
+
+		return nil
 	}
 
 	s.T = t
 	return t
-
-bad:
-	Fatal("structnext: not struct %v", Tconv(n, 0))
-
-rnil:
-	return nil
 }
 
 /*
@@ -1936,8 +1877,7 @@
 	}
 
 	switch n.Op {
-	case ONAME,
-		OLITERAL:
+	case ONAME, OLITERAL:
 		return n
 
 	case ODOT:
@@ -1952,8 +1892,7 @@
 		walkexpr(&r, init)
 		return r
 
-	case ODOTPTR,
-		OIND:
+	case ODOTPTR, OIND:
 		l := safeexpr(n.Left, init)
 		if l == n.Left {
 			return n
@@ -1964,8 +1903,7 @@
 		walkexpr(&a, init)
 		return a
 
-	case OINDEX,
-		OINDEXMAP:
+	case OINDEX, OINDEXMAP:
 		l := safeexpr(n.Left, init)
 		r := safeexpr(n.Right, init)
 		if l == n.Left && r == n.Right {
@@ -2001,8 +1939,7 @@
  */
 func cheapexpr(n *Node, init **NodeList) *Node {
 	switch n.Op {
-	case ONAME,
-		OLITERAL:
+	case ONAME, OLITERAL:
 		return n
 	}
 
@@ -2015,7 +1952,7 @@
  * assignment to it.
  */
 func localexpr(n *Node, t *Type, init **NodeList) *Node {
-	if n.Op == ONAME && (n.Addrtaken == 0 || strings.HasPrefix(n.Sym.Name, "autotmp_")) && (n.Class == PAUTO || n.Class == PPARAM || n.Class == PPARAMOUT) && convertop(n.Type, t, nil) == OCONVNOP {
+	if n.Op == ONAME && (!n.Addrtaken || strings.HasPrefix(n.Sym.Name, "autotmp_")) && (n.Class == PAUTO || n.Class == PPARAM || n.Class == PPARAMOUT) && convertop(n.Type, t, nil) == OCONVNOP {
 		return n
 	}
 
@@ -2051,7 +1988,7 @@
 // found with a given name
 func lookdot0(s *Sym, t *Type, save **Type, ignorecase int) int {
 	u := t
-	if Isptr[u.Etype] != 0 {
+	if Isptr[u.Etype] {
 		u = u.Type
 	}
 
@@ -2103,7 +2040,7 @@
 
 	c = 0
 	u = t
-	if Isptr[u.Etype] != 0 {
+	if Isptr[u.Etype] {
 		u = u.Type
 	}
 	if u.Etype != TSTRUCT && u.Etype != TINTER {
@@ -2135,54 +2072,47 @@
 // will give shortest unique addressing.
 // modify the tree with missing type names.
 func adddot(n *Node) *Node {
-	var s *Sym
-	var c int
-	var d int
-
 	typecheck(&n.Left, Etype|Erv)
 	n.Diag |= n.Left.Diag
 	t := n.Left.Type
 	if t == nil {
-		goto ret
-	}
-
-	if n.Left.Op == OTYPE {
-		goto ret
-	}
-
-	if n.Right.Op != ONAME {
-		goto ret
-	}
-	s = n.Right.Sym
-	if s == nil {
-		goto ret
-	}
-
-	for d = 0; d < len(dotlist); d++ {
-		c = adddot1(s, t, d, nil, 0)
-		if c > 0 {
-			goto out
-		}
-	}
-
-	goto ret
-
-out:
-	if c > 1 {
-		Yyerror("ambiguous selector %v", Nconv(n, 0))
-		n.Left = nil
 		return n
 	}
 
-	// rebuild elided dots
-	for c := d - 1; c >= 0; c-- {
-		if n.Left.Type != nil && Isptr[n.Left.Type.Etype] != 0 {
-			n.Left.Implicit = 1
-		}
-		n.Left = Nod(ODOT, n.Left, newname(dotlist[c].field.Sym))
+	if n.Left.Op == OTYPE {
+		return n
 	}
 
-ret:
+	if n.Right.Op != ONAME {
+		return n
+	}
+	s := n.Right.Sym
+	if s == nil {
+		return n
+	}
+
+	var c int
+	for d := 0; d < len(dotlist); d++ {
+		c = adddot1(s, t, d, nil, 0)
+		if c > 0 {
+			if c > 1 {
+				Yyerror("ambiguous selector %v", Nconv(n, 0))
+				n.Left = nil
+				return n
+			}
+
+			// rebuild elided dots
+			for c := d - 1; c >= 0; c-- {
+				if n.Left.Type != nil && Isptr[n.Left.Type.Etype] {
+					n.Left.Implicit = true
+				}
+				n.Left = Nod(ODOT, n.Left, newname(dotlist[c].field.Sym))
+			}
+
+			return n
+		}
+	}
+
 	return n
 }
 
@@ -2207,7 +2137,7 @@
 
 func expand0(t *Type, followptr int) {
 	u := t
-	if Isptr[u.Etype] != 0 {
+	if Isptr[u.Etype] {
 		followptr = 1
 		u = u.Type
 	}
@@ -2260,7 +2190,7 @@
 	}
 
 	u := t
-	if Isptr[u.Etype] != 0 {
+	if Isptr[u.Etype] {
 		followptr = 1
 		u = u.Type
 	}
@@ -2352,7 +2282,7 @@
 	var n *Node
 	var buf string
 
-	args := (*NodeList)(nil)
+	var args *NodeList
 	gen := 0
 	for t := Structfirst(&savet, tl); t != nil; t = structnext(&savet) {
 		n = nil
@@ -2451,18 +2381,18 @@
 	funchdr(fn)
 
 	// arg list
-	args := (*NodeList)(nil)
+	var args *NodeList
 
-	isddd := 0
+	isddd := false
 	for l := in; l != nil; l = l.Next {
 		args = list(args, l.N.Left)
-		isddd = int(l.N.Left.Isddd)
+		isddd = l.N.Left.Isddd
 	}
 
 	methodrcvr := getthisx(method.Type).Type.Type
 
 	// generate nil pointer check for better error
-	if Isptr[rcvr.Etype] != 0 && rcvr.Type == methodrcvr {
+	if Isptr[rcvr.Etype] && rcvr.Type == methodrcvr {
 		// generating wrapper from *T to T.
 		n := Nod(OIF, nil, nil)
 
@@ -2470,15 +2400,15 @@
 
 		// these strings are already in the reflect tables,
 		// so no space cost to use them here.
-		l := (*NodeList)(nil)
+		var l *NodeList
 
 		var v Val
 		v.Ctype = CTSTR
-		v.U.Sval = newstrlit(rcvr.Type.Sym.Pkg.Name) // package name
+		v.U.Sval = rcvr.Type.Sym.Pkg.Name // package name
 		l = list(l, nodlit(v))
-		v.U.Sval = newstrlit(rcvr.Type.Sym.Name) // type name
+		v.U.Sval = rcvr.Type.Sym.Name // type name
 		l = list(l, nodlit(v))
-		v.U.Sval = newstrlit(method.Sym.Name)
+		v.U.Sval = method.Sym.Name
 		l = list(l, nodlit(v)) // method name
 		call := Nod(OCALL, syslook("panicwrap", 0), nil)
 		call.List = l
@@ -2489,10 +2419,10 @@
 	dot := adddot(Nod(OXDOT, this.Left, newname(method.Sym)))
 
 	// generate call
-	if flag_race == 0 && Isptr[rcvr.Etype] != 0 && Isptr[methodrcvr.Etype] != 0 && method.Embedded != 0 && !isifacemethod(method.Type) {
+	if flag_race == 0 && Isptr[rcvr.Etype] && Isptr[methodrcvr.Etype] && method.Embedded != 0 && !isifacemethod(method.Type) {
 		// generate tail call: adjust pointer receiver and jump to embedded method.
 		dot = dot.Left // skip final .M
-		if Isptr[dotlist[0].field.Type.Etype] == 0 {
+		if !Isptr[dotlist[0].field.Type.Etype] {
 			dot = Nod(OADDR, dot, nil)
 		}
 		as := Nod(OAS, this.Left, Nod(OCONVNOP, dot, nil))
@@ -2502,10 +2432,10 @@
 		n.Left = newname(methodsym(method.Sym, methodrcvr, 0))
 		fn.Nbody = list(fn.Nbody, n)
 	} else {
-		fn.Wrapper = 1 // ignore frame for panic+recover matching
+		fn.Func.Wrapper = true // ignore frame for panic+recover matching
 		call := Nod(OCALL, dot, nil)
 		call.List = args
-		call.Isddd = uint8(isddd)
+		call.Isddd = isddd
 		if method.Type.Outtuple > 0 {
 			n := Nod(ORETURN, nil, nil)
 			n.List = list1(call)
@@ -2523,15 +2453,15 @@
 	Curfn = fn
 
 	// wrappers where T is anonymous (struct or interface) can be duplicated.
-	if rcvr.Etype == TSTRUCT || rcvr.Etype == TINTER || Isptr[rcvr.Etype] != 0 && rcvr.Type.Etype == TSTRUCT {
-		fn.Dupok = 1
+	if rcvr.Etype == TSTRUCT || rcvr.Etype == TINTER || Isptr[rcvr.Etype] && rcvr.Type.Etype == TSTRUCT {
+		fn.Func.Dupok = true
 	}
 	typecheck(&fn, Etop)
 	typechecklist(fn.Nbody, Etop)
 
 	// Set inl_nonlocal to whether we are calling a method on a
 	// type defined in a different package.  Checked in inlvar.
-	if methodrcvr.Local == 0 {
+	if !methodrcvr.Local {
 		inl_nonlocal = 1
 	}
 
@@ -2690,7 +2620,7 @@
 		// Walk the struct using memhash for runs of AMEM
 	// and calling specific hash functions for the others.
 	case TSTRUCT:
-		first := (*Type)(nil)
+		var first *Type
 
 		offend := int64(0)
 		var size int64
@@ -2779,7 +2709,7 @@
 
 	funcbody(fn)
 	Curfn = fn
-	fn.Dupok = 1
+	fn.Func.Dupok = true
 	typecheck(&fn, Etop)
 	typechecklist(fn.Nbody, Etop)
 	Curfn = nil
@@ -2817,18 +2747,13 @@
 		fn = syslook("memequal", 1)
 		*needsize = 1
 
-	case 1,
-		2,
-		4,
-		8,
-		16:
+	case 1, 2, 4, 8, 16:
 		buf := fmt.Sprintf("memequal%d", int(size)*8)
 		fn = syslook(buf, 1)
 		*needsize = 0
 	}
 
-	argtype(fn, type_)
-	argtype(fn, type_)
+	substArgTypes(fn, type_, type_)
 	return fn
 }
 
@@ -2935,7 +2860,7 @@
 	// and calling specific equality tests for the others.
 	// Skip blank-named fields.
 	case TSTRUCT:
-		first := (*Type)(nil)
+		var first *Type
 
 		offend := int64(0)
 		var size int64
@@ -2999,7 +2924,7 @@
 
 	funcbody(fn)
 	Curfn = fn
-	fn.Dupok = 1
+	fn.Func.Dupok = true
 	typecheck(&fn, Etop)
 	typechecklist(fn.Nbody, Etop)
 	Curfn = nil
@@ -3035,7 +2960,7 @@
 
 		if c == 1 {
 			for i = 0; i < d; i++ {
-				if Isptr[dotlist[i].field.Type.Etype] != 0 {
+				if Isptr[dotlist[i].field.Type.Etype] {
 					*followptr = 1
 					break
 				}
@@ -3113,7 +3038,7 @@
 		// the method does not exist for value types.
 		rcvr = getthisx(tm.Type).Type.Type
 
-		if Isptr[rcvr.Etype] != 0 && Isptr[t0.Etype] == 0 && followptr == 0 && !isifacemethod(tm.Type) {
+		if Isptr[rcvr.Etype] && !Isptr[t0.Etype] && followptr == 0 && !isifacemethod(tm.Type) {
 			if false && Debug['r'] != 0 {
 				Yyerror("interface pointer mismatch")
 			}
@@ -3153,105 +3078,8 @@
 	return et
 }
 
-func concat(a *NodeList, b *NodeList) *NodeList {
-	if a == nil {
-		return b
-	}
-	if b == nil {
-		return a
-	}
-
-	a.End.Next = b
-	a.End = b.End
-	b.End = nil
-	return a
-}
-
-func list1(n *Node) *NodeList {
-	if n == nil {
-		return nil
-	}
-	if n.Op == OBLOCK && n.Ninit == nil {
-		// Flatten list and steal storage.
-		// Poison pointer to catch errant uses.
-		l := n.List
-
-		n.List = nil
-		return l
-	}
-
-	l := new(NodeList)
-	l.N = n
-	l.End = l
-	return l
-}
-
-func list(l *NodeList, n *Node) *NodeList {
-	return concat(l, list1(n))
-}
-
-func listsort(l **NodeList, f func(*Node, *Node) int) {
-	if *l == nil || (*l).Next == nil {
-		return
-	}
-
-	l1 := *l
-	l2 := *l
-	for {
-		l2 = l2.Next
-		if l2 == nil {
-			break
-		}
-		l2 = l2.Next
-		if l2 == nil {
-			break
-		}
-		l1 = l1.Next
-	}
-
-	l2 = l1.Next
-	l1.Next = nil
-	l2.End = (*l).End
-	(*l).End = l1
-
-	l1 = *l
-	listsort(&l1, f)
-	listsort(&l2, f)
-
-	if f(l1.N, l2.N) < 0 {
-		*l = l1
-	} else {
-		*l = l2
-		l2 = l1
-		l1 = *l
-	}
-
-	// now l1 == *l; and l1 < l2
-
-	var le *NodeList
-	for (l1 != nil) && (l2 != nil) {
-		for (l1.Next != nil) && f(l1.Next.N, l2.N) < 0 {
-			l1 = l1.Next
-		}
-
-		// l1 is last one from l1 that is < l2
-		le = l1.Next // le is the rest of l1, first one that is >= l2
-		if le != nil {
-			le.End = (*l).End
-		}
-
-		(*l).End = l1       // cut *l at l1
-		*l = concat(*l, l2) // glue l2 to *l's tail
-
-		l1 = l2 // l1 is the first element of *l that is < the new l2
-		l2 = le // ... because l2 now is the old tail of l1
-	}
-
-	*l = concat(*l, l2) // any remainder
-}
-
 func listtreecopy(l *NodeList) *NodeList {
-	out := (*NodeList)(nil)
+	var out *NodeList
 	for ; l != nil; l = l.Next {
 		out = list(out, treecopy(l.N))
 	}
@@ -3270,21 +3098,6 @@
 /*
  * return nelem of list
  */
-func count(l *NodeList) int {
-	n := int64(0)
-	for ; l != nil; l = l.Next {
-		n++
-	}
-	if int64(int(n)) != n { // Overflow.
-		Yyerror("too many elements in list")
-	}
-
-	return int(n)
-}
-
-/*
- * return nelem of list
- */
 func structcount(t *Type) int {
 	var s Iter
 
@@ -3301,18 +3114,15 @@
  * 1000+ if it is a -(power of 2)
  */
 func powtwo(n *Node) int {
-	var v uint64
-	var b uint64
-
 	if n == nil || n.Op != OLITERAL || n.Type == nil {
-		goto no
+		return -1
 	}
-	if Isint[n.Type.Etype] == 0 {
-		goto no
+	if !Isint[n.Type.Etype] {
+		return -1
 	}
 
-	v = uint64(Mpgetfix(n.Val.U.Xval))
-	b = 1
+	v := uint64(Mpgetfix(n.Val.U.Xval))
+	b := uint64(1)
 	for i := 0; i < 64; i++ {
 		if b == v {
 			return i
@@ -3320,8 +3130,8 @@
 		b = b << 1
 	}
 
-	if Issigned[n.Type.Etype] == 0 {
-		goto no
+	if !Issigned[n.Type.Etype] {
+		return -1
 	}
 
 	v = -v
@@ -3333,7 +3143,6 @@
 		b = b << 1
 	}
 
-no:
 	return -1
 }
 
@@ -3592,46 +3401,38 @@
 	for i := 0; i < len(s); i++ {
 		c := s[i]
 		if c <= ' ' || i >= slash && c == '.' || c == '%' || c == '"' || c >= 0x7F {
-			goto escape
+			var buf bytes.Buffer
+			for i := 0; i < len(s); i++ {
+				c := s[i]
+				if c <= ' ' || i >= slash && c == '.' || c == '%' || c == '"' || c >= 0x7F {
+					fmt.Fprintf(&buf, "%%%02x", c)
+					continue
+				}
+				buf.WriteByte(c)
+			}
+			return buf.String()
 		}
 	}
 	return s
-
-escape:
-	var buf bytes.Buffer
-	for i := 0; i < len(s); i++ {
-		c := s[i]
-		if c <= ' ' || i >= slash && c == '.' || c == '%' || c == '"' || c >= 0x7F {
-			fmt.Fprintf(&buf, "%%%02x", c)
-			continue
-		}
-		buf.WriteByte(c)
-	}
-	return buf.String()
 }
 
-func mkpkg(path_ *Strlit) *Pkg {
-	h := int(stringhash(path_.S) & uint32(len(phash)-1))
-	for p := phash[h]; p != nil; p = p.Link {
-		if p.Path.S == path_.S {
-			return p
-		}
+var pkgMap = make(map[string]*Pkg)
+var pkgs []*Pkg
+
+func mkpkg(path string) *Pkg {
+	if p := pkgMap[path]; p != nil {
+		return p
 	}
 
 	p := new(Pkg)
-	p.Path = path_
-	p.Prefix = pathtoprefix(path_.S)
-	p.Link = phash[h]
-	phash[h] = p
+	p.Path = path
+	p.Prefix = pathtoprefix(path)
+	p.Syms = make(map[string]*Sym)
+	pkgMap[path] = p
+	pkgs = append(pkgs, p)
 	return p
 }
 
-func newstrlit(s string) *Strlit {
-	return &Strlit{
-		S: s,
-	}
-}
-
 func addinit(np **Node, init *NodeList) {
 	if init == nil {
 		return
@@ -3641,8 +3442,7 @@
 	switch n.Op {
 	// There may be multiple refs to this node;
 	// introduce OCONVNOP to hold init list.
-	case ONAME,
-		OLITERAL:
+	case ONAME, OLITERAL:
 		n = Nod(OCONVNOP, n, nil)
 
 		n.Type = n.Left.Type
@@ -3659,15 +3459,15 @@
 	"type",
 }
 
-func isbadimport(path_ *Strlit) bool {
-	if len(path_.S) != len(path_.S) {
+func isbadimport(path string) bool {
+	if strings.Contains(path, "\x00") {
 		Yyerror("import path contains NUL")
 		return true
 	}
 
 	for i := 0; i < len(reservedimports); i++ {
-		if path_.S == reservedimports[i] {
-			Yyerror("import path \"%s\" is reserved and cannot be used", path_.S)
+		if path == reservedimports[i] {
+			Yyerror("import path %q is reserved and cannot be used", path)
 			return true
 		}
 	}
@@ -3676,29 +3476,29 @@
 	_ = s
 	var r uint
 	_ = r
-	for _, r := range path_.S {
+	for _, r := range path {
 		if r == utf8.RuneError {
-			Yyerror("import path contains invalid UTF-8 sequence: \"%v\"", Zconv(path_, 0))
+			Yyerror("import path contains invalid UTF-8 sequence: %q", path)
 			return true
 		}
 
 		if r < 0x20 || r == 0x7f {
-			Yyerror("import path contains control character: \"%v\"", Zconv(path_, 0))
+			Yyerror("import path contains control character: %q", path)
 			return true
 		}
 
 		if r == '\\' {
-			Yyerror("import path contains backslash; use slash: \"%v\"", Zconv(path_, 0))
+			Yyerror("import path contains backslash; use slash: %q", path)
 			return true
 		}
 
 		if unicode.IsSpace(rune(r)) {
-			Yyerror("import path contains space character: \"%v\"", Zconv(path_, 0))
+			Yyerror("import path contains space character: %q", path)
 			return true
 		}
 
 		if strings.ContainsRune("!\"#$%&'()*,:;<=>?[]^`{|}", r) {
-			Yyerror("import path contains invalid character '%c': \"%v\"", r, Zconv(path_, 0))
+			Yyerror("import path contains invalid character '%c': %q", r, path)
 			return true
 		}
 	}
@@ -3742,3 +3542,16 @@
 
 	return false
 }
+
+// type2IET returns "T" if t is a concrete type,
+// "I" if t is an interface type, and "E" if t is an empty interface type.
+// It is used to build calls to the conv* and assert* runtime routines.
+func type2IET(t *Type) string {
+	if isnilinter(t) {
+		return "E"
+	}
+	if Isinter(t) {
+		return "I"
+	}
+	return "T"
+}
diff --git a/src/cmd/internal/gc/swt.go b/src/cmd/internal/gc/swt.go
index 81eb56c..991f3ac 100644
--- a/src/cmd/internal/gc/swt.go
+++ b/src/cmd/internal/gc/swt.go
@@ -7,257 +7,332 @@
 import (
 	"cmd/internal/obj"
 	"fmt"
+	"sort"
+	"strconv"
 )
 
 const (
-	Snorm = 0 + iota
-	Strue
-	Sfalse
-	Stype
-	Tdefault
-	Texprconst
-	Texprvar
-	Ttypenil
-	Ttypeconst
-	Ttypevar
-	Ncase = 4
+	// expression switch
+	switchKindExpr  = iota // switch a {...} or switch 5 {...}
+	switchKindTrue         // switch true {...} or switch {...}
+	switchKindFalse        // switch false {...}
+
+	// type switch
+	switchKindType // switch a.(type) {...}
 )
 
-type Case struct {
-	node    *Node
-	hash    uint32
-	type_   uint8
-	diag    uint8
-	ordinal uint16
-	link    *Case
+const (
+	caseKindDefault = iota // default:
+
+	// expression switch
+	caseKindExprConst // case 5:
+	caseKindExprVar   // case x:
+
+	// type switch
+	caseKindTypeNil   // case nil:
+	caseKindTypeConst // case time.Time: (concrete type, has type hash)
+	caseKindTypeVar   // case io.Reader: (interface type)
+)
+
+const binarySearchMin = 4 // minimum number of cases for binary search
+
+// An exprSwitch walks an expression switch.
+type exprSwitch struct {
+	exprname *Node // node for the expression being switched on
+	kind     int   // kind of switch statement (switchKind*)
 }
 
-var C *Case
+// A typeSwitch walks a type switch.
+type typeSwitch struct {
+	hashname *Node // node for the hash of the type of the variable being switched on
+	facename *Node // node for the concrete type of the variable being switched on
+	okname   *Node // boolean node used for comma-ok type assertions
+}
 
-func dumpcase(c0 *Case) {
-	for c := c0; c != nil; c = c.link {
-		switch c.type_ {
-		case Tdefault:
-			fmt.Printf("case-default\n")
-			fmt.Printf("\tord=%d\n", c.ordinal)
+// A caseClause is a single case clause in a switch statement.
+type caseClause struct {
+	node    *Node  // points at case statement
+	ordinal int    // position in switch
+	hash    uint32 // hash of a type switch
+	typ     uint8  // type of case
+}
 
-		case Texprconst:
-			fmt.Printf("case-exprconst\n")
-			fmt.Printf("\tord=%d\n", c.ordinal)
+// typecheckswitch typechecks a switch statement.
+func typecheckswitch(n *Node) {
+	lno := int(lineno)
+	typechecklist(n.Ninit, Etop)
 
-		case Texprvar:
-			fmt.Printf("case-exprvar\n")
-			fmt.Printf("\tord=%d\n", c.ordinal)
-			fmt.Printf("\top=%v\n", Oconv(int(c.node.Left.Op), 0))
+	var nilonly string
+	var top int
+	var t *Type
 
-		case Ttypenil:
-			fmt.Printf("case-typenil\n")
-			fmt.Printf("\tord=%d\n", c.ordinal)
-
-		case Ttypeconst:
-			fmt.Printf("case-typeconst\n")
-			fmt.Printf("\tord=%d\n", c.ordinal)
-			fmt.Printf("\thash=%x\n", c.hash)
-
-		case Ttypevar:
-			fmt.Printf("case-typevar\n")
-			fmt.Printf("\tord=%d\n", c.ordinal)
-
-		default:
-			fmt.Printf("case-???\n")
-			fmt.Printf("\tord=%d\n", c.ordinal)
-			fmt.Printf("\top=%v\n", Oconv(int(c.node.Left.Op), 0))
-			fmt.Printf("\thash=%x\n", c.hash)
+	if n.Ntest != nil && n.Ntest.Op == OTYPESW {
+		// type switch
+		top = Etype
+		typecheck(&n.Ntest.Right, Erv)
+		t = n.Ntest.Right.Type
+		if t != nil && t.Etype != TINTER {
+			Yyerror("cannot type switch on non-interface value %v", Nconv(n.Ntest.Right, obj.FmtLong))
 		}
-	}
-
-	fmt.Printf("\n")
-}
-
-func ordlcmp(c1 *Case, c2 *Case) int {
-	// sort default first
-	if c1.type_ == Tdefault {
-		return -1
-	}
-	if c2.type_ == Tdefault {
-		return +1
-	}
-
-	// sort nil second
-	if c1.type_ == Ttypenil {
-		return -1
-	}
-	if c2.type_ == Ttypenil {
-		return +1
-	}
-
-	// sort by ordinal
-	if c1.ordinal > c2.ordinal {
-		return +1
-	}
-	if c1.ordinal < c2.ordinal {
-		return -1
-	}
-	return 0
-}
-
-func exprcmp(c1 *Case, c2 *Case) int {
-	// sort non-constants last
-	if c1.type_ != Texprconst {
-		return +1
-	}
-	if c2.type_ != Texprconst {
-		return -1
-	}
-
-	n1 := c1.node.Left
-	n2 := c2.node.Left
-
-	// sort by type (for switches on interface)
-	ct := int(n1.Val.Ctype)
-
-	if ct != int(n2.Val.Ctype) {
-		return ct - int(n2.Val.Ctype)
-	}
-	if !Eqtype(n1.Type, n2.Type) {
-		if n1.Type.Vargen > n2.Type.Vargen {
-			return +1
-		} else {
-			return -1
-		}
-	}
-
-	// sort by constant value
-	n := 0
-
-	switch ct {
-	case CTFLT:
-		n = mpcmpfltflt(n1.Val.U.Fval, n2.Val.U.Fval)
-
-	case CTINT,
-		CTRUNE:
-		n = Mpcmpfixfix(n1.Val.U.Xval, n2.Val.U.Xval)
-
-	case CTSTR:
-		n = cmpslit(n1, n2)
-	}
-
-	return n
-}
-
-func typecmp(c1 *Case, c2 *Case) int {
-	// sort non-constants last
-	if c1.type_ != Ttypeconst {
-		return +1
-	}
-	if c2.type_ != Ttypeconst {
-		return -1
-	}
-
-	// sort by hash code
-	if c1.hash > c2.hash {
-		return +1
-	}
-	if c1.hash < c2.hash {
-		return -1
-	}
-
-	// sort by ordinal so duplicate error
-	// happens on later case.
-	if c1.ordinal > c2.ordinal {
-		return +1
-	}
-	if c1.ordinal < c2.ordinal {
-		return -1
-	}
-	return 0
-}
-
-func csort(l *Case, f func(*Case, *Case) int) *Case {
-	if l == nil || l.link == nil {
-		return l
-	}
-
-	l1 := l
-	l2 := l
-	for {
-		l2 = l2.link
-		if l2 == nil {
-			break
-		}
-		l2 = l2.link
-		if l2 == nil {
-			break
-		}
-		l1 = l1.link
-	}
-
-	l2 = l1.link
-	l1.link = nil
-	l1 = csort(l, f)
-	l2 = csort(l2, f)
-
-	/* set up lead element */
-	if f(l1, l2) < 0 {
-		l = l1
-		l1 = l1.link
 	} else {
-		l = l2
-		l2 = l2.link
-	}
-
-	le := l
-
-	for {
-		if l1 == nil {
-			for l2 != nil {
-				le.link = l2
-				le = l2
-				l2 = l2.link
-			}
-
-			le.link = nil
-			break
-		}
-
-		if l2 == nil {
-			for l1 != nil {
-				le.link = l1
-				le = l1
-				l1 = l1.link
-			}
-
-			break
-		}
-
-		if f(l1, l2) < 0 {
-			le.link = l1
-			le = l1
-			l1 = l1.link
+		// expression switch
+		top = Erv
+		if n.Ntest != nil {
+			typecheck(&n.Ntest, Erv)
+			defaultlit(&n.Ntest, nil)
+			t = n.Ntest.Type
 		} else {
-			le.link = l2
-			le = l2
-			l2 = l2.link
+			t = Types[TBOOL]
+		}
+		if t != nil {
+			var badtype *Type
+			switch {
+			case !okforeq[t.Etype]:
+				Yyerror("cannot switch on %v", Nconv(n.Ntest, obj.FmtLong))
+			case t.Etype == TARRAY && !Isfixedarray(t):
+				nilonly = "slice"
+			case t.Etype == TARRAY && Isfixedarray(t) && algtype1(t, nil) == ANOEQ:
+				Yyerror("cannot switch on %v", Nconv(n.Ntest, obj.FmtLong))
+			case t.Etype == TSTRUCT && algtype1(t, &badtype) == ANOEQ:
+				Yyerror("cannot switch on %v (struct containing %v cannot be compared)", Nconv(n.Ntest, obj.FmtLong), Tconv(badtype, 0))
+			case t.Etype == TFUNC:
+				nilonly = "func"
+			case t.Etype == TMAP:
+				nilonly = "map"
+			}
 		}
 	}
 
-	le.link = nil
-	return l
+	n.Type = t
+
+	var def *Node
+	var ll *NodeList
+	for l := n.List; l != nil; l = l.Next {
+		ncase := l.N
+		setlineno(n)
+		if ncase.List == nil {
+			// default
+			if def != nil {
+				Yyerror("multiple defaults in switch (first at %v)", def.Line())
+			} else {
+				def = ncase
+			}
+		} else {
+			for ll = ncase.List; ll != nil; ll = ll.Next {
+				setlineno(ll.N)
+				typecheck(&ll.N, Erv|Etype)
+				if ll.N.Type == nil || t == nil {
+					continue
+				}
+				setlineno(ncase)
+				switch top {
+				// expression switch
+				case Erv:
+					defaultlit(&ll.N, t)
+					switch {
+					case ll.N.Op == OTYPE:
+						Yyerror("type %v is not an expression", Tconv(ll.N.Type, 0))
+					case ll.N.Type != nil && assignop(ll.N.Type, t, nil) == 0 && assignop(t, ll.N.Type, nil) == 0:
+						if n.Ntest != nil {
+							Yyerror("invalid case %v in switch on %v (mismatched types %v and %v)", Nconv(ll.N, 0), Nconv(n.Ntest, 0), Tconv(ll.N.Type, 0), Tconv(t, 0))
+						} else {
+							Yyerror("invalid case %v in switch (mismatched types %v and bool)", Nconv(ll.N, 0), Tconv(ll.N.Type, 0))
+						}
+					case nilonly != "" && !Isconst(ll.N, CTNIL):
+						Yyerror("invalid case %v in switch (can only compare %s %v to nil)", Nconv(ll.N, 0), nilonly, Nconv(n.Ntest, 0))
+					}
+
+				// type switch
+				case Etype:
+					var missing, have *Type
+					var ptr int
+					switch {
+					case ll.N.Op == OLITERAL && Istype(ll.N.Type, TNIL):
+					case ll.N.Op != OTYPE && ll.N.Type != nil: // should this be ||?
+						Yyerror("%v is not a type", Nconv(ll.N, obj.FmtLong))
+						// reset to original type
+						ll.N = n.Ntest.Right
+					case ll.N.Type.Etype != TINTER && t.Etype == TINTER && !implements(ll.N.Type, t, &missing, &have, &ptr):
+						if have != nil && missing.Broke == 0 && have.Broke == 0 {
+							Yyerror("impossible type switch case: %v cannot have dynamic type %v"+" (wrong type for %v method)\n\thave %v%v\n\twant %v%v", Nconv(n.Ntest.Right, obj.FmtLong), Tconv(ll.N.Type, 0), Sconv(missing.Sym, 0), Sconv(have.Sym, 0), Tconv(have.Type, obj.FmtShort), Sconv(missing.Sym, 0), Tconv(missing.Type, obj.FmtShort))
+						} else if missing.Broke == 0 {
+							Yyerror("impossible type switch case: %v cannot have dynamic type %v"+" (missing %v method)", Nconv(n.Ntest.Right, obj.FmtLong), Tconv(ll.N.Type, 0), Sconv(missing.Sym, 0))
+						}
+					}
+				}
+			}
+		}
+
+		if top == Etype && n.Type != nil {
+			ll = ncase.List
+			nvar := ncase.Nname
+			if nvar != nil {
+				if ll != nil && ll.Next == nil && ll.N.Type != nil && !Istype(ll.N.Type, TNIL) {
+					// single entry type switch
+					nvar.Ntype = typenod(ll.N.Type)
+				} else {
+					// multiple entry type switch or default
+					nvar.Ntype = typenod(n.Type)
+				}
+
+				typecheck(&nvar, Erv|Easgn)
+				ncase.Nname = nvar
+			}
+		}
+
+		typechecklist(ncase.Nbody, Etop)
+	}
+
+	lineno = int32(lno)
 }
 
-var newlabel_swt_label int
+// walkswitch walks a switch statement.
+func walkswitch(sw *Node) {
+	// convert switch {...} to switch true {...}
+	if sw.Ntest == nil {
+		sw.Ntest = Nodbool(true)
+		typecheck(&sw.Ntest, Erv)
+	}
 
-func newlabel_swt() *Node {
-	newlabel_swt_label++
-	namebuf = fmt.Sprintf("%.6d", newlabel_swt_label)
-	return newname(Lookup(namebuf))
+	if sw.Ntest.Op == OTYPESW {
+		var s typeSwitch
+		s.walk(sw)
+	} else {
+		var s exprSwitch
+		s.walk(sw)
+	}
+
+	// Discard old AST elements. They can confuse racewalk.
+	sw.Ntest = nil
+	sw.List = nil
 }
 
-/*
- * build separate list of statements and cases
- * make labels between cases and statements
- * deal with fallthrough, break, unreachable statements
- */
+// walk generates an AST implementing sw.
+// sw is an expression switch.
+// The AST is generally of the form of a linear
+// search using if..goto, although binary search
+// is used with long runs of constants.
+func (s *exprSwitch) walk(sw *Node) {
+	casebody(sw, nil)
+
+	s.kind = switchKindExpr
+	if Isconst(sw.Ntest, CTBOOL) {
+		s.kind = switchKindTrue
+		if sw.Ntest.Val.U.Bval == 0 {
+			s.kind = switchKindFalse
+		}
+	}
+
+	walkexpr(&sw.Ntest, &sw.Ninit)
+	t := sw.Type
+	if t == nil {
+		return
+	}
+
+	// convert the switch into OIF statements
+	var cas *NodeList
+	if s.kind == switchKindTrue || s.kind == switchKindFalse {
+		s.exprname = Nodbool(s.kind == switchKindTrue)
+	} else if consttype(sw.Ntest) >= 0 {
+		// leave constants to enable dead code elimination (issue 9608)
+		s.exprname = sw.Ntest
+	} else {
+		s.exprname = temp(sw.Ntest.Type)
+		cas = list1(Nod(OAS, s.exprname, sw.Ntest))
+		typechecklist(cas, Etop)
+	}
+
+	// enumerate the cases, and lop off the default case
+	cc := caseClauses(sw, s.kind)
+	var def *Node
+	if len(cc) > 0 && cc[0].typ == caseKindDefault {
+		def = cc[0].node.Right
+		cc = cc[1:]
+	} else {
+		def = Nod(OBREAK, nil, nil)
+	}
+
+	// handle the cases in order
+	for len(cc) > 0 {
+		// deal with expressions one at a time
+		if !okforcmp[t.Etype] || cc[0].typ != caseKindExprConst {
+			a := s.walkCases(cc[:1])
+			cas = list(cas, a)
+			cc = cc[1:]
+			continue
+		}
+
+		// do binary search on runs of constants
+		var run int
+		for run = 1; run < len(cc) && cc[run].typ == caseKindExprConst; run++ {
+		}
+
+		// sort and compile constants
+		sort.Sort(caseClauseByExpr(cc[:run]))
+		a := s.walkCases(cc[:run])
+		cas = list(cas, a)
+		cc = cc[run:]
+	}
+
+	// handle default case
+	if nerrors == 0 {
+		cas = list(cas, def)
+		sw.Nbody = concat(cas, sw.Nbody)
+		sw.List = nil
+		walkstmtlist(sw.Nbody)
+	}
+}
+
+// walkCases generates an AST implementing the cases in cc.
+func (s *exprSwitch) walkCases(cc []*caseClause) *Node {
+	if len(cc) < binarySearchMin {
+		// linear search
+		var cas *NodeList
+		for _, c := range cc {
+			n := c.node
+			lno := int(setlineno(n))
+
+			a := Nod(OIF, nil, nil)
+			if (s.kind != switchKindTrue && s.kind != switchKindFalse) || assignop(n.Left.Type, s.exprname.Type, nil) == OCONVIFACE || assignop(s.exprname.Type, n.Left.Type, nil) == OCONVIFACE {
+				a.Ntest = Nod(OEQ, s.exprname, n.Left) // if name == val
+				typecheck(&a.Ntest, Erv)
+			} else if s.kind == switchKindTrue {
+				a.Ntest = n.Left // if val
+			} else {
+				// s.kind == switchKindFalse
+				a.Ntest = Nod(ONOT, n.Left, nil) // if !val
+				typecheck(&a.Ntest, Erv)
+			}
+			a.Nbody = list1(n.Right) // goto l
+
+			cas = list(cas, a)
+			lineno = int32(lno)
+		}
+		return liststmt(cas)
+	}
+
+	// find the middle and recur
+	half := len(cc) / 2
+	a := Nod(OIF, nil, nil)
+	mid := cc[half-1].node.Left
+	le := Nod(OLE, s.exprname, mid)
+	if Isconst(mid, CTSTR) {
+		// Search by length and then by value; see exprcmp.
+		lenlt := Nod(OLT, Nod(OLEN, s.exprname, nil), Nod(OLEN, mid, nil))
+		leneq := Nod(OEQ, Nod(OLEN, s.exprname, nil), Nod(OLEN, mid, nil))
+		a.Ntest = Nod(OOROR, lenlt, Nod(OANDAND, leneq, le))
+	} else {
+		a.Ntest = le
+	}
+	typecheck(&a.Ntest, Erv)
+	a.Nbody = list1(s.walkCases(cc[:half]))
+	a.Nelse = list1(s.walkCases(cc[half:]))
+	return a
+}
+
+// casebody builds separate lists of statements and cases.
+// It makes labels between cases and statements
+// and deals with fallthrough, break, and unreachable statements.
 func casebody(sw *Node, typeswvar *Node) {
 	if sw.List == nil {
 		return
@@ -265,67 +340,54 @@
 
 	lno := setlineno(sw)
 
-	cas := (*NodeList)(nil)  // cases
-	stat := (*NodeList)(nil) // statements
-	def := (*Node)(nil)      // defaults
+	var cas *NodeList  // cases
+	var stat *NodeList // statements
+	var def *Node      // defaults
 	br := Nod(OBREAK, nil, nil)
 
-	var c *Node
-	var go_ *Node
-	var needvar bool
-	var lc *NodeList
-	var last *Node
-	var n *Node
 	for l := sw.List; l != nil; l = l.Next {
-		n = l.N
+		n := l.N
 		setlineno(n)
 		if n.Op != OXCASE {
 			Fatal("casebody %v", Oconv(int(n.Op), 0))
 		}
 		n.Op = OCASE
-		needvar = count(n.List) != 1 || n.List.N.Op == OLITERAL
+		needvar := count(n.List) != 1 || n.List.N.Op == OLITERAL
 
-		go_ = Nod(OGOTO, newlabel_swt(), nil)
+		jmp := Nod(OGOTO, newCaseLabel(), nil)
 		if n.List == nil {
 			if def != nil {
 				Yyerror("more than one default case")
 			}
-
 			// reuse original default case
-			n.Right = go_
-
+			n.Right = jmp
 			def = n
 		}
 
 		if n.List != nil && n.List.Next == nil {
-			// one case - reuse OCASE node.
-			c = n.List.N
-
-			n.Left = c
-			n.Right = go_
+			// one case -- reuse OCASE node
+			n.Left = n.List.N
+			n.Right = jmp
 			n.List = nil
 			cas = list(cas, n)
 		} else {
 			// expand multi-valued cases
-			for lc = n.List; lc != nil; lc = lc.Next {
-				c = lc.N
-				cas = list(cas, Nod(OCASE, c, go_))
+			for lc := n.List; lc != nil; lc = lc.Next {
+				cas = list(cas, Nod(OCASE, lc.N, jmp))
 			}
 		}
 
-		stat = list(stat, Nod(OLABEL, go_.Left, nil))
+		stat = list(stat, Nod(OLABEL, jmp.Left, nil))
 		if typeswvar != nil && needvar && n.Nname != nil {
 			l := list1(Nod(ODCL, n.Nname, nil))
 			l = list(l, Nod(OAS, n.Nname, typeswvar))
 			typechecklist(l, Etop)
 			stat = concat(stat, l)
 		}
-
 		stat = concat(stat, n.Nbody)
 
 		// botch - shouldn't fall thru declaration
-		last = stat.End.N
-
+		last := stat.End.N
 		if last.Xoffset == n.Xoffset && last.Op == OXFALL {
 			if typeswvar != nil {
 				setlineno(last)
@@ -353,326 +415,103 @@
 	lineno = lno
 }
 
-func mkcaselist(sw *Node, arg int) *Case {
-	var n *Node
-	var c1 *Case
+// nSwitchLabel is the number of switch labels generated.
+// This should be per-function, but it is a global counter for now.
+var nSwitchLabel int
 
-	c := (*Case)(nil)
-	ord := 0
+func newCaseLabel() *Node {
+	label := strconv.Itoa(nSwitchLabel)
+	nSwitchLabel++
+	return newname(Lookup(label))
+}
 
+// caseClauses generates a slice of caseClauses
+// corresponding to the clauses in the switch statement sw.
+// Kind is the kind of switch statement.
+func caseClauses(sw *Node, kind int) []*caseClause {
+	var cc []*caseClause
 	for l := sw.List; l != nil; l = l.Next {
-		n = l.N
-		c1 = new(Case)
-		c1.link = c
-		c = c1
-
-		ord++
-		if int(uint16(ord)) != ord {
-			Fatal("too many cases in switch")
-		}
-		c.ordinal = uint16(ord)
+		n := l.N
+		c := new(caseClause)
+		cc = append(cc, c)
+		c.ordinal = len(cc)
 		c.node = n
 
 		if n.Left == nil {
-			c.type_ = Tdefault
+			c.typ = caseKindDefault
 			continue
 		}
 
-		switch arg {
-		case Stype:
-			c.hash = 0
-			if n.Left.Op == OLITERAL {
-				c.type_ = Ttypenil
-				continue
+		if kind == switchKindType {
+			// type switch
+			switch {
+			case n.Left.Op == OLITERAL:
+				c.typ = caseKindTypeNil
+			case Istype(n.Left.Type, TINTER):
+				c.typ = caseKindTypeVar
+			default:
+				c.typ = caseKindTypeConst
+				c.hash = typehash(n.Left.Type)
 			}
-
-			if Istype(n.Left.Type, TINTER) {
-				c.type_ = Ttypevar
-				continue
-			}
-
-			c.hash = typehash(n.Left.Type)
-			c.type_ = Ttypeconst
-			continue
-
-		case Snorm,
-			Strue,
-			Sfalse:
-			c.type_ = Texprvar
-			c.hash = typehash(n.Left.Type)
+		} else {
+			// expression switch
 			switch consttype(n.Left) {
-			case CTFLT,
-				CTINT,
-				CTRUNE,
-				CTSTR:
-				c.type_ = Texprconst
+			case CTFLT, CTINT, CTRUNE, CTSTR:
+				c.typ = caseKindExprConst
+			default:
+				c.typ = caseKindExprVar
 			}
-
-			continue
 		}
 	}
 
-	if c == nil {
+	if cc == nil {
 		return nil
 	}
 
 	// sort by value and diagnose duplicate cases
-	switch arg {
-	case Stype:
-		c = csort(c, typecmp)
-		var c2 *Case
-		for c1 := c; c1 != nil; c1 = c1.link {
-			for c2 = c1.link; c2 != nil && c2.hash == c1.hash; c2 = c2.link {
-				if c1.type_ == Ttypenil || c1.type_ == Tdefault {
+	if kind == switchKindType {
+		// type switch
+		sort.Sort(caseClauseByType(cc))
+		for i, c1 := range cc {
+			if c1.typ == caseKindTypeNil || c1.typ == caseKindDefault {
+				break
+			}
+			for _, c2 := range cc[i+1:] {
+				if c2.typ == caseKindTypeNil || c2.typ == caseKindDefault || c1.hash != c2.hash {
 					break
 				}
-				if c2.type_ == Ttypenil || c2.type_ == Tdefault {
-					break
+				if Eqtype(c1.node.Left.Type, c2.node.Left.Type) {
+					yyerrorl(int(c2.node.Lineno), "duplicate case %v in type switch\n\tprevious case at %v", Tconv(c2.node.Left.Type, 0), c1.node.Line())
 				}
-				if !Eqtype(c1.node.Left.Type, c2.node.Left.Type) {
-					continue
-				}
-				yyerrorl(int(c2.node.Lineno), "duplicate case %v in type switch\n\tprevious case at %v", Tconv(c2.node.Left.Type, 0), c1.node.Line())
 			}
 		}
-
-	case Snorm,
-		Strue,
-		Sfalse:
-		c = csort(c, exprcmp)
-		for c1 := c; c1.link != nil; c1 = c1.link {
-			if exprcmp(c1, c1.link) != 0 {
+	} else {
+		// expression switch
+		sort.Sort(caseClauseByExpr(cc))
+		for i, c1 := range cc {
+			if i+1 == len(cc) {
+				break
+			}
+			c2 := cc[i+1]
+			if exprcmp(c1, c2) != 0 {
 				continue
 			}
-			setlineno(c1.link.node)
+			setlineno(c2.node)
 			Yyerror("duplicate case %v in switch\n\tprevious case at %v", Nconv(c1.node.Left, 0), c1.node.Line())
 		}
 	}
 
 	// put list back in processing order
-	c = csort(c, ordlcmp)
-
-	return c
+	sort.Sort(caseClauseByOrd(cc))
+	return cc
 }
 
-var exprname *Node
-
-func exprbsw(c0 *Case, ncase int, arg int) *Node {
-	cas := (*NodeList)(nil)
-	if ncase < Ncase {
-		var a *Node
-		var n *Node
-		var lno int
-		for i := 0; i < ncase; i++ {
-			n = c0.node
-			lno = int(setlineno(n))
-
-			if (arg != Strue && arg != Sfalse) || assignop(n.Left.Type, exprname.Type, nil) == OCONVIFACE || assignop(exprname.Type, n.Left.Type, nil) == OCONVIFACE {
-				a = Nod(OIF, nil, nil)
-				a.Ntest = Nod(OEQ, exprname, n.Left) // if name == val
-				typecheck(&a.Ntest, Erv)
-				a.Nbody = list1(n.Right) // then goto l
-			} else if arg == Strue {
-				a = Nod(OIF, nil, nil)
-				a.Ntest = n.Left         // if val
-				a.Nbody = list1(n.Right) // then goto l // arg == Sfalse
-			} else {
-				a = Nod(OIF, nil, nil)
-				a.Ntest = Nod(ONOT, n.Left, nil) // if !val
-				typecheck(&a.Ntest, Erv)
-				a.Nbody = list1(n.Right) // then goto l
-			}
-
-			cas = list(cas, a)
-			c0 = c0.link
-			lineno = int32(lno)
-		}
-
-		return liststmt(cas)
-	}
-
-	// find the middle and recur
-	c := c0
-
-	half := ncase >> 1
-	for i := 1; i < half; i++ {
-		c = c.link
-	}
-	a := Nod(OIF, nil, nil)
-	a.Ntest = Nod(OLE, exprname, c.node.Left)
-	typecheck(&a.Ntest, Erv)
-	a.Nbody = list1(exprbsw(c0, half, arg))
-	a.Nelse = list1(exprbsw(c.link, ncase-half, arg))
-	return a
-}
-
-/*
- * normal (expression) switch.
- * rebuild case statements into if .. goto
- */
-func exprswitch(sw *Node) {
-	casebody(sw, nil)
-
-	arg := Snorm
-	if Isconst(sw.Ntest, CTBOOL) {
-		arg = Strue
-		if sw.Ntest.Val.U.Bval == 0 {
-			arg = Sfalse
-		}
-	}
-
-	walkexpr(&sw.Ntest, &sw.Ninit)
-	t := sw.Type
-	if t == nil {
-		return
-	}
-
-	/*
-	 * convert the switch into OIF statements
-	 */
-	exprname = nil
-
-	cas := (*NodeList)(nil)
-	if arg == Strue || arg == Sfalse {
-		exprname = Nodbool(arg == Strue)
-	} else if consttype(sw.Ntest) >= 0 {
-		// leave constants to enable dead code elimination (issue 9608)
-		exprname = sw.Ntest
-	} else {
-		exprname = temp(sw.Ntest.Type)
-		cas = list1(Nod(OAS, exprname, sw.Ntest))
-		typechecklist(cas, Etop)
-	}
-
-	c0 := mkcaselist(sw, arg)
-	var def *Node
-	if c0 != nil && c0.type_ == Tdefault {
-		def = c0.node.Right
-		c0 = c0.link
-	} else {
-		def = Nod(OBREAK, nil, nil)
-	}
-
-	var c *Case
-	var a *Node
-	var ncase int
-	var c1 *Case
-loop:
-	if c0 == nil {
-		cas = list(cas, def)
-		sw.Nbody = concat(cas, sw.Nbody)
-		sw.List = nil
-		walkstmtlist(sw.Nbody)
-		return
-	}
-
-	// deal with the variables one-at-a-time
-	if okforcmp[t.Etype] == 0 || c0.type_ != Texprconst {
-		a = exprbsw(c0, 1, arg)
-		cas = list(cas, a)
-		c0 = c0.link
-		goto loop
-	}
-
-	// do binary search on run of constants
-	ncase = 1
-
-	for c = c0; c.link != nil; c = c.link {
-		if c.link.type_ != Texprconst {
-			break
-		}
-		ncase++
-	}
-
-	// break the chain at the count
-	c1 = c.link
-
-	c.link = nil
-
-	// sort and compile constants
-	c0 = csort(c0, exprcmp)
-
-	a = exprbsw(c0, ncase, arg)
-	cas = list(cas, a)
-
-	c0 = c1
-	goto loop
-}
-
-var hashname *Node
-
-var facename *Node
-
-var boolname *Node
-
-func typeone(t *Node) *Node {
-	var_ := t.Nname
-	init := (*NodeList)(nil)
-	if var_ == nil {
-		typecheck(&nblank, Erv|Easgn)
-		var_ = nblank
-	} else {
-		init = list1(Nod(ODCL, var_, nil))
-	}
-
-	a := Nod(OAS2, nil, nil)
-	a.List = list(list1(var_), boolname) // var,bool =
-	b := Nod(ODOTTYPE, facename, nil)
-	b.Type = t.Left.Type // interface.(type)
-	a.Rlist = list1(b)
-	typecheck(&a, Etop)
-	init = list(init, a)
-
-	b = Nod(OIF, nil, nil)
-	b.Ntest = boolname
-	b.Nbody = list1(t.Right) // if bool { goto l }
-	a = liststmt(list(init, b))
-	return a
-}
-
-func typebsw(c0 *Case, ncase int) *Node {
-	cas := (*NodeList)(nil)
-
-	if ncase < Ncase {
-		var n *Node
-		var a *Node
-		for i := 0; i < ncase; i++ {
-			n = c0.node
-			if c0.type_ != Ttypeconst {
-				Fatal("typebsw")
-			}
-			a = Nod(OIF, nil, nil)
-			a.Ntest = Nod(OEQ, hashname, Nodintconst(int64(c0.hash)))
-			typecheck(&a.Ntest, Erv)
-			a.Nbody = list1(n.Right)
-			cas = list(cas, a)
-			c0 = c0.link
-		}
-
-		return liststmt(cas)
-	}
-
-	// find the middle and recur
-	c := c0
-
-	half := ncase >> 1
-	for i := 1; i < half; i++ {
-		c = c.link
-	}
-	a := Nod(OIF, nil, nil)
-	a.Ntest = Nod(OLE, hashname, Nodintconst(int64(c.hash)))
-	typecheck(&a.Ntest, Erv)
-	a.Nbody = list1(typebsw(c0, half))
-	a.Nelse = list1(typebsw(c.link, ncase-half))
-	return a
-}
-
-/*
- * convert switch of the form
- *	switch v := i.(type) { case t1: ..; case t2: ..; }
- * into if statements
- */
-func typeswitch(sw *Node) {
+// walk generates an AST that implements sw,
+// where sw is a type switch.
+// The AST is generally of the form of a linear
+// search using if..goto, although binary search
+// is used with long runs of concrete types.
+func (s *typeSwitch) walk(sw *Node) {
 	if sw.Ntest == nil {
 		return
 	}
@@ -688,126 +527,108 @@
 		return
 	}
 
-	cas := (*NodeList)(nil)
+	var cas *NodeList
 
-	/*
-	 * predeclare temporary variables
-	 * and the boolean var
-	 */
-	facename = temp(sw.Ntest.Right.Type)
+	// predeclare temporary variables and the boolean var
+	s.facename = temp(sw.Ntest.Right.Type)
 
-	a := Nod(OAS, facename, sw.Ntest.Right)
+	a := Nod(OAS, s.facename, sw.Ntest.Right)
 	typecheck(&a, Etop)
 	cas = list(cas, a)
 
-	casebody(sw, facename)
+	s.okname = temp(Types[TBOOL])
+	typecheck(&s.okname, Erv)
 
-	boolname = temp(Types[TBOOL])
-	typecheck(&boolname, Erv)
+	s.hashname = temp(Types[TUINT32])
+	typecheck(&s.hashname, Erv)
 
-	hashname = temp(Types[TUINT32])
-	typecheck(&hashname, Erv)
+	// set up labels and jumps
+	casebody(sw, s.facename)
 
+	// calculate type hash
 	t := sw.Ntest.Right.Type
 	if isnilinter(t) {
 		a = syslook("efacethash", 1)
 	} else {
 		a = syslook("ifacethash", 1)
 	}
-	argtype(a, t)
+	substArgTypes(a, t)
 	a = Nod(OCALL, a, nil)
-	a.List = list1(facename)
-	a = Nod(OAS, hashname, a)
+	a.List = list1(s.facename)
+	a = Nod(OAS, s.hashname, a)
 	typecheck(&a, Etop)
 	cas = list(cas, a)
 
-	c0 := mkcaselist(sw, Stype)
+	cc := caseClauses(sw, switchKindType)
 	var def *Node
-	if c0 != nil && c0.type_ == Tdefault {
-		def = c0.node.Right
-		c0 = c0.link
+	if len(cc) > 0 && cc[0].typ == caseKindDefault {
+		def = cc[0].node.Right
+		cc = cc[1:]
 	} else {
 		def = Nod(OBREAK, nil, nil)
 	}
 
-	/*
-	 * insert if statement into each case block
-	 */
-	var v Val
-	var n *Node
-	for c := c0; c != nil; c = c.link {
-		n = c.node
-		switch c.type_ {
-		case Ttypenil:
+	// insert type equality check into each case block
+	for _, c := range cc {
+		n := c.node
+		switch c.typ {
+		case caseKindTypeNil:
+			var v Val
 			v.Ctype = CTNIL
 			a = Nod(OIF, nil, nil)
-			a.Ntest = Nod(OEQ, facename, nodlit(v))
+			a.Ntest = Nod(OEQ, s.facename, nodlit(v))
 			typecheck(&a.Ntest, Erv)
 			a.Nbody = list1(n.Right) // if i==nil { goto l }
 			n.Right = a
 
-		case Ttypevar,
-			Ttypeconst:
-			n.Right = typeone(n)
+		case caseKindTypeVar, caseKindTypeConst:
+			n.Right = s.typeone(n)
 		}
 	}
 
-	/*
-	 * generate list of if statements, binary search for constant sequences
-	 */
-	var ncase int
-	var c1 *Case
-	var hash *NodeList
-	var c *Case
-	for c0 != nil {
-		if c0.type_ != Ttypeconst {
-			n = c0.node
+	// generate list of if statements, binary search for constant sequences
+	for len(cc) > 0 {
+		if cc[0].typ != caseKindTypeConst {
+			n := cc[0].node
 			cas = list(cas, n.Right)
-			c0 = c0.link
+			cc = cc[1:]
 			continue
 		}
 
 		// identify run of constants
-		c = c0
-		c1 = c
-
-		for c.link != nil && c.link.type_ == Ttypeconst {
-			c = c.link
+		var run int
+		for run = 1; run < len(cc) && cc[run].typ == caseKindTypeConst; run++ {
 		}
-		c0 = c.link
-		c.link = nil
 
 		// sort by hash
-		c1 = csort(c1, typecmp)
+		sort.Sort(caseClauseByType(cc[:run]))
 
 		// for debugging: linear search
 		if false {
-			for c = c1; c != nil; c = c.link {
-				n = c.node
+			for i := 0; i < run; i++ {
+				n := cc[i].node
 				cas = list(cas, n.Right)
 			}
-
 			continue
 		}
 
 		// combine adjacent cases with the same hash
-		ncase = 0
-
-		for c = c1; c != nil; c = c.link {
+		ncase := 0
+		for i := 0; i < run; i++ {
 			ncase++
-			hash = list1(c.node.Right)
-			for c.link != nil && c.link.hash == c.hash {
-				hash = list(hash, c.link.node.Right)
-				c.link = c.link.link
+			hash := list1(cc[i].node.Right)
+			for j := i + 1; j < run && cc[i].hash == cc[j].hash; j++ {
+				hash = list(hash, cc[j].node.Right)
 			}
-
-			c.node.Right = liststmt(hash)
+			cc[i].node.Right = liststmt(hash)
 		}
 
 		// binary search among cases to narrow by hash
-		cas = list(cas, typebsw(c1, ncase))
+		cas = list(cas, s.walkCases(cc[:ncase]))
+		cc = cc[ncase:]
 	}
 
+	// handle default case
 	if nerrors == 0 {
 		cas = list(cas, def)
 		sw.Nbody = concat(cas, sw.Nbody)
@@ -816,161 +637,204 @@
 	}
 }
 
-func walkswitch(sw *Node) {
-	/*
-	 * reorder the body into (OLIST, cases, statements)
-	 * cases have OGOTO into statements.
-	 * both have inserted OBREAK statements
-	 */
-	if sw.Ntest == nil {
-		sw.Ntest = Nodbool(true)
-		typecheck(&sw.Ntest, Erv)
+// typeone generates an AST that jumps to the
+// case body if the variable is of type t.
+func (s *typeSwitch) typeone(t *Node) *Node {
+	name := t.Nname
+	var init *NodeList
+	if name == nil {
+		typecheck(&nblank, Erv|Easgn)
+		name = nblank
+	} else {
+		init = list1(Nod(ODCL, name, nil))
 	}
 
-	if sw.Ntest.Op == OTYPESW {
-		typeswitch(sw)
+	a := Nod(OAS2, nil, nil)
+	a.List = list(list1(name), s.okname) // name, ok =
+	b := Nod(ODOTTYPE, s.facename, nil)
+	b.Type = t.Left.Type // interface.(type)
+	a.Rlist = list1(b)
+	typecheck(&a, Etop)
+	init = list(init, a)
 
-		//dump("sw", sw);
-		return
-	}
+	c := Nod(OIF, nil, nil)
+	c.Ntest = s.okname
+	c.Nbody = list1(t.Right) // if ok { goto l }
 
-	exprswitch(sw)
-
-	// Discard old AST elements after a walk. They can confuse racewealk.
-	sw.Ntest = nil
-
-	sw.List = nil
+	return liststmt(list(init, c))
 }
 
-/*
- * type check switch statement
- */
-func typecheckswitch(n *Node) {
-	var top int
-	var t *Type
-
-	lno := int(lineno)
-	typechecklist(n.Ninit, Etop)
-	nilonly := ""
-
-	if n.Ntest != nil && n.Ntest.Op == OTYPESW {
-		// type switch
-		top = Etype
-
-		typecheck(&n.Ntest.Right, Erv)
-		t = n.Ntest.Right.Type
-		if t != nil && t.Etype != TINTER {
-			Yyerror("cannot type switch on non-interface value %v", Nconv(n.Ntest.Right, obj.FmtLong))
-		}
-	} else {
-		// value switch
-		top = Erv
-
-		if n.Ntest != nil {
-			typecheck(&n.Ntest, Erv)
-			defaultlit(&n.Ntest, nil)
-			t = n.Ntest.Type
-		} else {
-			t = Types[TBOOL]
-		}
-		if t != nil {
-			var badtype *Type
-			if okforeq[t.Etype] == 0 {
-				Yyerror("cannot switch on %v", Nconv(n.Ntest, obj.FmtLong))
-			} else if t.Etype == TARRAY && !Isfixedarray(t) {
-				nilonly = "slice"
-			} else if t.Etype == TARRAY && Isfixedarray(t) && algtype1(t, nil) == ANOEQ {
-				Yyerror("cannot switch on %v", Nconv(n.Ntest, obj.FmtLong))
-			} else if t.Etype == TSTRUCT && algtype1(t, &badtype) == ANOEQ {
-				Yyerror("cannot switch on %v (struct containing %v cannot be compared)", Nconv(n.Ntest, obj.FmtLong), Tconv(badtype, 0))
-			} else if t.Etype == TFUNC {
-				nilonly = "func"
-			} else if t.Etype == TMAP {
-				nilonly = "map"
+// walkCases generates an AST implementing the cases in cc.
+func (s *typeSwitch) walkCases(cc []*caseClause) *Node {
+	if len(cc) < binarySearchMin {
+		var cas *NodeList
+		for _, c := range cc {
+			n := c.node
+			if c.typ != caseKindTypeConst {
+				Fatal("typeSwitch walkCases")
 			}
+			a := Nod(OIF, nil, nil)
+			a.Ntest = Nod(OEQ, s.hashname, Nodintconst(int64(c.hash)))
+			typecheck(&a.Ntest, Erv)
+			a.Nbody = list1(n.Right)
+			cas = list(cas, a)
+		}
+		return liststmt(cas)
+	}
+
+	// find the middle and recur
+	half := len(cc) / 2
+	a := Nod(OIF, nil, nil)
+	a.Ntest = Nod(OLE, s.hashname, Nodintconst(int64(cc[half-1].hash)))
+	typecheck(&a.Ntest, Erv)
+	a.Nbody = list1(s.walkCases(cc[:half]))
+	a.Nelse = list1(s.walkCases(cc[half:]))
+	return a
+}
+
+type caseClauseByOrd []*caseClause
+
+func (x caseClauseByOrd) Len() int      { return len(x) }
+func (x caseClauseByOrd) Swap(i, j int) { x[i], x[j] = x[j], x[i] }
+func (x caseClauseByOrd) Less(i, j int) bool {
+	c1, c2 := x[i], x[j]
+	switch {
+	// sort default first
+	case c1.typ == caseKindDefault:
+		return true
+	case c2.typ == caseKindDefault:
+		return false
+
+	// sort nil second
+	case c1.typ == caseKindTypeNil:
+		return true
+	case c2.typ == caseKindTypeNil:
+		return false
+	}
+
+	// sort by ordinal
+	return c1.ordinal < c2.ordinal
+}
+
+type caseClauseByExpr []*caseClause
+
+func (x caseClauseByExpr) Len() int      { return len(x) }
+func (x caseClauseByExpr) Swap(i, j int) { x[i], x[j] = x[j], x[i] }
+func (x caseClauseByExpr) Less(i, j int) bool {
+	return exprcmp(x[i], x[j]) < 0
+}
+
+func exprcmp(c1, c2 *caseClause) int {
+	// sort non-constants last
+	if c1.typ != caseKindExprConst {
+		return +1
+	}
+	if c2.typ != caseKindExprConst {
+		return -1
+	}
+
+	n1 := c1.node.Left
+	n2 := c2.node.Left
+
+	// sort by type (for switches on interface)
+	ct := int(n1.Val.Ctype)
+	if ct > int(n2.Val.Ctype) {
+		return +1
+	}
+	if ct < int(n2.Val.Ctype) {
+		return -1
+	}
+	if !Eqtype(n1.Type, n2.Type) {
+		if n1.Type.Vargen > n2.Type.Vargen {
+			return +1
+		} else {
+			return -1
 		}
 	}
 
-	n.Type = t
-
-	def := (*Node)(nil)
-	var ptr int
-	var have *Type
-	var nvar *Node
-	var ll *NodeList
-	var missing *Type
-	var ncase *Node
-	for l := n.List; l != nil; l = l.Next {
-		ncase = l.N
-		setlineno(n)
-		if ncase.List == nil {
-			// default
-			if def != nil {
-				Yyerror("multiple defaults in switch (first at %v)", def.Line())
-			} else {
-				def = ncase
-			}
-		} else {
-			for ll = ncase.List; ll != nil; ll = ll.Next {
-				setlineno(ll.N)
-				typecheck(&ll.N, Erv|Etype)
-				if ll.N.Type == nil || t == nil {
-					continue
-				}
-				setlineno(ncase)
-				switch top {
-				case Erv: // expression switch
-					defaultlit(&ll.N, t)
-
-					if ll.N.Op == OTYPE {
-						Yyerror("type %v is not an expression", Tconv(ll.N.Type, 0))
-					} else if ll.N.Type != nil && assignop(ll.N.Type, t, nil) == 0 && assignop(t, ll.N.Type, nil) == 0 {
-						if n.Ntest != nil {
-							Yyerror("invalid case %v in switch on %v (mismatched types %v and %v)", Nconv(ll.N, 0), Nconv(n.Ntest, 0), Tconv(ll.N.Type, 0), Tconv(t, 0))
-						} else {
-							Yyerror("invalid case %v in switch (mismatched types %v and bool)", Nconv(ll.N, 0), Tconv(ll.N.Type, 0))
-						}
-					} else if nilonly != "" && !Isconst(ll.N, CTNIL) {
-						Yyerror("invalid case %v in switch (can only compare %s %v to nil)", Nconv(ll.N, 0), nilonly, Nconv(n.Ntest, 0))
-					}
-
-				case Etype: // type switch
-					if ll.N.Op == OLITERAL && Istype(ll.N.Type, TNIL) {
-					} else if ll.N.Op != OTYPE && ll.N.Type != nil { // should this be ||?
-						Yyerror("%v is not a type", Nconv(ll.N, obj.FmtLong))
-
-						// reset to original type
-						ll.N = n.Ntest.Right
-					} else if ll.N.Type.Etype != TINTER && t.Etype == TINTER && !implements(ll.N.Type, t, &missing, &have, &ptr) {
-						if have != nil && missing.Broke == 0 && have.Broke == 0 {
-							Yyerror("impossible type switch case: %v cannot have dynamic type %v"+" (wrong type for %v method)\n\thave %v%v\n\twant %v%v", Nconv(n.Ntest.Right, obj.FmtLong), Tconv(ll.N.Type, 0), Sconv(missing.Sym, 0), Sconv(have.Sym, 0), Tconv(have.Type, obj.FmtShort), Sconv(missing.Sym, 0), Tconv(missing.Type, obj.FmtShort))
-						} else if missing.Broke == 0 {
-							Yyerror("impossible type switch case: %v cannot have dynamic type %v"+" (missing %v method)", Nconv(n.Ntest.Right, obj.FmtLong), Tconv(ll.N.Type, 0), Sconv(missing.Sym, 0))
-						}
-					}
-				}
-			}
+	// sort by constant value to enable binary search
+	switch ct {
+	case CTFLT:
+		return mpcmpfltflt(n1.Val.U.Fval, n2.Val.U.Fval)
+	case CTINT, CTRUNE:
+		return Mpcmpfixfix(n1.Val.U.Xval, n2.Val.U.Xval)
+	case CTSTR:
+		// Sort strings by length and then by value.
+		// It is much cheaper to compare lengths than values,
+		// and all we need here is consistency.
+		// We respect this sorting in exprSwitch.walkCases.
+		a := n1.Val.U.Sval
+		b := n2.Val.U.Sval
+		if len(a) < len(b) {
+			return -1
 		}
-
-		if top == Etype && n.Type != nil {
-			ll = ncase.List
-			nvar = ncase.Nname
-			if nvar != nil {
-				if ll != nil && ll.Next == nil && ll.N.Type != nil && !Istype(ll.N.Type, TNIL) {
-					// single entry type switch
-					nvar.Ntype = typenod(ll.N.Type)
-				} else {
-					// multiple entry type switch or default
-					nvar.Ntype = typenod(n.Type)
-				}
-
-				typecheck(&nvar, Erv|Easgn)
-				ncase.Nname = nvar
-			}
+		if len(a) > len(b) {
+			return +1
 		}
-
-		typechecklist(ncase.Nbody, Etop)
+		return stringsCompare(a, b)
 	}
 
-	lineno = int32(lno)
+	return 0
+}
+
+type caseClauseByType []*caseClause
+
+func (x caseClauseByType) Len() int      { return len(x) }
+func (x caseClauseByType) Swap(i, j int) { x[i], x[j] = x[j], x[i] }
+func (x caseClauseByType) Less(i, j int) bool {
+	c1, c2 := x[i], x[j]
+	switch {
+	// sort non-constants last
+	case c1.typ != caseKindTypeConst:
+		return false
+	case c2.typ != caseKindTypeConst:
+		return true
+
+	// sort by hash code
+	case c1.hash != c2.hash:
+		return c1.hash < c2.hash
+	}
+
+	// sort by ordinal
+	return c1.ordinal < c2.ordinal
+}
+
+func dumpcase(cc []*caseClause) {
+	for _, c := range cc {
+		switch c.typ {
+		case caseKindDefault:
+			fmt.Printf("case-default\n")
+			fmt.Printf("\tord=%d\n", c.ordinal)
+
+		case caseKindExprConst:
+			fmt.Printf("case-exprconst\n")
+			fmt.Printf("\tord=%d\n", c.ordinal)
+
+		case caseKindExprVar:
+			fmt.Printf("case-exprvar\n")
+			fmt.Printf("\tord=%d\n", c.ordinal)
+			fmt.Printf("\top=%v\n", Oconv(int(c.node.Left.Op), 0))
+
+		case caseKindTypeNil:
+			fmt.Printf("case-typenil\n")
+			fmt.Printf("\tord=%d\n", c.ordinal)
+
+		case caseKindTypeConst:
+			fmt.Printf("case-typeconst\n")
+			fmt.Printf("\tord=%d\n", c.ordinal)
+			fmt.Printf("\thash=%x\n", c.hash)
+
+		case caseKindTypeVar:
+			fmt.Printf("case-typevar\n")
+			fmt.Printf("\tord=%d\n", c.ordinal)
+
+		default:
+			fmt.Printf("case-???\n")
+			fmt.Printf("\tord=%d\n", c.ordinal)
+			fmt.Printf("\top=%v\n", Oconv(int(c.node.Left.Op), 0))
+			fmt.Printf("\thash=%x\n", c.hash)
+		}
+	}
+
+	fmt.Printf("\n")
 }
diff --git a/src/cmd/internal/gc/syntax.go b/src/cmd/internal/gc/syntax.go
new file mode 100644
index 0000000..8f5b85d
--- /dev/null
+++ b/src/cmd/internal/gc/syntax.go
@@ -0,0 +1,449 @@
+// 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.
+
+// “Abstract” syntax representation.
+
+package gc
+
+// A Node is a single node in the syntax tree.
+// Actually the syntax tree is a syntax DAG, because there is only one
+// node with Op=ONAME for a given instance of a variable x.
+// The same is true for Op=OTYPE and Op=OLITERAL.
+type Node struct {
+	// Tree structure.
+	// Generic recursive walks should follow these fields.
+	Left  *Node
+	Right *Node
+	Ntest *Node
+	Nincr *Node
+	Ninit *NodeList
+	Nbody *NodeList
+	Nelse *NodeList
+	List  *NodeList
+	Rlist *NodeList
+
+	Op          uint8
+	Nointerface bool
+	Ullman      uint8 // sethi/ullman number
+	Addable     uint8 // type of addressability - 0 is not addressable
+	Etype       uint8 // op for OASOP, etype for OTYPE, exclam for export
+	Bounded     bool  // bounds check unnecessary
+	Class       uint8 // PPARAM, PAUTO, PEXTERN, etc
+	Method      uint8 // OCALLMETH name
+	Embedded    uint8 // ODCLFIELD embedded type
+	Colas       uint8 // OAS resulting from :=
+	Diag        uint8 // already printed error about this
+	Noescape    bool  // func arguments do not escape; TODO(rsc): move Noescape to Func struct (see CL 7360)
+	Walkdef     uint8
+	Typecheck   uint8
+	Local       bool
+	Dodata      uint8
+	Initorder   uint8
+	Used        bool
+	Isddd       bool // is the argument variadic
+	Readonly    bool
+	Implicit    bool
+	Addrtaken   bool  // address taken, even if not moved to heap
+	Assigned    bool  // is the variable ever assigned to
+	Captured    bool  // is the variable captured by a closure
+	Byval       bool  // is the variable captured by value or by reference
+	Reslice     bool  // this is a reslice x = x[0:y] or x = append(x, ...)
+	Likely      int8  // likeliness of if statement
+	Hasbreak    bool  // has break statement
+	Needzero    bool  // if it contains pointers, needs to be zeroed on function entry
+	Esc         uint8 // EscXXX
+	Funcdepth   int32
+
+	// most nodes
+	Type  *Type
+	Orig  *Node // original form, for printing, and tracking copies of ONAMEs
+	Nname *Node
+
+	// func
+	Func *Func
+
+	// OLITERAL/OREGISTER
+	Val Val
+
+	// ONAME
+	Ntype     *Node
+	Defn      *Node // ONAME: initializing assignment; OLABEL: labeled statement
+	Pack      *Node // real package for import . names
+	Curfn     *Node // function for local variables
+	Paramfld  *Type // TFIELD for this PPARAM; also for ODOT, curfn
+	Decldepth int   // declaration loop depth, increased for every loop or label
+
+	// ONAME func param with PHEAP
+	Heapaddr   *Node // temp holding heap address of param
+	Outerexpr  *Node // expression copied into closure for variable
+	Stackparam *Node // OPARAM node referring to stack copy of param
+	Alloc      *Node // allocation call
+
+	// ONAME closure param with PPARAMREF
+	Outer   *Node // outer PPARAMREF in nested closure
+	Closure *Node // ONAME/PHEAP <-> ONAME/PPARAMREF
+	Top     int   // top context (Ecall, Eproc, etc)
+
+	// ONAME substitute while inlining
+	Inlvar *Node
+
+	// OPACK
+	Pkg *Pkg
+
+	// OARRAYLIT, OMAPLIT, OSTRUCTLIT.
+	Initplan *InitPlan
+
+	// Escape analysis.
+	Escflowsrc   *NodeList // flow(this, src)
+	Escretval    *NodeList // on OCALLxxx, list of dummy return values
+	Escloopdepth int       // -1: global, 0: return variables, 1:function top level, increased inside function for every loop or label to mark scopes
+
+	Sym      *Sym  // various
+	Vargen   int32 // unique name for OTYPE/ONAME
+	Lineno   int32
+	Xoffset  int64
+	Stkdelta int64 // offset added by stack frame compaction phase.
+	Ostk     int32 // 6g only
+	Iota     int32
+	Walkgen  uint32
+	Esclevel int32
+	Opt      interface{} // for optimization passes
+}
+
+// Func holds Node fields used only with function-like nodes.
+type Func struct {
+	Shortname *Node
+	Enter     *NodeList
+	Exit      *NodeList
+	Cvars     *NodeList // closure params
+	Dcl       *NodeList // autodcl for this func/closure
+	Inldcl    *NodeList // copy of dcl for use in inlining
+	Closgen   int
+	Outerfunc *Node
+
+	Inl     *NodeList // copy of the body for use in inlining
+	InlCost int32
+
+	Endlineno int32
+
+	Nosplit        bool // func should not execute on separate stack
+	Nowritebarrier bool // emit compiler error instead of write barrier
+	Dupok          bool // duplicate definitions ok
+	Wrapper        bool // is method wrapper
+	Needctxt       bool // function uses context register (has closure variables)
+}
+
+// Node ops.
+const (
+	OXXX = iota
+
+	// names
+	ONAME    // var, const or func name
+	ONONAME  // unnamed arg or return value: f(int, string) (int, error) { etc }
+	OTYPE    // type name
+	OPACK    // import
+	OLITERAL // literal
+
+	// expressions
+	OADD             // x + y
+	OSUB             // x - y
+	OOR              // x | y
+	OXOR             // x ^ y
+	OADDSTR          // s + "foo"
+	OADDR            // &x
+	OANDAND          // b0 && b1
+	OAPPEND          // append
+	OARRAYBYTESTR    // string(bytes)
+	OARRAYBYTESTRTMP // string(bytes) ephemeral
+	OARRAYRUNESTR    // string(runes)
+	OSTRARRAYBYTE    // []byte(s)
+	OSTRARRAYBYTETMP // []byte(s) ephemeral
+	OSTRARRAYRUNE    // []rune(s)
+	OAS              // x = y or x := y
+	OAS2             // x, y, z = xx, yy, zz
+	OAS2FUNC         // x, y = f()
+	OAS2RECV         // x, ok = <-c
+	OAS2MAPR         // x, ok = m["foo"]
+	OAS2DOTTYPE      // x, ok = I.(int)
+	OASOP            // x += y
+	OCALL            // function call, method call or type conversion, possibly preceded by defer or go.
+	OCALLFUNC        // f()
+	OCALLMETH        // t.Method()
+	OCALLINTER       // err.Error()
+	OCALLPART        // t.Method (without ())
+	OCAP             // cap
+	OCLOSE           // close
+	OCLOSURE         // f = func() { etc }
+	OCMPIFACE        // err1 == err2
+	OCMPSTR          // s1 == s2
+	OCOMPLIT         // composite literal, typechecking may convert to a more specific OXXXLIT.
+	OMAPLIT          // M{"foo":3, "bar":4}
+	OSTRUCTLIT       // T{x:3, y:4}
+	OARRAYLIT        // [2]int{3, 4}
+	OPTRLIT          // &T{x:3, y:4}
+	OCONV            // var i int; var u uint; i = int(u)
+	OCONVIFACE       // I(t)
+	OCONVNOP         // type Int int; var i int; var j Int; i = int(j)
+	OCOPY            // copy
+	ODCL             // var x int
+	ODCLFUNC         // func f() or func (r) f()
+	ODCLFIELD        // struct field, interface field, or func/method argument/return value.
+	ODCLCONST        // const pi = 3.14
+	ODCLTYPE         // type Int int
+	ODELETE          // delete
+	ODOT             // t.x
+	ODOTPTR          // p.x that is implicitly (*p).x
+	ODOTMETH         // t.Method
+	ODOTINTER        // err.Error
+	OXDOT            // t.x, typechecking may convert to a more specific ODOTXXX.
+	ODOTTYPE         // e = err.(MyErr)
+	ODOTTYPE2        // e, ok = err.(MyErr)
+	OEQ              // x == y
+	ONE              // x != y
+	OLT              // x < y
+	OLE              // x <= y
+	OGE              // x >= y
+	OGT              // x > y
+	OIND             // *p
+	OINDEX           // a[i]
+	OINDEXMAP        // m[s]
+	OKEY             // The x:3 in t{x:3, y:4}, the 1:2 in a[1:2], the 2:20 in [3]int{2:20}, etc.
+	OPARAM           // The on-stack copy of a parameter or return value that escapes.
+	OLEN             // len
+	OMAKE            // make, typechecking may convert to a more specific OMAKEXXX.
+	OMAKECHAN        // make(chan int)
+	OMAKEMAP         // make(map[string]int)
+	OMAKESLICE       // make([]int, 0)
+	OMUL             // *
+	ODIV             // x / y
+	OMOD             // x % y
+	OLSH             // x << u
+	ORSH             // x >> u
+	OAND             // x & y
+	OANDNOT          // x &^ y
+	ONEW             // new
+	ONOT             // !b
+	OCOM             // ^x
+	OPLUS            // +x
+	OMINUS           // -y
+	OOROR            // b1 || b2
+	OPANIC           // panic
+	OPRINT           // print
+	OPRINTN          // println
+	OPAREN           // (x)
+	OSEND            // c <- x
+	OSLICE           // v[1:2], typechecking may convert to a more specific OSLICEXXX.
+	OSLICEARR        // a[1:2]
+	OSLICESTR        // s[1:2]
+	OSLICE3          // v[1:2:3], typechecking may convert to OSLICE3ARR.
+	OSLICE3ARR       // a[1:2:3]
+	ORECOVER         // recover
+	ORECV            // <-c
+	ORUNESTR         // string(i)
+	OSELRECV         // case x = <-c:
+	OSELRECV2        // case x, ok = <-c:
+	OIOTA            // iota
+	OREAL            // real
+	OIMAG            // imag
+	OCOMPLEX         // complex
+
+	// statements
+	OBLOCK    // block of code
+	OBREAK    // break
+	OCASE     // case, after being verified by swt.c's casebody.
+	OXCASE    // case, before verification.
+	OCONTINUE // continue
+	ODEFER    // defer
+	OEMPTY    // no-op
+	OFALL     // fallthrough, after being verified by swt.c's casebody.
+	OXFALL    // fallthrough, before verification.
+	OFOR      // for
+	OGOTO     // goto
+	OIF       // if
+	OLABEL    // label:
+	OPROC     // go
+	ORANGE    // range
+	ORETURN   // return
+	OSELECT   // select
+	OSWITCH   // switch x
+	OTYPESW   // switch err.(type)
+
+	// types
+	OTCHAN   // chan int
+	OTMAP    // map[string]int
+	OTSTRUCT // struct{}
+	OTINTER  // interface{}
+	OTFUNC   // func()
+	OTARRAY  // []int, [8]int, [N]int or [...]int
+
+	// misc
+	ODDD        // func f(args ...int) or f(l...) or var a = [...]int{0, 1, 2}.
+	ODDDARG     // func f(args ...int), introduced by escape analysis.
+	OINLCALL    // intermediary representation of an inlined call.
+	OEFACE      // itable and data words of an empty-interface value.
+	OITAB       // itable word of an interface value.
+	OSPTR       // base pointer of a slice or string.
+	OCLOSUREVAR // variable reference at beginning of closure function
+	OCFUNC      // reference to c function pointer (not go func value)
+	OCHECKNIL   // emit code to ensure pointer/interface not nil
+	OVARKILL    // variable is dead
+
+	// thearch-specific registers
+	OREGISTER // a register, such as AX.
+	OINDREG   // offset plus indirect of a register, such as 8(SP).
+
+	// 386/amd64-specific opcodes
+	OCMP    // compare: ACMP.
+	ODEC    // decrement: ADEC.
+	OINC    // increment: AINC.
+	OEXTEND // extend: ACWD/ACDQ/ACQO.
+	OHMUL   // high mul: AMUL/AIMUL for unsigned/signed (OMUL uses AIMUL for both).
+	OLROT   // left rotate: AROL.
+	ORROTC  // right rotate-carry: ARCR.
+	ORETJMP // return to other function
+	OPS     // compare parity set (for x86 NaN check)
+
+	OEND
+)
+
+/*
+ * Every node has a walkgen field.
+ * If you want to do a traversal of a node graph that
+ * might contain duplicates and want to avoid
+ * visiting the same nodes twice, increment walkgen
+ * before starting.  Then before processing a node, do
+ *
+ *	if(n->walkgen == walkgen)
+ *		return;
+ *	n->walkgen = walkgen;
+ *
+ * Such a walk cannot call another such walk recursively,
+ * because of the use of the global walkgen.
+ */
+var walkgen uint32
+
+// A NodeList is a linked list of nodes.
+// TODO(rsc): Some uses of NodeList should be made into slices.
+// The remaining ones probably just need a simple linked list,
+// not one with concatenation support.
+type NodeList struct {
+	N    *Node
+	Next *NodeList
+	End  *NodeList
+}
+
+// concat returns the concatenation of the lists a and b.
+// The storage taken by both is reused for the result.
+func concat(a *NodeList, b *NodeList) *NodeList {
+	if a == nil {
+		return b
+	}
+	if b == nil {
+		return a
+	}
+
+	a.End.Next = b
+	a.End = b.End
+	b.End = nil
+	return a
+}
+
+// list1 returns a one-element list containing n.
+func list1(n *Node) *NodeList {
+	if n == nil {
+		return nil
+	}
+	if n.Op == OBLOCK && n.Ninit == nil {
+		// Flatten list and steal storage.
+		// Poison pointer to catch errant uses.
+		l := n.List
+
+		n.List = nil
+		return l
+	}
+
+	l := new(NodeList)
+	l.N = n
+	l.End = l
+	return l
+}
+
+// list returns the result of appending n to l.
+func list(l *NodeList, n *Node) *NodeList {
+	return concat(l, list1(n))
+}
+
+// listsort sorts *l in place according to the 3-way comparison function f.
+// The algorithm is mergesort, so it is guaranteed to be O(n log n).
+func listsort(l **NodeList, f func(*Node, *Node) int) {
+	if *l == nil || (*l).Next == nil {
+		return
+	}
+
+	l1 := *l
+	l2 := *l
+	for {
+		l2 = l2.Next
+		if l2 == nil {
+			break
+		}
+		l2 = l2.Next
+		if l2 == nil {
+			break
+		}
+		l1 = l1.Next
+	}
+
+	l2 = l1.Next
+	l1.Next = nil
+	l2.End = (*l).End
+	(*l).End = l1
+
+	l1 = *l
+	listsort(&l1, f)
+	listsort(&l2, f)
+
+	if f(l1.N, l2.N) < 0 {
+		*l = l1
+	} else {
+		*l = l2
+		l2 = l1
+		l1 = *l
+	}
+
+	// now l1 == *l; and l1 < l2
+
+	var le *NodeList
+	for (l1 != nil) && (l2 != nil) {
+		for (l1.Next != nil) && f(l1.Next.N, l2.N) < 0 {
+			l1 = l1.Next
+		}
+
+		// l1 is last one from l1 that is < l2
+		le = l1.Next // le is the rest of l1, first one that is >= l2
+		if le != nil {
+			le.End = (*l).End
+		}
+
+		(*l).End = l1       // cut *l at l1
+		*l = concat(*l, l2) // glue l2 to *l's tail
+
+		l1 = l2 // l1 is the first element of *l that is < the new l2
+		l2 = le // ... because l2 now is the old tail of l1
+	}
+
+	*l = concat(*l, l2) // any remainder
+}
+
+// count returns the length of the list l.
+func count(l *NodeList) int {
+	n := int64(0)
+	for ; l != nil; l = l.Next {
+		n++
+	}
+	if int64(int(n)) != n { // Overflow.
+		Yyerror("too many elements in list")
+	}
+	return int(n)
+}
diff --git a/src/cmd/internal/gc/typecheck.go b/src/cmd/internal/gc/typecheck.go
index 1468d5f..4399164 100644
--- a/src/cmd/internal/gc/typecheck.go
+++ b/src/cmd/internal/gc/typecheck.go
@@ -146,10 +146,7 @@
 	// But re-typecheck ONAME/OTYPE/OLITERAL/OPACK node in case context has changed.
 	if n.Typecheck == 1 {
 		switch n.Op {
-		case ONAME,
-			OTYPE,
-			OLITERAL,
-			OPACK:
+		case ONAME, OTYPE, OLITERAL, OPACK:
 			break
 
 		default:
@@ -265,10 +262,7 @@
 		return
 	}
 	switch consttype(n) {
-	case CTINT,
-		CTRUNE,
-		CTFLT,
-		CTCPLX:
+	case CTINT, CTRUNE, CTFLT, CTCPLX:
 		defaultlit(np, Types[TINT])
 	}
 
@@ -276,44 +270,27 @@
 }
 
 func typecheck1(np **Node, top int) {
-	var et int
-	var aop int
-	var op int
-	var ptr int
-	var l *Node
-	var r *Node
-	var lo *Node
-	var mid *Node
-	var hi *Node
-	var ok int
-	var ntop int
-	var t *Type
-	var tp *Type
-	var missing *Type
-	var have *Type
-	var badtype *Type
-	var v Val
-	var why string
-	var x int64
-
 	n := *np
+	defer func() {
+		*np = n
+	}()
 
 	if n.Sym != nil {
 		if n.Op == ONAME && n.Etype != 0 && top&Ecall == 0 {
 			Yyerror("use of builtin %v not in function call", Sconv(n.Sym, 0))
-			goto error
+			n.Type = nil
+			return
 		}
 
 		typecheckdef(n)
 		if n.Op == ONONAME {
-			goto error
+			n.Type = nil
+			return
 		}
 	}
 
-	*np = n
-
-reswitch:
-	ok = 0
+	ok := 0
+OpSwitch:
 	switch n.Op {
 	// until typecheck is complete, do nothing.
 	default:
@@ -330,11 +307,11 @@
 		if n.Type == nil && n.Val.Ctype == CTSTR {
 			n.Type = idealstring
 		}
-		goto ret
+		break OpSwitch
 
 	case ONONAME:
 		ok |= Erv
-		goto ret
+		break OpSwitch
 
 	case ONAME:
 		if n.Decldepth == 0 {
@@ -342,30 +319,33 @@
 		}
 		if n.Etype != 0 {
 			ok |= Ecall
-			goto ret
+			break OpSwitch
 		}
 
 		if top&Easgn == 0 {
 			// not a write to the variable
 			if isblank(n) {
 				Yyerror("cannot use _ as value")
-				goto error
+				n.Type = nil
+				return
 			}
 
-			n.Used = 1
+			n.Used = true
 		}
 
 		if top&Ecall == 0 && isunsafebuiltin(n) {
 			Yyerror("%v is not an expression, must be called", Nconv(n, 0))
-			goto error
+			n.Type = nil
+			return
 		}
 
 		ok |= Erv
-		goto ret
+		break OpSwitch
 
 	case OPACK:
 		Yyerror("use of package %v without selector", Sconv(n.Sym, 0))
-		goto error
+		n.Type = nil
+		return
 
 	case ODDD:
 		break
@@ -377,14 +357,15 @@
 		ok |= Etype
 
 		if n.Type == nil {
-			goto error
+			n.Type = nil
+			return
 		}
 
 	case OTARRAY:
 		ok |= Etype
-		t = typ(TARRAY)
-		l = n.Left
-		r = n.Right
+		t := typ(TARRAY)
+		l := n.Left
+		r := n.Right
 		if l == nil {
 			t.Bound = -1 // slice
 		} else if l.Op == ODDD {
@@ -395,37 +376,41 @@
 				Yyerror("use of [...] array outside of array literal")
 			}
 		} else {
-			l = typecheck(&n.Left, Erv)
+			l := typecheck(&n.Left, Erv)
+			var v Val
 			switch consttype(l) {
-			case CTINT,
-				CTRUNE:
+			case CTINT, CTRUNE:
 				v = l.Val
 
 			case CTFLT:
 				v = toint(l.Val)
 
 			default:
-				if l.Type != nil && Isint[l.Type.Etype] != 0 && l.Op != OLITERAL {
+				if l.Type != nil && Isint[l.Type.Etype] && l.Op != OLITERAL {
 					Yyerror("non-constant array bound %v", Nconv(l, 0))
 				} else {
 					Yyerror("invalid array bound %v", Nconv(l, 0))
 				}
-				goto error
+				n.Type = nil
+				return
 			}
 
 			t.Bound = Mpgetfix(v.U.Xval)
 			if doesoverflow(v, Types[TINT]) {
 				Yyerror("array bound is too large")
-				goto error
+				n.Type = nil
+				return
 			} else if t.Bound < 0 {
 				Yyerror("array bound must be non-negative")
-				goto error
+				n.Type = nil
+				return
 			}
 		}
 
 		typecheck(&r, Etype)
 		if r.Type == nil {
-			goto error
+			n.Type = nil
+			return
 		}
 		t.Type = r.Type
 		n.Op = OTYPE
@@ -438,10 +423,11 @@
 
 	case OTMAP:
 		ok |= Etype
-		l = typecheck(&n.Left, Etype)
-		r = typecheck(&n.Right, Etype)
+		l := typecheck(&n.Left, Etype)
+		r := typecheck(&n.Right, Etype)
 		if l.Type == nil || r.Type == nil {
-			goto error
+			n.Type = nil
+			return
 		}
 		n.Op = OTYPE
 		n.Type = maptype(l.Type, r.Type)
@@ -450,11 +436,12 @@
 
 	case OTCHAN:
 		ok |= Etype
-		l = typecheck(&n.Left, Etype)
+		l := typecheck(&n.Left, Etype)
 		if l.Type == nil {
-			goto error
+			n.Type = nil
+			return
 		}
-		t = typ(TCHAN)
+		t := typ(TCHAN)
 		t.Type = l.Type
 		t.Chan = n.Etype
 		n.Op = OTYPE
@@ -467,7 +454,8 @@
 		n.Op = OTYPE
 		n.Type = tostruct(n.List)
 		if n.Type == nil || n.Type.Broke != 0 {
-			goto error
+			n.Type = nil
+			return
 		}
 		n.List = nil
 
@@ -476,7 +464,8 @@
 		n.Op = OTYPE
 		n.Type = tointerface(n.List)
 		if n.Type == nil {
-			goto error
+			n.Type = nil
+			return
 		}
 
 	case OTFUNC:
@@ -484,61 +473,53 @@
 		n.Op = OTYPE
 		n.Type = functype(n.Left, n.List, n.Rlist)
 		if n.Type == nil {
-			goto error
+			n.Type = nil
+			return
 		}
 
 		/*
 		 * type or expr
 		 */
 	case OIND:
-		ntop = Erv | Etype
+		ntop := Erv | Etype
 
-		if top&Eaddr == 0 {
+		if top&Eaddr == 0 { // The *x in &*x is not an indirect.
 			ntop |= Eindir
 		}
 		ntop |= top & Ecomplit
-		l = typecheck(&n.Left, ntop)
-		t = l.Type
+		l := typecheck(&n.Left, ntop)
+		t := l.Type
 		if t == nil {
-			goto error
+			n.Type = nil
+			return
 		}
 		if l.Op == OTYPE {
 			ok |= Etype
 			n.Op = OTYPE
 			n.Type = Ptrto(l.Type)
 			n.Left = nil
-			goto ret
+			break OpSwitch
 		}
 
-		if Isptr[t.Etype] == 0 {
+		if !Isptr[t.Etype] {
 			if top&(Erv|Etop) != 0 {
 				Yyerror("invalid indirect of %v", Nconv(n.Left, obj.FmtLong))
-				goto error
+				n.Type = nil
+				return
 			}
 
-			goto ret
+			break OpSwitch
 		}
 
 		ok |= Erv
 		n.Type = t.Type
-		goto ret
+		break OpSwitch
 
 		/*
 		 * arithmetic exprs
 		 */
-	case OASOP:
-		ok |= Etop
-
-		l = typecheck(&n.Left, Erv)
-		r = typecheck(&n.Right, Erv)
-		checkassign(n, n.Left)
-		if l.Type == nil || r.Type == nil {
-			goto error
-		}
-		op = int(n.Etype)
-		goto arith
-
-	case OADD,
+	case OASOP,
+		OADD,
 		OAND,
 		OANDAND,
 		OANDNOT,
@@ -557,32 +538,267 @@
 		OOROR,
 		OSUB,
 		OXOR:
-		ok |= Erv
-		l = typecheck(&n.Left, Erv|top&Eiota)
-		r = typecheck(&n.Right, Erv|top&Eiota)
-		if l.Type == nil || r.Type == nil {
-			goto error
+		var l *Node
+		var op int
+		var r *Node
+		if n.Op == OASOP {
+			ok |= Etop
+			l = typecheck(&n.Left, Erv)
+			r = typecheck(&n.Right, Erv)
+			checkassign(n, n.Left)
+			if l.Type == nil || r.Type == nil {
+				n.Type = nil
+				return
+			}
+			op = int(n.Etype)
+		} else {
+			ok |= Erv
+			l = typecheck(&n.Left, Erv|top&Eiota)
+			r = typecheck(&n.Right, Erv|top&Eiota)
+			if l.Type == nil || r.Type == nil {
+				n.Type = nil
+				return
+			}
+			op = int(n.Op)
 		}
-		op = int(n.Op)
-		goto arith
+		if op == OLSH || op == ORSH {
+			defaultlit(&r, Types[TUINT])
+			n.Right = r
+			t := r.Type
+			if !Isint[t.Etype] || Issigned[t.Etype] {
+				Yyerror("invalid operation: %v (shift count type %v, must be unsigned integer)", Nconv(n, 0), Tconv(r.Type, 0))
+				n.Type = nil
+				return
+			}
 
-	case OCOM,
-		OMINUS,
-		ONOT,
-		OPLUS:
-		ok |= Erv
-		l = typecheck(&n.Left, Erv|top&Eiota)
-		t = l.Type
-		if t == nil {
-			goto error
+			t = l.Type
+			if t != nil && t.Etype != TIDEAL && !Isint[t.Etype] {
+				Yyerror("invalid operation: %v (shift of type %v)", Nconv(n, 0), Tconv(t, 0))
+				n.Type = nil
+				return
+			}
+
+			// no defaultlit for left
+			// the outer context gives the type
+			n.Type = l.Type
+
+			break OpSwitch
 		}
-		if okfor[n.Op][t.Etype] == 0 {
-			Yyerror("invalid operation: %v %v", Oconv(int(n.Op), 0), Tconv(t, 0))
-			goto error
+
+		// ideal mixed with non-ideal
+		defaultlit2(&l, &r, 0)
+
+		n.Left = l
+		n.Right = r
+		if l.Type == nil || r.Type == nil {
+			n.Type = nil
+			return
+		}
+		t := l.Type
+		if t.Etype == TIDEAL {
+			t = r.Type
+		}
+		et := int(t.Etype)
+		if et == TIDEAL {
+			et = TINT
+		}
+		aop := 0
+		if iscmp[n.Op] && t.Etype != TIDEAL && !Eqtype(l.Type, r.Type) {
+			// comparison is okay as long as one side is
+			// assignable to the other.  convert so they have
+			// the same type.
+			//
+			// the only conversion that isn't a no-op is concrete == interface.
+			// in that case, check comparability of the concrete type.
+			// The conversion allocates, so only do it if the concrete type is huge.
+			if r.Type.Etype != TBLANK {
+				aop = assignop(l.Type, r.Type, nil)
+				if aop != 0 {
+					if Isinter(r.Type) && !Isinter(l.Type) && algtype1(l.Type, nil) == ANOEQ {
+						Yyerror("invalid operation: %v (operator %v not defined on %s)", Nconv(n, 0), Oconv(int(op), 0), typekind(l.Type))
+						n.Type = nil
+						return
+					}
+
+					dowidth(l.Type)
+					if Isinter(r.Type) == Isinter(l.Type) || l.Type.Width >= 1<<16 {
+						l = Nod(aop, l, nil)
+						l.Type = r.Type
+						l.Typecheck = 1
+						n.Left = l
+					}
+
+					t = r.Type
+					goto converted
+				}
+			}
+
+			if l.Type.Etype != TBLANK {
+				aop = assignop(r.Type, l.Type, nil)
+				if aop != 0 {
+					if Isinter(l.Type) && !Isinter(r.Type) && algtype1(r.Type, nil) == ANOEQ {
+						Yyerror("invalid operation: %v (operator %v not defined on %s)", Nconv(n, 0), Oconv(int(op), 0), typekind(r.Type))
+						n.Type = nil
+						return
+					}
+
+					dowidth(r.Type)
+					if Isinter(r.Type) == Isinter(l.Type) || r.Type.Width >= 1<<16 {
+						r = Nod(aop, r, nil)
+						r.Type = l.Type
+						r.Typecheck = 1
+						n.Right = r
+					}
+
+					t = l.Type
+				}
+			}
+
+		converted:
+			et = int(t.Etype)
+		}
+
+		if t.Etype != TIDEAL && !Eqtype(l.Type, r.Type) {
+			defaultlit2(&l, &r, 1)
+			if n.Op == OASOP && n.Implicit {
+				Yyerror("invalid operation: %v (non-numeric type %v)", Nconv(n, 0), Tconv(l.Type, 0))
+				n.Type = nil
+				return
+			}
+
+			if Isinter(r.Type) == Isinter(l.Type) || aop == 0 {
+				Yyerror("invalid operation: %v (mismatched types %v and %v)", Nconv(n, 0), Tconv(l.Type, 0), Tconv(r.Type, 0))
+				n.Type = nil
+				return
+			}
+		}
+
+		if !okfor[op][et] {
+			Yyerror("invalid operation: %v (operator %v not defined on %s)", Nconv(n, 0), Oconv(int(op), 0), typekind(t))
+			n.Type = nil
+			return
+		}
+
+		// okfor allows any array == array, map == map, func == func.
+		// restrict to slice/map/func == nil and nil == slice/map/func.
+		if Isfixedarray(l.Type) && algtype1(l.Type, nil) == ANOEQ {
+			Yyerror("invalid operation: %v (%v cannot be compared)", Nconv(n, 0), Tconv(l.Type, 0))
+			n.Type = nil
+			return
+		}
+
+		if Isslice(l.Type) && !isnil(l) && !isnil(r) {
+			Yyerror("invalid operation: %v (slice can only be compared to nil)", Nconv(n, 0))
+			n.Type = nil
+			return
+		}
+
+		if l.Type.Etype == TMAP && !isnil(l) && !isnil(r) {
+			Yyerror("invalid operation: %v (map can only be compared to nil)", Nconv(n, 0))
+			n.Type = nil
+			return
+		}
+
+		if l.Type.Etype == TFUNC && !isnil(l) && !isnil(r) {
+			Yyerror("invalid operation: %v (func can only be compared to nil)", Nconv(n, 0))
+			n.Type = nil
+			return
+		}
+
+		var badtype *Type
+		if l.Type.Etype == TSTRUCT && algtype1(l.Type, &badtype) == ANOEQ {
+			Yyerror("invalid operation: %v (struct containing %v cannot be compared)", Nconv(n, 0), Tconv(badtype, 0))
+			n.Type = nil
+			return
+		}
+
+		t = l.Type
+		if iscmp[n.Op] {
+			evconst(n)
+			t = idealbool
+			if n.Op != OLITERAL {
+				defaultlit2(&l, &r, 1)
+				n.Left = l
+				n.Right = r
+			}
+		} else if n.Op == OANDAND || n.Op == OOROR {
+			if l.Type == r.Type {
+				t = l.Type
+			} else if l.Type == idealbool {
+				t = r.Type
+			} else if r.Type == idealbool {
+				t = l.Type
+			}
+		} else
+		// non-comparison operators on ideal bools should make them lose their ideal-ness
+		if t == idealbool {
+			t = Types[TBOOL]
+		}
+
+		if et == TSTRING {
+			if iscmp[n.Op] {
+				n.Etype = n.Op
+				n.Op = OCMPSTR
+			} else if n.Op == OADD {
+				// create OADDSTR node with list of strings in x + y + z + (w + v) + ...
+				n.Op = OADDSTR
+
+				if l.Op == OADDSTR {
+					n.List = l.List
+				} else {
+					n.List = list1(l)
+				}
+				if r.Op == OADDSTR {
+					n.List = concat(n.List, r.List)
+				} else {
+					n.List = list(n.List, r)
+				}
+				n.Left = nil
+				n.Right = nil
+			}
+		}
+
+		if et == TINTER {
+			if l.Op == OLITERAL && l.Val.Ctype == CTNIL {
+				// swap for back end
+				n.Left = r
+
+				n.Right = l
+			} else if r.Op == OLITERAL && r.Val.Ctype == CTNIL {
+			} else // leave alone for back end
+			if Isinter(r.Type) == Isinter(l.Type) {
+				n.Etype = n.Op
+				n.Op = OCMPIFACE
+			}
+		}
+
+		if (op == ODIV || op == OMOD) && Isconst(r, CTINT) {
+			if mpcmpfixc(r.Val.U.Xval, 0) == 0 {
+				Yyerror("division by zero")
+				n.Type = nil
+				return
+			}
 		}
 
 		n.Type = t
-		goto ret
+		break OpSwitch
+
+	case OCOM, OMINUS, ONOT, OPLUS:
+		ok |= Erv
+		l := typecheck(&n.Left, Erv|top&Eiota)
+		t := l.Type
+		if t == nil {
+			n.Type = nil
+			return
+		}
+		if !okfor[n.Op][t.Etype] {
+			Yyerror("invalid operation: %v %v", Oconv(int(n.Op), 0), Tconv(t, 0))
+			n.Type = nil
+			return
+		}
+
+		n.Type = t
+		break OpSwitch
 
 		/*
 		 * exprs
@@ -592,66 +808,72 @@
 
 		typecheck(&n.Left, Erv|Eaddr)
 		if n.Left.Type == nil {
-			goto error
+			n.Type = nil
+			return
 		}
 		checklvalue(n.Left, "take the address of")
-		r = outervalue(n.Left)
+		r := outervalue(n.Left)
+		var l *Node
 		for l = n.Left; l != r; l = l.Left {
-			l.Addrtaken = 1
+			l.Addrtaken = true
 			if l.Closure != nil {
-				l.Closure.Addrtaken = 1
+				l.Closure.Addrtaken = true
 			}
 		}
 
 		if l.Orig != l && l.Op == ONAME {
 			Fatal("found non-orig name node %v", Nconv(l, 0))
 		}
-		l.Addrtaken = 1
+		l.Addrtaken = true
 		if l.Closure != nil {
-			l.Closure.Addrtaken = 1
+			l.Closure.Addrtaken = true
 		}
 		defaultlit(&n.Left, nil)
 		l = n.Left
-		t = l.Type
+		t := l.Type
 		if t == nil {
-			goto error
+			n.Type = nil
+			return
 		}
 		n.Type = Ptrto(t)
-		goto ret
+		break OpSwitch
 
 	case OCOMPLIT:
 		ok |= Erv
 		typecheckcomplit(&n)
 		if n.Type == nil {
-			goto error
+			n.Type = nil
+			return
 		}
-		goto ret
+		break OpSwitch
 
-	case OXDOT:
-		n = adddot(n)
-		n.Op = ODOT
-		if n.Left == nil {
-			goto error
+	case OXDOT, ODOT:
+		if n.Op == OXDOT {
+			n = adddot(n)
+			n.Op = ODOT
+			if n.Left == nil {
+				n.Type = nil
+				return
+			}
 		}
-		fallthrough
 
-		// fall through
-	case ODOT:
 		typecheck(&n.Left, Erv|Etype)
 
 		defaultlit(&n.Left, nil)
 		if n.Right.Op != ONAME {
 			Yyerror("rhs of . must be a name") // impossible
-			goto error
+			n.Type = nil
+			return
 		}
 
-		t = n.Left.Type
+		t := n.Left.Type
 		if t == nil {
 			adderrorname(n)
-			goto error
+			n.Type = nil
+			return
 		}
 
-		r = n.Right
+		r := n.Right
 
 		if n.Left.Op == OTYPE {
 			if !looktypedot(n, t, 0) {
@@ -660,13 +882,15 @@
 				} else {
 					Yyerror("%v undefined (type %v has no method %v)", Nconv(n, 0), Tconv(t, 0), Sconv(n.Right.Sym, 0))
 				}
-				goto error
+				n.Type = nil
+				return
 			}
 
 			if n.Type.Etype != TFUNC || n.Type.Thistuple != 1 {
 				Yyerror("type %v has no method %v", Tconv(n.Left.Type, 0), Sconv(n.Right.Sym, obj.FmtShort))
 				n.Type = nil
-				goto error
+				n.Type = nil
+				return
 			}
 
 			n.Op = ONAME
@@ -675,13 +899,14 @@
 			n.Xoffset = 0
 			n.Class = PFUNC
 			ok = Erv
-			goto ret
+			break OpSwitch
 		}
 
-		if Isptr[t.Etype] != 0 && t.Type.Etype != TINTER {
+		if Isptr[t.Etype] && t.Type.Etype != TINTER {
 			t = t.Type
 			if t == nil {
-				goto error
+				n.Type = nil
+				return
 			}
 			n.Op = ODOTPTR
 			checkwidth(t)
@@ -689,7 +914,8 @@
 
 		if isblank(n.Right) {
 			Yyerror("cannot refer to blank field or method")
-			goto error
+			n.Type = nil
+			return
 		}
 
 		if !lookdot(n, t, 0) {
@@ -698,12 +924,12 @@
 			} else {
 				Yyerror("%v undefined (type %v has no field or method %v)", Nconv(n, 0), Tconv(n.Left.Type, 0), Sconv(n.Right.Sym, 0))
 			}
-			goto error
+			n.Type = nil
+			return
 		}
 
 		switch n.Op {
-		case ODOTINTER,
-			ODOTMETH:
+		case ODOTINTER, ODOTMETH:
 			if top&Ecall != 0 {
 				ok |= Ecall
 			} else {
@@ -715,20 +941,22 @@
 			ok |= Erv
 		}
 
-		goto ret
+		break OpSwitch
 
 	case ODOTTYPE:
 		ok |= Erv
 		typecheck(&n.Left, Erv)
 		defaultlit(&n.Left, nil)
-		l = n.Left
-		t = l.Type
+		l := n.Left
+		t := l.Type
 		if t == nil {
-			goto error
+			n.Type = nil
+			return
 		}
 		if !Isinter(t) {
 			Yyerror("invalid type assertion: %v (non-interface type %v on left)", Nconv(n, 0), Tconv(t, 0))
-			goto error
+			n.Type = nil
+			return
 		}
 
 		if n.Right != nil {
@@ -736,11 +964,15 @@
 			n.Type = n.Right.Type
 			n.Right = nil
 			if n.Type == nil {
-				goto error
+				n.Type = nil
+				return
 			}
 		}
 
 		if n.Type != nil && n.Type.Etype != TINTER {
+			var have *Type
+			var missing *Type
+			var ptr int
 			if !implements(n.Type, t, &missing, &have, &ptr) {
 				if have != nil && have.Sym == missing.Sym {
 					Yyerror("impossible type assertion:\n\t%v does not implement %v (wrong type for %v method)\n"+"\t\thave %v%v\n\t\twant %v%v", Tconv(n.Type, 0), Tconv(t, 0), Sconv(missing.Sym, 0), Sconv(have.Sym, 0), Tconv(have.Type, obj.FmtShort|obj.FmtByte), Sconv(missing.Sym, 0), Tconv(missing.Type, obj.FmtShort|obj.FmtByte))
@@ -751,38 +983,40 @@
 				} else {
 					Yyerror("impossible type assertion:\n\t%v does not implement %v (missing %v method)", Tconv(n.Type, 0), Tconv(t, 0), Sconv(missing.Sym, 0))
 				}
-				goto error
+				n.Type = nil
+				return
 			}
 		}
 
-		goto ret
+		break OpSwitch
 
 	case OINDEX:
 		ok |= Erv
 		typecheck(&n.Left, Erv)
 		defaultlit(&n.Left, nil)
 		implicitstar(&n.Left)
-		l = n.Left
+		l := n.Left
 		typecheck(&n.Right, Erv)
-		r = n.Right
-		t = l.Type
+		r := n.Right
+		t := l.Type
 		if t == nil || r.Type == nil {
-			goto error
+			n.Type = nil
+			return
 		}
 		switch t.Etype {
 		default:
 			Yyerror("invalid operation: %v (type %v does not support indexing)", Nconv(n, 0), Tconv(t, 0))
-			goto error
+			n.Type = nil
+			return
 
-		case TSTRING,
-			TARRAY:
+		case TSTRING, TARRAY:
 			indexlit(&n.Right)
 			if t.Etype == TSTRING {
 				n.Type = Types[TUINT8]
 			} else {
 				n.Type = t.Type
 			}
-			why = "string"
+			why := "string"
 			if t.Etype == TARRAY {
 				if Isfixedarray(t) {
 					why = "array"
@@ -791,19 +1025,19 @@
 				}
 			}
 
-			if n.Right.Type != nil && Isint[n.Right.Type.Etype] == 0 {
+			if n.Right.Type != nil && !Isint[n.Right.Type.Etype] {
 				Yyerror("non-integer %s index %v", why, Nconv(n.Right, 0))
 				break
 			}
 
 			if Isconst(n.Right, CTINT) {
-				x = Mpgetfix(n.Right.Val.U.Xval)
+				x := Mpgetfix(n.Right.Val.U.Xval)
 				if x < 0 {
 					Yyerror("invalid %s index %v (index must be non-negative)", why, Nconv(n.Right, 0))
 				} else if Isfixedarray(t) && t.Bound > 0 && x >= t.Bound {
 					Yyerror("invalid array index %v (out of bounds for %d-element array)", Nconv(n.Right, 0), t.Bound)
-				} else if Isconst(n.Left, CTSTR) && x >= int64(len(n.Left.Val.U.Sval.S)) {
-					Yyerror("invalid string index %v (out of bounds for %d-byte string)", Nconv(n.Right, 0), len(n.Left.Val.U.Sval.S))
+				} else if Isconst(n.Left, CTSTR) && x >= int64(len(n.Left.Val.U.Sval)) {
+					Yyerror("invalid string index %v (out of bounds for %d-byte string)", Nconv(n.Right, 0), len(n.Left.Val.U.Sval))
 				} else if Mpcmpfixfix(n.Right.Val.U.Xval, Maxintval[TINT]) > 0 {
 					Yyerror("invalid %s index %v (index too large)", why, Nconv(n.Right, 0))
 				}
@@ -819,54 +1053,61 @@
 			n.Op = OINDEXMAP
 		}
 
-		goto ret
+		break OpSwitch
 
 	case ORECV:
 		ok |= Etop | Erv
 		typecheck(&n.Left, Erv)
 		defaultlit(&n.Left, nil)
-		l = n.Left
-		t = l.Type
+		l := n.Left
+		t := l.Type
 		if t == nil {
-			goto error
+			n.Type = nil
+			return
 		}
 		if t.Etype != TCHAN {
 			Yyerror("invalid operation: %v (receive from non-chan type %v)", Nconv(n, 0), Tconv(t, 0))
-			goto error
+			n.Type = nil
+			return
 		}
 
 		if t.Chan&Crecv == 0 {
 			Yyerror("invalid operation: %v (receive from send-only type %v)", Nconv(n, 0), Tconv(t, 0))
-			goto error
+			n.Type = nil
+			return
 		}
 
 		n.Type = t.Type
-		goto ret
+		break OpSwitch
 
 	case OSEND:
 		ok |= Etop
-		l = typecheck(&n.Left, Erv)
+		l := typecheck(&n.Left, Erv)
 		typecheck(&n.Right, Erv)
 		defaultlit(&n.Left, nil)
 		l = n.Left
-		t = l.Type
+		t := l.Type
 		if t == nil {
-			goto error
+			n.Type = nil
+			return
 		}
 		if t.Etype != TCHAN {
 			Yyerror("invalid operation: %v (send to non-chan type %v)", Nconv(n, 0), Tconv(t, 0))
-			goto error
+			n.Type = nil
+			return
 		}
 
 		if t.Chan&Csend == 0 {
 			Yyerror("invalid operation: %v (send to receive-only type %v)", Nconv(n, 0), Tconv(t, 0))
-			goto error
+			n.Type = nil
+			return
 		}
 
 		defaultlit(&n.Right, t.Type)
-		r = n.Right
+		r := n.Right
 		if r.Type == nil {
-			goto error
+			n.Type = nil
+			return
 		}
 		n.Right = assignconv(r, l.Type.Type, "send")
 
@@ -874,7 +1115,7 @@
 		n.Etype = 0
 
 		n.Type = nil
-		goto ret
+		break OpSwitch
 
 	case OSLICE:
 		ok |= Erv
@@ -884,28 +1125,30 @@
 		defaultlit(&n.Left, nil)
 		indexlit(&n.Right.Left)
 		indexlit(&n.Right.Right)
-		l = n.Left
+		l := n.Left
 		if Isfixedarray(l.Type) {
 			if !islvalue(n.Left) {
 				Yyerror("invalid operation %v (slice of unaddressable value)", Nconv(n, 0))
-				goto error
+				n.Type = nil
+				return
 			}
 
 			n.Left = Nod(OADDR, n.Left, nil)
-			n.Left.Implicit = 1
+			n.Left.Implicit = true
 			typecheck(&n.Left, Erv)
 			l = n.Left
 		}
 
-		t = l.Type
+		t := l.Type
 		if t == nil {
-			goto error
+			n.Type = nil
+			return
 		}
-		tp = nil
+		var tp *Type
 		if Istype(t, TSTRING) {
 			n.Type = t
 			n.Op = OSLICESTR
-		} else if Isptr[t.Etype] != 0 && Isfixedarray(t.Type) {
+		} else if Isptr[t.Etype] && Isfixedarray(t.Type) {
 			tp = t.Type
 			n.Type = typ(TARRAY)
 			n.Type.Type = tp.Type
@@ -916,21 +1159,25 @@
 			n.Type = t
 		} else {
 			Yyerror("cannot slice %v (type %v)", Nconv(l, 0), Tconv(t, 0))
-			goto error
+			n.Type = nil
+			return
 		}
 
-		lo = n.Right.Left
+		lo := n.Right.Left
 		if lo != nil && checksliceindex(l, lo, tp) < 0 {
-			goto error
+			n.Type = nil
+			return
 		}
-		hi = n.Right.Right
+		hi := n.Right.Right
 		if hi != nil && checksliceindex(l, hi, tp) < 0 {
-			goto error
+			n.Type = nil
+			return
 		}
 		if checksliceconst(lo, hi) < 0 {
-			goto error
+			n.Type = nil
+			return
 		}
-		goto ret
+		break OpSwitch
 
 	case OSLICE3:
 		ok |= Erv
@@ -942,30 +1189,33 @@
 		indexlit(&n.Right.Left)
 		indexlit(&n.Right.Right.Left)
 		indexlit(&n.Right.Right.Right)
-		l = n.Left
+		l := n.Left
 		if Isfixedarray(l.Type) {
 			if !islvalue(n.Left) {
 				Yyerror("invalid operation %v (slice of unaddressable value)", Nconv(n, 0))
-				goto error
+				n.Type = nil
+				return
 			}
 
 			n.Left = Nod(OADDR, n.Left, nil)
-			n.Left.Implicit = 1
+			n.Left.Implicit = true
 			typecheck(&n.Left, Erv)
 			l = n.Left
 		}
 
-		t = l.Type
+		t := l.Type
 		if t == nil {
-			goto error
+			n.Type = nil
+			return
 		}
-		tp = nil
 		if Istype(t, TSTRING) {
 			Yyerror("invalid operation %v (3-index slice of string)", Nconv(n, 0))
-			goto error
+			n.Type = nil
+			return
 		}
 
-		if Isptr[t.Etype] != 0 && Isfixedarray(t.Type) {
+		var tp *Type
+		if Isptr[t.Etype] && Isfixedarray(t.Type) {
 			tp = t.Type
 			n.Type = typ(TARRAY)
 			n.Type.Type = tp.Type
@@ -976,40 +1226,46 @@
 			n.Type = t
 		} else {
 			Yyerror("cannot slice %v (type %v)", Nconv(l, 0), Tconv(t, 0))
-			goto error
+			n.Type = nil
+			return
 		}
 
-		lo = n.Right.Left
+		lo := n.Right.Left
 		if lo != nil && checksliceindex(l, lo, tp) < 0 {
-			goto error
+			n.Type = nil
+			return
 		}
-		mid = n.Right.Right.Left
+		mid := n.Right.Right.Left
 		if mid != nil && checksliceindex(l, mid, tp) < 0 {
-			goto error
+			n.Type = nil
+			return
 		}
-		hi = n.Right.Right.Right
+		hi := n.Right.Right.Right
 		if hi != nil && checksliceindex(l, hi, tp) < 0 {
-			goto error
+			n.Type = nil
+			return
 		}
 		if checksliceconst(lo, hi) < 0 || checksliceconst(lo, mid) < 0 || checksliceconst(mid, hi) < 0 {
-			goto error
+			n.Type = nil
+			return
 		}
-		goto ret
+		break OpSwitch
 
 		/*
 		 * call and call like
 		 */
 	case OCALL:
-		l = n.Left
+		l := n.Left
 
 		if l.Op == ONAME {
-			r = unsafenmagic(n)
+			r := unsafenmagic(n)
 			if r != nil {
-				if n.Isddd != 0 {
+				if n.Isddd {
 					Yyerror("invalid use of ... with builtin %v", Nconv(l, 0))
 				}
 				n = r
-				goto reswitch
+				typecheck1(&n, top)
+				return
 			}
 		}
 
@@ -1017,7 +1273,7 @@
 		n.Diag |= n.Left.Diag
 		l = n.Left
 		if l.Op == ONAME && l.Etype != 0 {
-			if n.Isddd != 0 && l.Etype != OAPPEND {
+			if n.Isddd && l.Etype != OAPPEND {
 				Yyerror("invalid use of ... with builtin %v", Nconv(l, 0))
 			}
 
@@ -1026,13 +1282,14 @@
 
 			n.Left = n.Right
 			n.Right = nil
-			goto reswitch
+			typecheck1(&n, top)
+			return
 		}
 
 		defaultlit(&n.Left, nil)
-		l := n.Left
+		l = n.Left
 		if l.Op == OTYPE {
-			if n.Isddd != 0 || l.Type.Bound == -100 {
+			if n.Isddd || l.Type.Bound == -100 {
 				if l.Type.Broke == 0 {
 					Yyerror("invalid use of ... in type conversion", l)
 				}
@@ -1048,19 +1305,22 @@
 			n.Op = OCONV
 			n.Type = l.Type
 			if onearg(n, "conversion to %v", Tconv(l.Type, 0)) < 0 {
-				goto error
+				n.Type = nil
+				return
 			}
-			goto doconv
+			typecheck1(&n, top)
+			return
 		}
 
-		if count(n.List) == 1 && n.Isddd == 0 {
+		if count(n.List) == 1 && !n.Isddd {
 			typecheck(&n.List.N, Erv|Efnstruct)
 		} else {
 			typechecklist(n.List, Erv)
 		}
 		t := l.Type
 		if t == nil {
-			goto error
+			n.Type = nil
+			return
 		}
 		checkwidth(t)
 
@@ -1085,46 +1345,44 @@
 			n.Op = OCALLFUNC
 			if t.Etype != TFUNC {
 				Yyerror("cannot call non-function %v (type %v)", Nconv(l, 0), Tconv(t, 0))
-				goto error
+				n.Type = nil
+				return
 			}
 		}
 
-		descbuf := fmt.Sprintf("argument to %v", Nconv(n.Left, 0))
-		desc := descbuf
-		typecheckaste(OCALL, n.Left, int(n.Isddd), getinargx(t), n.List, desc)
+		typecheckaste(OCALL, n.Left, n.Isddd, getinargx(t), n.List, func() string { return fmt.Sprintf("argument to %v", Nconv(n.Left, 0)) })
 		ok |= Etop
 		if t.Outtuple == 0 {
-			goto ret
+			break OpSwitch
 		}
 		ok |= Erv
 		if t.Outtuple == 1 {
 			t := getoutargx(l.Type).Type
 			if t == nil {
-				goto error
+				n.Type = nil
+				return
 			}
 			if t.Etype == TFIELD {
 				t = t.Type
 			}
 			n.Type = t
-			goto ret
+			break OpSwitch
 		}
 
 		// multiple return
 		if top&(Efnstruct|Etop) == 0 {
 			Yyerror("multiple-value %v() in single-value context", Nconv(l, 0))
-			goto ret
+			break OpSwitch
 		}
 
 		n.Type = getoutargx(l.Type)
-		goto ret
+		break OpSwitch
 
-	case OCAP,
-		OLEN,
-		OREAL,
-		OIMAG:
+	case OCAP, OLEN, OREAL, OIMAG:
 		ok |= Erv
 		if onearg(n, "%v", Oconv(int(n.Op), 0)) < 0 {
-			goto error
+			n.Type = nil
+			return
 		}
 		typecheck(&n.Left, Erv)
 		defaultlit(&n.Left, nil)
@@ -1132,22 +1390,22 @@
 		l := n.Left
 		t := l.Type
 		if t == nil {
-			goto error
+			n.Type = nil
+			return
 		}
 		switch n.Op {
 		case OCAP:
-			if okforcap[t.Etype] == 0 {
+			if !okforcap[t.Etype] {
 				goto badcall1
 			}
 
 		case OLEN:
-			if okforlen[t.Etype] == 0 {
+			if !okforlen[t.Etype] {
 				goto badcall1
 			}
 
-		case OREAL,
-			OIMAG:
-			if Iscomplex[t.Etype] == 0 {
+		case OREAL, OIMAG:
+			if !Iscomplex[t.Etype] {
 				goto badcall1
 			}
 			if Isconst(l, CTCPLX) {
@@ -1161,7 +1419,7 @@
 			}
 
 			n.Type = Types[cplxsubtype(int(t.Etype))]
-			goto ret
+			break OpSwitch
 		}
 
 		// might be constant
@@ -1169,7 +1427,7 @@
 		case TSTRING:
 			if Isconst(l, CTSTR) {
 				r := Nod(OXXX, nil, nil)
-				Nodconst(r, Types[TINT], int64(len(l.Val.U.Sval.S)))
+				Nodconst(r, Types[TINT], int64(len(l.Val.U.Sval)))
 				r.Orig = n
 				n = r
 			}
@@ -1188,7 +1446,12 @@
 		}
 
 		n.Type = Types[TINT]
-		goto ret
+		break OpSwitch
+
+	badcall1:
+		Yyerror("invalid argument %v for %v", Nconv(n.Left, obj.FmtLong), Oconv(int(n.Op), 0))
+		n.Type = nil
+		return
 
 	case OCOMPLEX:
 		ok |= Erv
@@ -1198,13 +1461,15 @@
 			typechecklist(n.List, Efnstruct)
 			if n.List.N.Op != OCALLFUNC && n.List.N.Op != OCALLMETH {
 				Yyerror("invalid operation: complex expects two arguments")
-				goto error
+				n.Type = nil
+				return
 			}
 
 			t := n.List.N.Left.Type
 			if t.Outtuple != 2 {
 				Yyerror("invalid operation: complex expects two arguments, %v returns %d results", Nconv(n.List.N, 0), t.Outtuple)
-				goto error
+				n.Type = nil
+				return
 			}
 
 			t = n.List.N.Type.Type
@@ -1212,16 +1477,19 @@
 			r = t.Down.Nname
 		} else {
 			if twoarg(n) < 0 {
-				goto error
+				n.Type = nil
+				return
 			}
 			l = typecheck(&n.Left, Erv|top&Eiota)
 			r = typecheck(&n.Right, Erv|top&Eiota)
 			if l.Type == nil || r.Type == nil {
-				goto error
+				n.Type = nil
+				return
 			}
 			defaultlit2(&l, &r, 0)
 			if l.Type == nil || r.Type == nil {
-				goto error
+				n.Type = nil
+				return
 			}
 			n.Left = l
 			n.Right = r
@@ -1229,14 +1497,16 @@
 
 		if !Eqtype(l.Type, r.Type) {
 			Yyerror("invalid operation: %v (mismatched types %v and %v)", Nconv(n, 0), Tconv(l.Type, 0), Tconv(r.Type, 0))
-			goto error
+			n.Type = nil
+			return
 		}
 
 		var t *Type
 		switch l.Type.Etype {
 		default:
 			Yyerror("invalid operation: %v (arguments have type %v, expected floating-point)", Nconv(n, 0), Tconv(l.Type, 0), r.Type)
-			goto error
+			n.Type = nil
+			return
 
 		case TIDEAL:
 			t = Types[TIDEAL]
@@ -1257,47 +1527,54 @@
 		}
 
 		n.Type = t
-		goto ret
+		break OpSwitch
 
 	case OCLOSE:
 		if onearg(n, "%v", Oconv(int(n.Op), 0)) < 0 {
-			goto error
+			n.Type = nil
+			return
 		}
 		typecheck(&n.Left, Erv)
 		defaultlit(&n.Left, nil)
 		l := n.Left
 		t := l.Type
 		if t == nil {
-			goto error
+			n.Type = nil
+			return
 		}
 		if t.Etype != TCHAN {
 			Yyerror("invalid operation: %v (non-chan type %v)", Nconv(n, 0), Tconv(t, 0))
-			goto error
+			n.Type = nil
+			return
 		}
 
 		if t.Chan&Csend == 0 {
 			Yyerror("invalid operation: %v (cannot close receive-only channel)", Nconv(n, 0))
-			goto error
+			n.Type = nil
+			return
 		}
 
 		ok |= Etop
-		goto ret
+		break OpSwitch
 
 	case ODELETE:
 		args := n.List
 		if args == nil {
 			Yyerror("missing arguments to delete")
-			goto error
+			n.Type = nil
+			return
 		}
 
 		if args.Next == nil {
 			Yyerror("missing second (key) argument to delete")
-			goto error
+			n.Type = nil
+			return
 		}
 
 		if args.Next.Next != nil {
 			Yyerror("too many arguments to delete")
-			goto error
+			n.Type = nil
+			return
 		}
 
 		ok |= Etop
@@ -1306,21 +1583,23 @@
 		r := args.Next.N
 		if l.Type != nil && l.Type.Etype != TMAP {
 			Yyerror("first argument to delete must be map; have %v", Tconv(l.Type, obj.FmtLong))
-			goto error
+			n.Type = nil
+			return
 		}
 
 		args.Next.N = assignconv(r, l.Type.Down, "delete")
-		goto ret
+		break OpSwitch
 
 	case OAPPEND:
 		ok |= Erv
 		args := n.List
 		if args == nil {
 			Yyerror("missing arguments to append")
-			goto error
+			n.Type = nil
+			return
 		}
 
-		if count(args) == 1 && n.Isddd == 0 {
+		if count(args) == 1 && !n.Isddd {
 			typecheck(&args.N, Erv|Efnstruct)
 		} else {
 			typechecklist(args, Erv)
@@ -1328,7 +1607,8 @@
 
 		t := args.N.Type
 		if t == nil {
-			goto error
+			n.Type = nil
+			return
 		}
 
 		// Unpack multiple-return result before type-checking.
@@ -1343,31 +1623,35 @@
 		if !Isslice(t) {
 			if Isconst(args.N, CTNIL) {
 				Yyerror("first argument to append must be typed slice; have untyped nil", t)
-				goto error
+				n.Type = nil
+				return
 			}
 
 			Yyerror("first argument to append must be slice; have %v", Tconv(t, obj.FmtLong))
-			goto error
+			n.Type = nil
+			return
 		}
 
-		if n.Isddd != 0 {
+		if n.Isddd {
 			if args.Next == nil {
 				Yyerror("cannot use ... on first argument to append")
-				goto error
+				n.Type = nil
+				return
 			}
 
 			if args.Next.Next != nil {
 				Yyerror("too many arguments to append")
-				goto error
+				n.Type = nil
+				return
 			}
 
 			if Istype(t.Type, TUINT8) && Istype(args.Next.N.Type, TSTRING) {
 				defaultlit(&args.Next.N, Types[TSTRING])
-				goto ret
+				break OpSwitch
 			}
 
 			args.Next.N = assignconv(args.Next.N, t.Orig, "append")
-			goto ret
+			break OpSwitch
 		}
 
 		for args = args.Next; args != nil; args = args.Next {
@@ -1377,19 +1661,21 @@
 			args.N = assignconv(args.N, t.Type, "append")
 		}
 
-		goto ret
+		break OpSwitch
 
 	case OCOPY:
 		ok |= Etop | Erv
 		args := n.List
 		if args == nil || args.Next == nil {
 			Yyerror("missing arguments to copy")
-			goto error
+			n.Type = nil
+			return
 		}
 
 		if args.Next.Next != nil {
 			Yyerror("too many arguments to copy")
-			goto error
+			n.Type = nil
+			return
 		}
 
 		n.Left = args.N
@@ -1399,21 +1685,24 @@
 		typecheck(&n.Left, Erv)
 		typecheck(&n.Right, Erv)
 		if n.Left.Type == nil || n.Right.Type == nil {
-			goto error
+			n.Type = nil
+			return
 		}
 		defaultlit(&n.Left, nil)
 		defaultlit(&n.Right, nil)
 		if n.Left.Type == nil || n.Right.Type == nil {
-			goto error
+			n.Type = nil
+			return
 		}
 
 		// copy([]byte, string)
 		if Isslice(n.Left.Type) && n.Right.Type.Etype == TSTRING {
 			if Eqtype(n.Left.Type.Type, bytetype) {
-				goto ret
+				break OpSwitch
 			}
 			Yyerror("arguments to copy have different element types: %v and string", Tconv(n.Left.Type, obj.FmtLong))
-			goto error
+			n.Type = nil
+			return
 		}
 
 		if !Isslice(n.Left.Type) || !Isslice(n.Right.Type) {
@@ -1424,25 +1713,73 @@
 			} else {
 				Yyerror("second argument to copy should be slice or string; have %v", Tconv(n.Right.Type, obj.FmtLong))
 			}
-			goto error
+			n.Type = nil
+			return
 		}
 
 		if !Eqtype(n.Left.Type.Type, n.Right.Type.Type) {
 			Yyerror("arguments to copy have different element types: %v and %v", Tconv(n.Left.Type, obj.FmtLong), Tconv(n.Right.Type, obj.FmtLong))
-			goto error
+			n.Type = nil
+			return
 		}
 
-		goto ret
+		break OpSwitch
 
 	case OCONV:
-		goto doconv
+		{
+			ok |= Erv
+			saveorignode(n)
+			typecheck(&n.Left, Erv|top&(Eindir|Eiota))
+			convlit1(&n.Left, n.Type, true)
+			t := n.Left.Type
+			if t == nil || n.Type == nil {
+				n.Type = nil
+				return
+			}
+			var why string
+			n.Op = uint8(convertop(t, n.Type, &why))
+			if (n.Op) == 0 {
+				if n.Diag == 0 && n.Type.Broke == 0 {
+					Yyerror("cannot convert %v to type %v%s", Nconv(n.Left, obj.FmtLong), Tconv(n.Type, 0), why)
+					n.Diag = 1
+				}
+
+				n.Op = OCONV
+			}
+
+			switch n.Op {
+			case OCONVNOP:
+				if n.Left.Op == OLITERAL && n.Type != Types[TBOOL] {
+					r := Nod(OXXX, nil, nil)
+					n.Op = OCONV
+					n.Orig = r
+					*r = *n
+					n.Op = OLITERAL
+					n.Val = n.Left.Val
+				}
+
+				// do not use stringtoarraylit.
+			// generated code and compiler memory footprint is better without it.
+			case OSTRARRAYBYTE:
+				break
+
+			case OSTRARRAYRUNE:
+				if n.Left.Op == OLITERAL {
+					stringtoarraylit(&n)
+				}
+			}
+
+			break OpSwitch
+		}
+		break OpSwitch
 
 	case OMAKE:
 		ok |= Erv
 		args := n.List
 		if args == nil {
 			Yyerror("missing argument to make")
-			goto error
+			n.Type = nil
+			return
 		}
 
 		n.List = nil
@@ -1451,29 +1788,33 @@
 		typecheck(&l, Etype)
 		t := l.Type
 		if t == nil {
-			goto error
+			n.Type = nil
+			return
 		}
 
 		switch t.Etype {
 		default:
 			Yyerror("cannot make type %v", Tconv(t, 0))
-			goto error
+			n.Type = nil
+			return
 
 		case TARRAY:
 			if !Isslice(t) {
 				Yyerror("cannot make type %v", Tconv(t, 0))
-				goto error
+				n.Type = nil
+				return
 			}
 
 			if args == nil {
 				Yyerror("missing len argument to make(%v)", Tconv(t, 0))
-				goto error
+				n.Type = nil
+				return
 			}
 
 			l = args.N
 			args = args.Next
 			typecheck(&l, Erv)
-			r := (*Node)(nil)
+			var r *Node
 			if args != nil {
 				r = args.N
 				args = args.Next
@@ -1481,16 +1822,19 @@
 			}
 
 			if l.Type == nil || (r != nil && r.Type == nil) {
-				goto error
+				n.Type = nil
+				return
 			}
 			et := bool2int(checkmake(t, "len", l) < 0)
 			et |= bool2int(r != nil && checkmake(t, "cap", r) < 0)
 			if et != 0 {
-				goto error
+				n.Type = nil
+				return
 			}
 			if Isconst(l, CTINT) && r != nil && Isconst(r, CTINT) && Mpcmpfixfix(l.Val.U.Xval, r.Val.U.Xval) > 0 {
 				Yyerror("len larger than cap in make(%v)", Tconv(t, 0))
-				goto error
+				n.Type = nil
+				return
 			}
 
 			n.Left = l
@@ -1504,10 +1848,12 @@
 				typecheck(&l, Erv)
 				defaultlit(&l, Types[TINT])
 				if l.Type == nil {
-					goto error
+					n.Type = nil
+					return
 				}
 				if checkmake(t, "size", l) < 0 {
-					goto error
+					n.Type = nil
+					return
 				}
 				n.Left = l
 			} else {
@@ -1523,10 +1869,12 @@
 				typecheck(&l, Erv)
 				defaultlit(&l, Types[TINT])
 				if l.Type == nil {
-					goto error
+					n.Type = nil
+					return
 				}
 				if checkmake(t, "buffer", l) < 0 {
-					goto error
+					n.Type = nil
+					return
 				}
 				n.Left = l
 			} else {
@@ -1538,37 +1886,40 @@
 		if args != nil {
 			Yyerror("too many arguments to make(%v)", Tconv(t, 0))
 			n.Op = OMAKE
-			goto error
+			n.Type = nil
+			return
 		}
 
 		n.Type = t
-		goto ret
+		break OpSwitch
 
 	case ONEW:
 		ok |= Erv
 		args := n.List
 		if args == nil {
 			Yyerror("missing argument to new")
-			goto error
+			n.Type = nil
+			return
 		}
 
 		l := args.N
 		typecheck(&l, Etype)
 		t := l.Type
 		if t == nil {
-			goto error
+			n.Type = nil
+			return
 		}
 		if args.Next != nil {
 			Yyerror("too many arguments to new(%v)", Tconv(t, 0))
-			goto error
+			n.Type = nil
+			return
 		}
 
 		n.Left = l
 		n.Type = Ptrto(t)
-		goto ret
+		break OpSwitch
 
-	case OPRINT,
-		OPRINTN:
+	case OPRINT, OPRINTN:
 		ok |= Etop
 		typechecklist(n.List, Erv|Eindir) // Eindir: address does not escape
 		for args := n.List; args != nil; args = args.Next {
@@ -1580,57 +1931,63 @@
 			}
 		}
 
-		goto ret
+		break OpSwitch
 
 	case OPANIC:
 		ok |= Etop
 		if onearg(n, "panic") < 0 {
-			goto error
+			n.Type = nil
+			return
 		}
 		typecheck(&n.Left, Erv)
 		defaultlit(&n.Left, Types[TINTER])
 		if n.Left.Type == nil {
-			goto error
+			n.Type = nil
+			return
 		}
-		goto ret
+		break OpSwitch
 
 	case ORECOVER:
 		ok |= Erv | Etop
 		if n.List != nil {
 			Yyerror("too many arguments to recover")
-			goto error
+			n.Type = nil
+			return
 		}
 
 		n.Type = Types[TINTER]
-		goto ret
+		break OpSwitch
 
 	case OCLOSURE:
 		ok |= Erv
 		typecheckclosure(n, top)
 		if n.Type == nil {
-			goto error
+			n.Type = nil
+			return
 		}
-		goto ret
+		break OpSwitch
 
 	case OITAB:
 		ok |= Erv
 		typecheck(&n.Left, Erv)
 		t := n.Left.Type
 		if t == nil {
-			goto error
+			n.Type = nil
+			return
 		}
 		if t.Etype != TINTER {
 			Fatal("OITAB of %v", Tconv(t, 0))
 		}
 		n.Type = Ptrto(Types[TUINTPTR])
-		goto ret
+		break OpSwitch
 
 	case OSPTR:
 		ok |= Erv
 		typecheck(&n.Left, Erv)
 		t := n.Left.Type
 		if t == nil {
-			goto error
+			n.Type = nil
+			return
 		}
 		if !Isslice(t) && t.Etype != TSTRING {
 			Fatal("OSPTR of %v", Tconv(t, 0))
@@ -1640,22 +1997,22 @@
 		} else {
 			n.Type = Ptrto(t.Type)
 		}
-		goto ret
+		break OpSwitch
 
 	case OCLOSUREVAR:
 		ok |= Erv
-		goto ret
+		break OpSwitch
 
 	case OCFUNC:
 		ok |= Erv
 		typecheck(&n.Left, Erv)
 		n.Type = Types[TUINTPTR]
-		goto ret
+		break OpSwitch
 
 	case OCONVNOP:
 		ok |= Erv
 		typecheck(&n.Left, Erv)
-		goto ret
+		break OpSwitch
 
 		/*
 		 * statements
@@ -1669,12 +2026,12 @@
 		if n.Left.Op == ONAME && strings.HasPrefix(n.Left.Sym.Name, "autotmp_") {
 			n.Left.Defn = n
 		}
-		goto ret
+		break OpSwitch
 
 	case OAS2:
 		ok |= Etop
 		typecheckas2(n)
-		goto ret
+		break OpSwitch
 
 	case OBREAK,
 		OCONTINUE,
@@ -1684,12 +2041,12 @@
 		OXFALL,
 		OVARKILL:
 		ok |= Etop
-		goto ret
+		break OpSwitch
 
 	case OLABEL:
 		ok |= Etop
 		decldepth++
-		goto ret
+		break OpSwitch
 
 	case ODEFER:
 		ok |= Etop
@@ -1697,13 +2054,13 @@
 		if n.Left.Diag == 0 {
 			checkdefergo(n)
 		}
-		goto ret
+		break OpSwitch
 
 	case OPROC:
 		ok |= Etop
 		typecheck(&n.Left, Etop|Eproc|Erv)
 		checkdefergo(n)
-		goto ret
+		break OpSwitch
 
 	case OFOR:
 		ok |= Etop
@@ -1719,7 +2076,7 @@
 		typecheck(&n.Nincr, Etop)
 		typechecklist(n.Nbody, Etop)
 		decldepth--
-		goto ret
+		break OpSwitch
 
 	case OIF:
 		ok |= Etop
@@ -1733,7 +2090,7 @@
 		}
 		typechecklist(n.Nbody, Etop)
 		typechecklist(n.Nelse, Etop)
-		goto ret
+		break OpSwitch
 
 	case ORETURN:
 		ok |= Etop
@@ -1744,53 +2101,55 @@
 		}
 		if Curfn == nil {
 			Yyerror("return outside function")
-			goto error
+			n.Type = nil
+			return
 		}
 
 		if Curfn.Type.Outnamed != 0 && n.List == nil {
-			goto ret
+			break OpSwitch
 		}
-		typecheckaste(ORETURN, nil, 0, getoutargx(Curfn.Type), n.List, "return argument")
-		goto ret
+		typecheckaste(ORETURN, nil, false, getoutargx(Curfn.Type), n.List, func() string { return "return argument" })
+		break OpSwitch
 
 	case ORETJMP:
 		ok |= Etop
-		goto ret
+		break OpSwitch
 
 	case OSELECT:
 		ok |= Etop
 		typecheckselect(n)
-		goto ret
+		break OpSwitch
 
 	case OSWITCH:
 		ok |= Etop
 		typecheckswitch(n)
-		goto ret
+		break OpSwitch
 
 	case ORANGE:
 		ok |= Etop
 		typecheckrange(n)
-		goto ret
+		break OpSwitch
 
 	case OTYPESW:
 		Yyerror("use of .(type) outside type switch")
-		goto error
+		n.Type = nil
+		return
 
 	case OXCASE:
 		ok |= Etop
 		typechecklist(n.List, Erv)
 		typechecklist(n.Nbody, Etop)
-		goto ret
+		break OpSwitch
 
 	case ODCLFUNC:
 		ok |= Etop
 		typecheckfunc(n)
-		goto ret
+		break OpSwitch
 
 	case ODCLCONST:
 		ok |= Etop
 		typecheck(&n.Left, Erv)
-		goto ret
+		break OpSwitch
 
 	case ODCLTYPE:
 		ok |= Etop
@@ -1798,267 +2157,10 @@
 		if incannedimport == 0 {
 			checkwidth(n.Left.Type)
 		}
-		goto ret
+		break OpSwitch
 	}
 
-	goto ret
-
-arith:
-	if op == OLSH || op == ORSH {
-		goto shift
-	}
-
-	// ideal mixed with non-ideal
-	defaultlit2(&l, &r, 0)
-
-	n.Left = l
-	n.Right = r
-	if l.Type == nil || r.Type == nil {
-		goto error
-	}
-	t = l.Type
-	if t.Etype == TIDEAL {
-		t = r.Type
-	}
-	et = int(t.Etype)
-	if et == TIDEAL {
-		et = TINT
-	}
-	aop = 0
-	if iscmp[n.Op] != 0 && t.Etype != TIDEAL && !Eqtype(l.Type, r.Type) {
-		// comparison is okay as long as one side is
-		// assignable to the other.  convert so they have
-		// the same type.
-		//
-		// the only conversion that isn't a no-op is concrete == interface.
-		// in that case, check comparability of the concrete type.
-		// The conversion allocates, so only do it if the concrete type is huge.
-		if r.Type.Etype != TBLANK {
-			aop = assignop(l.Type, r.Type, nil)
-			if aop != 0 {
-				if Isinter(r.Type) && !Isinter(l.Type) && algtype1(l.Type, nil) == ANOEQ {
-					Yyerror("invalid operation: %v (operator %v not defined on %s)", Nconv(n, 0), Oconv(int(op), 0), typekind(l.Type))
-					goto error
-				}
-
-				dowidth(l.Type)
-				if Isinter(r.Type) == Isinter(l.Type) || l.Type.Width >= 1<<16 {
-					l = Nod(aop, l, nil)
-					l.Type = r.Type
-					l.Typecheck = 1
-					n.Left = l
-				}
-
-				t = r.Type
-				goto converted
-			}
-		}
-
-		if l.Type.Etype != TBLANK {
-			aop = assignop(r.Type, l.Type, nil)
-			if aop != 0 {
-				if Isinter(l.Type) && !Isinter(r.Type) && algtype1(r.Type, nil) == ANOEQ {
-					Yyerror("invalid operation: %v (operator %v not defined on %s)", Nconv(n, 0), Oconv(int(op), 0), typekind(r.Type))
-					goto error
-				}
-
-				dowidth(r.Type)
-				if Isinter(r.Type) == Isinter(l.Type) || r.Type.Width >= 1<<16 {
-					r = Nod(aop, r, nil)
-					r.Type = l.Type
-					r.Typecheck = 1
-					n.Right = r
-				}
-
-				t = l.Type
-			}
-		}
-
-	converted:
-		et = int(t.Etype)
-	}
-
-	if t.Etype != TIDEAL && !Eqtype(l.Type, r.Type) {
-		defaultlit2(&l, &r, 1)
-		if n.Op == OASOP && n.Implicit != 0 {
-			Yyerror("invalid operation: %v (non-numeric type %v)", Nconv(n, 0), Tconv(l.Type, 0))
-			goto error
-		}
-
-		if Isinter(r.Type) == Isinter(l.Type) || aop == 0 {
-			Yyerror("invalid operation: %v (mismatched types %v and %v)", Nconv(n, 0), Tconv(l.Type, 0), Tconv(r.Type, 0))
-			goto error
-		}
-	}
-
-	if okfor[op][et] == 0 {
-		Yyerror("invalid operation: %v (operator %v not defined on %s)", Nconv(n, 0), Oconv(int(op), 0), typekind(t))
-		goto error
-	}
-
-	// okfor allows any array == array, map == map, func == func.
-	// restrict to slice/map/func == nil and nil == slice/map/func.
-	if Isfixedarray(l.Type) && algtype1(l.Type, nil) == ANOEQ {
-		Yyerror("invalid operation: %v (%v cannot be compared)", Nconv(n, 0), Tconv(l.Type, 0))
-		goto error
-	}
-
-	if Isslice(l.Type) && !isnil(l) && !isnil(r) {
-		Yyerror("invalid operation: %v (slice can only be compared to nil)", Nconv(n, 0))
-		goto error
-	}
-
-	if l.Type.Etype == TMAP && !isnil(l) && !isnil(r) {
-		Yyerror("invalid operation: %v (map can only be compared to nil)", Nconv(n, 0))
-		goto error
-	}
-
-	if l.Type.Etype == TFUNC && !isnil(l) && !isnil(r) {
-		Yyerror("invalid operation: %v (func can only be compared to nil)", Nconv(n, 0))
-		goto error
-	}
-
-	if l.Type.Etype == TSTRUCT && algtype1(l.Type, &badtype) == ANOEQ {
-		Yyerror("invalid operation: %v (struct containing %v cannot be compared)", Nconv(n, 0), Tconv(badtype, 0))
-		goto error
-	}
-
-	t = l.Type
-	if iscmp[n.Op] != 0 {
-		evconst(n)
-		t = idealbool
-		if n.Op != OLITERAL {
-			defaultlit2(&l, &r, 1)
-			n.Left = l
-			n.Right = r
-		}
-	} else if n.Op == OANDAND || n.Op == OOROR {
-		if l.Type == r.Type {
-			t = l.Type
-		} else if l.Type == idealbool {
-			t = r.Type
-		} else if r.Type == idealbool {
-			t = l.Type
-		}
-	} else
-	// non-comparison operators on ideal bools should make them lose their ideal-ness
-	if t == idealbool {
-		t = Types[TBOOL]
-	}
-
-	if et == TSTRING {
-		if iscmp[n.Op] != 0 {
-			n.Etype = n.Op
-			n.Op = OCMPSTR
-		} else if n.Op == OADD {
-			// create OADDSTR node with list of strings in x + y + z + (w + v) + ...
-			n.Op = OADDSTR
-
-			if l.Op == OADDSTR {
-				n.List = l.List
-			} else {
-				n.List = list1(l)
-			}
-			if r.Op == OADDSTR {
-				n.List = concat(n.List, r.List)
-			} else {
-				n.List = list(n.List, r)
-			}
-			n.Left = nil
-			n.Right = nil
-		}
-	}
-
-	if et == TINTER {
-		if l.Op == OLITERAL && l.Val.Ctype == CTNIL {
-			// swap for back end
-			n.Left = r
-
-			n.Right = l
-		} else if r.Op == OLITERAL && r.Val.Ctype == CTNIL {
-		} else // leave alone for back end
-		if Isinter(r.Type) == Isinter(l.Type) {
-			n.Etype = n.Op
-			n.Op = OCMPIFACE
-		}
-	}
-
-	if (op == ODIV || op == OMOD) && Isconst(r, CTINT) {
-		if mpcmpfixc(r.Val.U.Xval, 0) == 0 {
-			Yyerror("division by zero")
-			goto error
-		}
-	}
-
-	n.Type = t
-	goto ret
-
-shift:
-	defaultlit(&r, Types[TUINT])
-	n.Right = r
-	t = r.Type
-	if Isint[t.Etype] == 0 || Issigned[t.Etype] != 0 {
-		Yyerror("invalid operation: %v (shift count type %v, must be unsigned integer)", Nconv(n, 0), Tconv(r.Type, 0))
-		goto error
-	}
-
-	t = l.Type
-	if t != nil && t.Etype != TIDEAL && Isint[t.Etype] == 0 {
-		Yyerror("invalid operation: %v (shift of type %v)", Nconv(n, 0), Tconv(t, 0))
-		goto error
-	}
-
-	// no defaultlit for left
-	// the outer context gives the type
-	n.Type = l.Type
-
-	goto ret
-
-doconv:
-	ok |= Erv
-	saveorignode(n)
-	typecheck(&n.Left, Erv|top&(Eindir|Eiota))
-	convlit1(&n.Left, n.Type, true)
-	t = n.Left.Type
-	if t == nil || n.Type == nil {
-		goto error
-	}
-	n.Op = uint8(convertop(t, n.Type, &why))
-	if (n.Op) == 0 {
-		if n.Diag == 0 && n.Type.Broke == 0 {
-			Yyerror("cannot convert %v to type %v%s", Nconv(n.Left, obj.FmtLong), Tconv(n.Type, 0), why)
-			n.Diag = 1
-		}
-
-		n.Op = OCONV
-	}
-
-	switch n.Op {
-	case OCONVNOP:
-		if n.Left.Op == OLITERAL && n.Type != Types[TBOOL] {
-			r := Nod(OXXX, nil, nil)
-			n.Op = OCONV
-			n.Orig = r
-			*r = *n
-			n.Op = OLITERAL
-			n.Val = n.Left.Val
-		}
-
-		// do not use stringtoarraylit.
-	// generated code and compiler memory footprint is better without it.
-	case OSTRARRAYBYTE:
-		break
-
-	case OSTRARRAYRUNE:
-		if n.Left.Op == OLITERAL {
-			stringtoarraylit(&n)
-		}
-	}
-
-	goto ret
-
-ret:
-	t = n.Type
+	t := n.Type
 	if t != nil && t.Funarg == 0 && n.Op != OTYPE {
 		switch t.Etype {
 		case TFUNC, // might have TANY; wait until its called
@@ -2081,18 +2183,21 @@
 	evconst(n)
 	if n.Op == OTYPE && top&Etype == 0 {
 		Yyerror("type %v is not an expression", Tconv(n.Type, 0))
-		goto error
+		n.Type = nil
+		return
 	}
 
 	if top&(Erv|Etype) == Etype && n.Op != OTYPE {
 		Yyerror("%v is not a type", Nconv(n, 0))
-		goto error
+		n.Type = nil
+		return
 	}
 
 	// TODO(rsc): simplify
 	if (top&(Ecall|Erv|Etype) != 0) && top&Etop == 0 && ok&(Erv|Etype|Ecall) == 0 {
 		Yyerror("%v used as value", Nconv(n, 0))
-		goto error
+		n.Type = nil
+		return
 	}
 
 	if (top&Etop != 0) && top&(Ecall|Erv|Etype) == 0 && ok&Etop == 0 {
@@ -2101,24 +2206,14 @@
 			n.Diag = 1
 		}
 
-		goto error
+		n.Type = nil
+		return
 	}
 
 	/* TODO
 	if(n->type == T)
 		fatal("typecheck nil type");
 	*/
-	goto out
-
-badcall1:
-	Yyerror("invalid argument %v for %v", Nconv(n.Left, obj.FmtLong), Oconv(int(n.Op), 0))
-	goto error
-
-error:
-	n.Type = nil
-
-out:
-	*np = n
 }
 
 func checksliceindex(l *Node, r *Node, tp *Type) int {
@@ -2126,7 +2221,7 @@
 	if t == nil {
 		return -1
 	}
-	if Isint[t.Etype] == 0 {
+	if !Isint[t.Etype] {
 		Yyerror("invalid slice index %v (type %v)", Nconv(r, 0), Tconv(t, 0))
 		return -1
 	}
@@ -2138,8 +2233,8 @@
 		} else if tp != nil && tp.Bound > 0 && Mpgetfix(r.Val.U.Xval) > tp.Bound {
 			Yyerror("invalid slice index %v (out of bounds for %d-element array)", Nconv(r, 0), tp.Bound)
 			return -1
-		} else if Isconst(l, CTSTR) && Mpgetfix(r.Val.U.Xval) > int64(len(l.Val.U.Sval.S)) {
-			Yyerror("invalid slice index %v (out of bounds for %d-byte string)", Nconv(r, 0), len(l.Val.U.Sval.S))
+		} else if Isconst(l, CTSTR) && Mpgetfix(r.Val.U.Xval) > int64(len(l.Val.U.Sval)) {
+			Yyerror("invalid slice index %v (out of bounds for %d-byte string)", Nconv(r, 0), len(l.Val.U.Sval))
 			return -1
 		} else if Mpcmpfixfix(r.Val.U.Xval, Maxintval[TINT]) > 0 {
 			Yyerror("invalid slice index %v (index too large)", Nconv(r, 0))
@@ -2218,7 +2313,7 @@
 	n := *nn
 
 	t := n.Type
-	if t == nil || Isptr[t.Etype] == 0 {
+	if t == nil || !Isptr[t.Etype] {
 		return
 	}
 	t = t.Type
@@ -2229,7 +2324,7 @@
 		return
 	}
 	n = Nod(OIND, n, nil)
-	n.Implicit = 1
+	n.Implicit = true
 	typecheck(&n, Erv)
 	*nn = n
 }
@@ -2285,7 +2380,7 @@
 }
 
 func lookdot1(errnode *Node, s *Sym, t *Type, f *Type, dostrcmp int) *Type {
-	r := (*Type)(nil)
+	var r *Type
 	for ; f != nil; f = f.Down {
 		if dostrcmp != 0 && f.Sym.Name == s.Name {
 			return f
@@ -2296,7 +2391,7 @@
 		if r != nil {
 			if errnode != nil {
 				Yyerror("ambiguous selector %v", Nconv(errnode, 0))
-			} else if Isptr[t.Etype] != 0 {
+			} else if Isptr[t.Etype] {
 				Yyerror("ambiguous selector (%v).%v", Tconv(t, 0), Sconv(s, 0))
 			} else {
 				Yyerror("ambiguous selector %v.%v", Tconv(t, 0), Sconv(s, 0))
@@ -2341,7 +2436,7 @@
 	}
 
 	// disallow T.m if m requires *T receiver
-	if Isptr[getthisx(f2.Type).Type.Type.Etype] != 0 && Isptr[t.Etype] == 0 && f2.Embedded != 2 && !isifacemethod(f2.Type) {
+	if Isptr[getthisx(f2.Type).Type.Type.Etype] && !Isptr[t.Etype] && f2.Embedded != 2 && !isifacemethod(f2.Type) {
 		Yyerror("invalid method expression %v (needs pointer receiver: (*%v).%v)", Nconv(n, 0), Tconv(t, 0), Sconv(f2.Sym, obj.FmtShort))
 		return false
 	}
@@ -2364,12 +2459,12 @@
 	s := n.Right.Sym
 
 	dowidth(t)
-	f1 := (*Type)(nil)
+	var f1 *Type
 	if t.Etype == TSTRUCT || t.Etype == TINTER {
 		f1 = lookdot1(n, s, t, t.Type, dostrcmp)
 	}
 
-	f2 := (*Type)(nil)
+	var f2 *Type
 	if n.Left.Type == t || n.Left.Type.Sym == nil {
 		f2 = methtype(t, 0)
 		if f2 != nil {
@@ -2390,9 +2485,9 @@
 		n.Type = f1.Type
 		n.Paramfld = f1
 		if t.Etype == TINTER {
-			if Isptr[n.Left.Type.Etype] != 0 {
+			if Isptr[n.Left.Type.Etype] {
 				n.Left = Nod(OIND, n.Left, nil) // implicitstar
-				n.Left.Implicit = 1
+				n.Left.Implicit = true
 				typecheck(&n.Left, Erv)
 			}
 
@@ -2410,11 +2505,11 @@
 			if int(rcvr.Etype) == Tptr && Eqtype(rcvr.Type, tt) {
 				checklvalue(n.Left, "call pointer method on")
 				n.Left = Nod(OADDR, n.Left, nil)
-				n.Left.Implicit = 1
+				n.Left.Implicit = true
 				typecheck(&n.Left, Etype|Erv)
 			} else if int(tt.Etype) == Tptr && int(rcvr.Etype) != Tptr && Eqtype(tt.Type, rcvr) {
 				n.Left = Nod(OIND, n.Left, nil)
-				n.Left.Implicit = 1
+				n.Left.Implicit = true
 				typecheck(&n.Left, Etype|Erv)
 			} else if int(tt.Etype) == Tptr && int(tt.Type.Etype) == Tptr && Eqtype(derefall(tt), derefall(rcvr)) {
 				Yyerror("calling method %v with receiver %v requires explicit dereference", Nconv(n.Right, 0), Nconv(n.Left, obj.FmtLong))
@@ -2424,7 +2519,7 @@
 						break
 					}
 					n.Left = Nod(OIND, n.Left, nil)
-					n.Left.Implicit = 1
+					n.Left.Implicit = true
 					typecheck(&n.Left, Etype|Erv)
 					tt = tt.Type
 				}
@@ -2437,8 +2532,8 @@
 		for ll.Left != nil {
 			ll = ll.Left
 		}
-		if ll.Implicit != 0 {
-			if Isptr[ll.Type.Etype] != 0 && ll.Type.Sym != nil && ll.Type.Sym.Def != nil && ll.Type.Sym.Def.Op == OTYPE {
+		if ll.Implicit {
+			if Isptr[ll.Type.Etype] && ll.Type.Sym != nil && ll.Type.Sym.Def != nil && ll.Type.Sym.Def.Op == OTYPE {
 				// It is invalid to automatically dereference a named pointer type when selecting a method.
 				// Make n->left == ll to clarify error message.
 				n.Left = ll
@@ -2470,7 +2565,7 @@
 
 func hasddd(t *Type) bool {
 	for tl := t.Type; tl != nil; tl = tl.Down {
-		if tl.Isddd != 0 {
+		if tl.Isddd {
 			return true
 		}
 	}
@@ -2490,7 +2585,7 @@
 /*
  * typecheck assignment: type list = expression list
  */
-func typecheckaste(op int, call *Node, isddd int, tstruct *Type, nl *NodeList, desc string) {
+func typecheckaste(op int, call *Node, isddd bool, tstruct *Type, nl *NodeList, desc func() string) {
 	var t *Type
 	var n *Node
 	var n1 int
@@ -2521,13 +2616,13 @@
 				tn := n.Type.Type
 				var why string
 				for tl := tstruct.Type; tl != nil; tl = tl.Down {
-					if tl.Isddd != 0 {
+					if tl.Isddd {
 						for ; tn != nil; tn = tn.Down {
 							if assignop(tn.Type, tl.Type.Type, &why) == 0 {
 								if call != nil {
 									Yyerror("cannot use %v as type %v in argument to %v%s", Tconv(tn.Type, 0), Tconv(tl.Type.Type, 0), Nconv(call, 0), why)
 								} else {
-									Yyerror("cannot use %v as type %v in %s%s", Tconv(tn.Type, 0), Tconv(tl.Type.Type, 0), desc, why)
+									Yyerror("cannot use %v as type %v in %s%s", Tconv(tn.Type, 0), Tconv(tl.Type.Type, 0), desc(), why)
 								}
 							}
 						}
@@ -2542,7 +2637,7 @@
 						if call != nil {
 							Yyerror("cannot use %v as type %v in argument to %v%s", Tconv(tn.Type, 0), Tconv(tl.Type, 0), Nconv(call, 0), why)
 						} else {
-							Yyerror("cannot use %v as type %v in %s%s", Tconv(tn.Type, 0), Tconv(tl.Type, 0), desc, why)
+							Yyerror("cannot use %v as type %v in %s%s", Tconv(tn.Type, 0), Tconv(tl.Type, 0), desc(), why)
 						}
 					}
 
@@ -2567,7 +2662,7 @@
 			goto notenough
 		}
 	} else {
-		if isddd == 0 {
+		if !isddd {
 			if n2 < n1-1 {
 				goto notenough
 			}
@@ -2583,8 +2678,8 @@
 
 	for tl := tstruct.Type; tl != nil; tl = tl.Down {
 		t = tl.Type
-		if tl.Isddd != 0 {
-			if isddd != 0 {
+		if tl.Isddd {
+			if isddd {
 				if nl == nil {
 					goto notenough
 				}
@@ -2594,7 +2689,7 @@
 				n = nl.N
 				setlineno(n)
 				if n.Type != nil {
-					nl.N = assignconv(n, t, desc)
+					nl.N = assignconvfn(n, t, desc)
 				}
 				goto out
 			}
@@ -2603,7 +2698,7 @@
 				n = nl.N
 				setlineno(nl.N)
 				if n.Type != nil {
-					nl.N = assignconv(n, t.Type, desc)
+					nl.N = assignconvfn(n, t.Type, desc)
 				}
 			}
 
@@ -2616,7 +2711,7 @@
 		n = nl.N
 		setlineno(n)
 		if n.Type != nil {
-			nl.N = assignconv(n, t, desc)
+			nl.N = assignconvfn(n, t, desc)
 		}
 		nl = nl.Next
 	}
@@ -2624,7 +2719,7 @@
 	if nl != nil {
 		goto toomany
 	}
-	if isddd != 0 {
+	if isddd {
 		if call != nil {
 			Yyerror("invalid use of ... in call to %v", Nconv(call, 0))
 		} else {
@@ -2662,21 +2757,16 @@
 /*
  * type check composite
  */
-func fielddup(n *Node, hash []*Node) {
+func fielddup(n *Node, hash map[string]bool) {
 	if n.Op != ONAME {
 		Fatal("fielddup: not ONAME")
 	}
-	s := n.Sym.Name
-	h := uint(stringhash(s) % uint32(len(hash)))
-	for a := hash[h]; a != nil; a = a.Ntest {
-		if a.Sym.Name == s {
-			Yyerror("duplicate field name in struct literal: %s", s)
-			return
-		}
+	name := n.Sym.Name
+	if hash[name] {
+		Yyerror("duplicate field name in struct literal: %s", name)
+		return
 	}
-
-	n.Ntest = hash[h]
-	hash[h] = n
+	hash[name] = true
 }
 
 func keydup(n *Node, hash []*Node) {
@@ -2694,8 +2784,7 @@
 	default: // unknown, bool, nil
 		b = 23
 
-	case CTINT,
-		CTRUNE:
+	case CTINT, CTRUNE:
 		b = uint32(Mpgetfix(n.Val.U.Xval))
 
 	case CTFLT:
@@ -2708,15 +2797,15 @@
 
 	case CTSTR:
 		b = 0
-		s := n.Val.U.Sval.S
-		for i := len(n.Val.U.Sval.S); i > 0; i-- {
+		s := n.Val.U.Sval
+		for i := len(n.Val.U.Sval); i > 0; i-- {
 			b = b*PRIME1 + uint32(s[0])
 			s = s[1:]
 		}
 	}
 
 	h := uint(b % uint32(len(hash)))
-	cmp := Node{}
+	var cmp Node
 	for a := hash[h]; a != nil; a = a.Ntest {
 		cmp.Op = OEQ
 		cmp.Left = n
@@ -2812,17 +2901,12 @@
 
 func iscomptype(t *Type) bool {
 	switch t.Etype {
-	case TARRAY,
-		TSTRUCT,
-		TMAP:
+	case TARRAY, TSTRUCT, TMAP:
 		return true
 
-	case TPTR32,
-		TPTR64:
+	case TPTR32, TPTR64:
 		switch t.Type.Etype {
-		case TARRAY,
-			TSTRUCT,
-			TMAP:
+		case TARRAY, TSTRUCT, TMAP:
 			return true
 		}
 	}
@@ -2837,8 +2921,8 @@
 
 	if n.Right == nil {
 		n.Right = typenod(t)
-		n.Implicit = 1       // don't print
-		n.Right.Implicit = 1 // * is okay
+		n.Implicit = true       // don't print
+		n.Right.Implicit = true // * is okay
 	} else if Debug['s'] != 0 {
 		typecheck(&n.Right, Etype)
 		if n.Right.Type != nil && Eqtype(n.Right.Type, t) {
@@ -2848,54 +2932,57 @@
 }
 
 func typecheckcomplit(np **Node) {
-	var nerr int
-	var l *Node
-	var norig *Node
-	var r *Node
-	var t *Type
-
 	n := *np
 	lno := lineno
+	defer func() {
+		lineno = lno
+		*np = n
+	}()
 
 	if n.Right == nil {
 		if n.List != nil {
 			setlineno(n.List.N)
 		}
 		Yyerror("missing type in composite literal")
-		goto error
+		n.Type = nil
+		return
 	}
 
 	// Save original node (including n->right)
-	norig = Nod(int(n.Op), nil, nil)
+	norig := Nod(int(n.Op), nil, nil)
 
 	*norig = *n
 
 	setlineno(n.Right)
-	l = typecheck(&n.Right, Etype|Ecomplit) /* sic */
-	t = l.Type
+	l := typecheck(&n.Right, Etype|Ecomplit) /* sic */
+	t := l.Type
 	if t == nil {
-		goto error
+		n.Type = nil
+		return
 	}
-	nerr = nerrors
+	nerr := nerrors
 	n.Type = t
 
-	if Isptr[t.Etype] != 0 {
+	if Isptr[t.Etype] {
 		// For better or worse, we don't allow pointers as the composite literal type,
 		// except when using the &T syntax, which sets implicit on the OIND.
-		if n.Right.Implicit == 0 {
+		if !n.Right.Implicit {
 			Yyerror("invalid pointer type %v for composite literal (use &%v instead)", Tconv(t, 0), Tconv(t.Type, 0))
-			goto error
+			n.Type = nil
+			return
 		}
 
 		// Also, the underlying type must be a struct, map, slice, or array.
 		if !iscomptype(t) {
 			Yyerror("invalid pointer type %v for composite literal", Tconv(t, 0))
-			goto error
+			n.Type = nil
+			return
 		}
 
 		t = t.Type
 	}
 
+	var r *Node
 	switch t.Etype {
 	default:
 		Yyerror("invalid type for composite literal: %v", Tconv(t, 0))
@@ -3022,8 +3109,7 @@
 				Yyerror("too few values in struct initializer")
 			}
 		} else {
-			var autohash [101]*Node
-			hash := inithash(n, autohash[:])
+			hash := make(map[string]bool)
 
 			// keyed list
 			var s *Sym
@@ -3084,11 +3170,12 @@
 	}
 
 	if nerr != nerrors {
-		goto error
+		n.Type = nil
+		return
 	}
 
 	n.Orig = norig
-	if Isptr[n.Type.Etype] != 0 {
+	if Isptr[n.Type.Etype] {
 		n = Nod(OPTRLIT, n, nil)
 		n.Typecheck = 1
 		n.Type = n.Left.Type
@@ -3097,14 +3184,7 @@
 	}
 
 	n.Orig = norig
-	*np = n
-	lineno = lno
 	return
-
-error:
-	n.Type = nil
-	*np = n
-	lineno = lno
 }
 
 /*
@@ -3122,10 +3202,7 @@
 		fallthrough
 
 		// fall through
-	case OIND,
-		ODOTPTR,
-		OCLOSUREVAR,
-		OPARAM:
+	case OIND, ODOTPTR, OCLOSUREVAR, OPARAM:
 		return true
 
 	case ODOT:
@@ -3153,15 +3230,15 @@
 		r := outervalue(n)
 		var l *Node
 		for l = n; l != r; l = l.Left {
-			l.Assigned = 1
+			l.Assigned = true
 			if l.Closure != nil {
-				l.Closure.Assigned = 1
+				l.Closure.Assigned = true
 			}
 		}
 
-		l.Assigned = 1
+		l.Assigned = true
 		if l.Closure != nil {
-			l.Closure.Assigned = 1
+			l.Closure.Assigned = true
 		}
 	}
 
@@ -3195,12 +3272,10 @@
 	}
 
 	switch l.Op {
-	case ONAME,
-		OCLOSUREVAR:
+	case ONAME, OCLOSUREVAR:
 		return l == r
 
-	case ODOT,
-		ODOTPTR:
+	case ODOT, ODOTPTR:
 		return l.Right != nil && r.Right != nil && l.Right.Sym == r.Right.Sym && samesafeexpr(l.Left, r.Left)
 
 	case OIND:
@@ -3261,11 +3336,9 @@
 		switch n.Right.Op {
 		// For x = x[0:y], x can be updated in place, without touching pointer.
 		// TODO(rsc): Reenable once it is actually updated in place without touching the pointer.
-		case OSLICE,
-			OSLICE3,
-			OSLICESTR:
+		case OSLICE, OSLICE3, OSLICESTR:
 			if false && samesafeexpr(n.Left, n.Right.Left) && (n.Right.Right.Left == nil || iszero(n.Right.Right.Left)) {
-				n.Right.Reslice = 1
+				n.Right.Reslice = true
 			}
 
 			// For x = append(x, ...), x can be updated in place when there is capacity,
@@ -3274,7 +3347,7 @@
 		// TODO(rsc): Reenable once the emitted code does update the pointer.
 		case OAPPEND:
 			if false && n.Right.List != nil && samesafeexpr(n.Left, n.Right.List.N) {
-				n.Right.Reslice = 1
+				n.Right.Reslice = true
 			}
 		}
 	}
@@ -3290,10 +3363,7 @@
 }
 
 func typecheckas2(n *Node) {
-	var ll *NodeList
-	var lr *NodeList
-
-	for ll = n.List; ll != nil; ll = ll.Next {
+	for ll := n.List; ll != nil; ll = ll.Next {
 		// delicate little dance.
 		ll.N = resolve(ll.N)
 
@@ -3315,9 +3385,9 @@
 	var r *Node
 	if cl == cr {
 		// easy
-		ll = n.List
-		lr = n.Rlist
-		for ; ll != nil; (func() { ll = ll.Next; lr = lr.Next })() {
+		ll := n.List
+		lr := n.Rlist
+		for ; ll != nil; ll, lr = ll.Next, lr.Next {
 			if ll.N.Type != nil && lr.N.Type != nil {
 				lr.N = assignconv(lr.N, ll.N.Type, "assignment")
 			}
@@ -3339,9 +3409,7 @@
 			goto out
 		}
 		switch r.Op {
-		case OCALLMETH,
-			OCALLINTER,
-			OCALLFUNC:
+		case OCALLMETH, OCALLINTER, OCALLFUNC:
 			if r.Type.Etype != TSTRUCT || r.Type.Funarg == 0 {
 				break
 			}
@@ -3352,7 +3420,7 @@
 			n.Op = OAS2FUNC
 			var s Iter
 			t := Structfirst(&s, &r.Type)
-			for ll = n.List; ll != nil; ll = ll.Next {
+			for ll := n.List; ll != nil; ll = ll.Next {
 				if t.Type != nil && ll.N.Type != nil {
 					checkassignto(t.Type, ll.N)
 				}
@@ -3372,9 +3440,7 @@
 			goto out
 		}
 		switch r.Op {
-		case OINDEXMAP,
-			ORECV,
-			ODOTTYPE:
+		case OINDEXMAP, ORECV, ODOTTYPE:
 			switch r.Op {
 			case OINDEXMAP:
 				n.Op = OAS2MAPR
@@ -3411,7 +3477,7 @@
 out:
 	n.Typecheck = 1
 
-	for ll = n.List; ll != nil; ll = ll.Next {
+	for ll := n.List; ll != nil; ll = ll.Next {
 		if ll.N.Typecheck == 0 {
 			typecheck(&ll.N, Erv|Easgn)
 		}
@@ -3430,11 +3496,11 @@
 	n.Type = t
 	t.Nname = n.Nname
 	rcvr := getthisx(t).Type
-	if rcvr != nil && n.Shortname != nil && !isblank(n.Shortname) {
-		addmethod(n.Shortname.Sym, t, true, n.Nname.Nointerface)
+	if rcvr != nil && n.Func.Shortname != nil && !isblank(n.Func.Shortname) {
+		addmethod(n.Func.Shortname.Sym, t, true, n.Nname.Nointerface)
 	}
 
-	for l := n.Dcl; l != nil; l = l.Next {
+	for l := n.Func.Dcl; l != nil; l = l.Next {
 		if l.N.Op == ONAME && (l.N.Class == PPARAM || l.N.Class == PPARAMOUT) {
 			l.N.Decldepth = 1
 		}
@@ -3447,7 +3513,7 @@
 		Fatal("stringtoarraylit %N", n)
 	}
 
-	s := n.Left.Val.U.Sval.S
+	s := n.Left.Val.U.Sval
 	var l *NodeList
 	if n.Type.Type.Etype == TUINT8 {
 		// []byte
@@ -3541,7 +3607,7 @@
 
 	if embedlineno != 0 {
 		lineno = int32(embedlineno)
-		if Isptr[t.Etype] != 0 {
+		if Isptr[t.Etype] {
 			Yyerror("embedded type cannot be a pointer")
 		}
 	}
@@ -3668,8 +3734,7 @@
 		Fatal("typecheckdef %v", Oconv(int(n.Op), 0))
 
 		// not really syms
-	case OGOTO,
-		OLABEL:
+	case OGOTO, OLABEL:
 		break
 
 	case OLITERAL:
@@ -3708,7 +3773,7 @@
 
 		t := n.Type
 		if t != nil {
-			if okforconst[t.Etype] == 0 {
+			if !okforconst[t.Etype] {
 				Yyerror("invalid constant type %v", Tconv(t, 0))
 				goto ret
 			}
@@ -3803,10 +3868,7 @@
 func checkmake(t *Type, arg string, n *Node) int {
 	if n.Op == OLITERAL {
 		switch n.Val.Ctype {
-		case CTINT,
-			CTRUNE,
-			CTFLT,
-			CTCPLX:
+		case CTINT, CTRUNE, CTFLT, CTCPLX:
 			n.Val = toint(n.Val)
 			if mpcmpfixc(n.Val.U.Xval, 0) < 0 {
 				Yyerror("negative %s argument in make(%v)", arg, Tconv(t, 0))
@@ -3829,7 +3891,7 @@
 		}
 	}
 
-	if Isint[n.Type.Etype] == 0 && n.Type.Etype != TIDEAL {
+	if !Isint[n.Type.Etype] && n.Type.Etype != TIDEAL {
 		Yyerror("non-integer %s argument in make(%v) - %v", arg, Tconv(t, 0), Tconv(n.Type, 0))
 		return -1
 	}
@@ -3849,12 +3911,12 @@
 	case OBREAK:
 		if n.Left == nil {
 			if implicit != nil {
-				implicit.Hasbreak = 1
+				implicit.Hasbreak = true
 			}
 		} else {
 			lab := n.Left.Sym.Label
 			if lab != nil {
-				lab.Def.Hasbreak = 1
+				lab.Def.Hasbreak = true
 			}
 		}
 
@@ -3948,7 +4010,7 @@
 		if n.Ntest != nil {
 			return false
 		}
-		if n.Hasbreak != 0 {
+		if n.Hasbreak {
 			return false
 		}
 		return true
@@ -3956,10 +4018,8 @@
 	case OIF:
 		return isterminating(n.Nbody, 0) && isterminating(n.Nelse, 0)
 
-	case OSWITCH,
-		OTYPESW,
-		OSELECT:
-		if n.Hasbreak != 0 {
+	case OSWITCH, OTYPESW, OSELECT:
+		if n.Hasbreak {
 			return false
 		}
 		def := 0
@@ -3984,7 +4044,7 @@
 func checkreturn(fn *Node) {
 	if fn.Type.Outtuple != 0 && fn.Nbody != nil {
 		if !isterminating(fn.Nbody, 1) {
-			yyerrorl(int(fn.Endlineno), "missing return at end of function")
+			yyerrorl(int(fn.Func.Endlineno), "missing return at end of function")
 		}
 	}
 }
diff --git a/src/cmd/internal/gc/unsafe.go b/src/cmd/internal/gc/unsafe.go
index 7f0a33f..7bd35f8 100644
--- a/src/cmd/internal/gc/unsafe.go
+++ b/src/cmd/internal/gc/unsafe.go
@@ -14,31 +14,28 @@
  * rewrite with a constant
  */
 func unsafenmagic(nn *Node) *Node {
-	var r *Node
-	var s *Sym
-	var v int64
-
 	fn := nn.Left
 	args := nn.List
 
 	if safemode != 0 || fn == nil || fn.Op != ONAME {
-		goto no
+		return nil
 	}
-	s = fn.Sym
+	s := fn.Sym
 	if s == nil {
-		goto no
+		return nil
 	}
 	if s.Pkg != unsafepkg {
-		goto no
+		return nil
 	}
 
 	if args == nil {
 		Yyerror("missing argument for %v", Sconv(s, 0))
-		goto no
+		return nil
 	}
 
-	r = args.N
+	r := args.N
 
+	var v int64
 	if s.Name == "Sizeof" {
 		typecheck(&r, Erv)
 		defaultlit(&r, nil)
@@ -65,8 +62,7 @@
 		base := r.Left
 		typecheck(&r, Erv)
 		switch r.Op {
-		case ODOT,
-			ODOTPTR:
+		case ODOT, ODOTPTR:
 			break
 
 		case OCALLPART:
@@ -127,7 +123,6 @@
 		goto yes
 	}
 
-no:
 	return nil
 
 bad:
diff --git a/src/cmd/internal/gc/util.go b/src/cmd/internal/gc/util.go
index df68d50..c3f7db2 100644
--- a/src/cmd/internal/gc/util.go
+++ b/src/cmd/internal/gc/util.go
@@ -39,17 +39,14 @@
 
 func plan9quote(s string) string {
 	if s == "" {
-		goto needquote
+		return "'" + strings.Replace(s, "'", "''", -1) + "'"
 	}
 	for i := 0; i < len(s); i++ {
 		if s[i] <= ' ' || s[i] == '\'' {
-			goto needquote
+			return "'" + strings.Replace(s, "'", "''", -1) + "'"
 		}
 	}
 	return s
-
-needquote:
-	return "'" + strings.Replace(s, "'", "''", -1) + "'"
 }
 
 // simulation of int(*s++) in C
diff --git a/src/cmd/internal/gc/walk.go b/src/cmd/internal/gc/walk.go
index c57bdd6..03e7926 100644
--- a/src/cmd/internal/gc/walk.go
+++ b/src/cmd/internal/gc/walk.go
@@ -29,30 +29,30 @@
 
 	// Final typecheck for any unused variables.
 	// It's hard to be on the heap when not-used, but best to be consistent about &~PHEAP here and below.
-	for l := fn.Dcl; l != nil; l = l.Next {
+	for l := fn.Func.Dcl; l != nil; l = l.Next {
 		if l.N.Op == ONAME && l.N.Class&^PHEAP == PAUTO {
 			typecheck(&l.N, Erv|Easgn)
 		}
 	}
 
 	// Propagate the used flag for typeswitch variables up to the NONAME in it's definition.
-	for l := fn.Dcl; l != nil; l = l.Next {
-		if l.N.Op == ONAME && l.N.Class&^PHEAP == PAUTO && l.N.Defn != nil && l.N.Defn.Op == OTYPESW && l.N.Used != 0 {
-			l.N.Defn.Left.Used++
+	for l := fn.Func.Dcl; l != nil; l = l.Next {
+		if l.N.Op == ONAME && l.N.Class&^PHEAP == PAUTO && l.N.Defn != nil && l.N.Defn.Op == OTYPESW && l.N.Used {
+			l.N.Defn.Left.Used = true
 		}
 	}
 
-	for l := fn.Dcl; l != nil; l = l.Next {
-		if l.N.Op != ONAME || l.N.Class&^PHEAP != PAUTO || l.N.Sym.Name[0] == '&' || l.N.Used != 0 {
+	for l := fn.Func.Dcl; l != nil; l = l.Next {
+		if l.N.Op != ONAME || l.N.Class&^PHEAP != PAUTO || l.N.Sym.Name[0] == '&' || l.N.Used {
 			continue
 		}
 		if l.N.Defn != nil && l.N.Defn.Op == OTYPESW {
-			if l.N.Defn.Left.Used != 0 {
+			if l.N.Defn.Left.Used {
 				continue
 			}
 			lineno = l.N.Defn.Left.Lineno
 			Yyerror("%v declared and not used", Sconv(l.N.Sym, 0))
-			l.N.Defn.Left.Used = 1 // suppress repeats
+			l.N.Defn.Left.Used = true // suppress repeats
 		} else {
 			lineno = l.N.Lineno
 			Yyerror("%v declared and not used", Sconv(l.N.Sym, 0))
@@ -70,9 +70,9 @@
 	}
 
 	heapmoves()
-	if Debug['W'] != 0 && Curfn.Enter != nil {
+	if Debug['W'] != 0 && Curfn.Func.Enter != nil {
 		s := fmt.Sprintf("enter %v", Sconv(Curfn.Nname.Sym, 0))
-		dumplist(s, Curfn.Enter)
+		dumplist(s, Curfn.Func.Enter)
 	}
 }
 
@@ -83,7 +83,7 @@
 }
 
 func samelist(a *NodeList, b *NodeList) bool {
-	for ; a != nil && b != nil; (func() { a = a.Next; b = b.Next })() {
+	for ; a != nil && b != nil; a, b = a.Next, b.Next {
 		if a.N != b.N {
 			return false
 		}
@@ -91,21 +91,21 @@
 	return a == b
 }
 
-func paramoutheap(fn *Node) int {
-	for l := fn.Dcl; l != nil; l = l.Next {
+func paramoutheap(fn *Node) bool {
+	for l := fn.Func.Dcl; l != nil; l = l.Next {
 		switch l.N.Class {
 		case PPARAMOUT,
 			PPARAMOUT | PHEAP:
-			return int(l.N.Addrtaken)
+			return l.N.Addrtaken
 
 			// stop early - parameters are over
 		case PAUTO,
 			PAUTO | PHEAP:
-			return 0
+			return false
 		}
 	}
 
-	return 0
+	return false
 }
 
 // adds "adjust" to all the argument locations for the call n.
@@ -232,8 +232,7 @@
 	case ODEFER:
 		Hasdefer = 1
 		switch n.Left.Op {
-		case OPRINT,
-			OPRINTN:
+		case OPRINT, OPRINTN:
 			walkprintfunc(&n.Left, &n.Ninit)
 
 		case OCOPY:
@@ -265,8 +264,7 @@
 
 	case OPROC:
 		switch n.Left.Op {
-		case OPRINT,
-			OPRINTN:
+		case OPRINT, OPRINTN:
 			walkprintfunc(&n.Left, &n.Ninit)
 
 		case OCOPY:
@@ -284,13 +282,13 @@
 		if n.List == nil {
 			break
 		}
-		if (Curfn.Type.Outnamed != 0 && count(n.List) > 1) || paramoutheap(Curfn) != 0 {
+		if (Curfn.Type.Outnamed != 0 && count(n.List) > 1) || paramoutheap(Curfn) {
 			// assign to the function out parameters,
 			// so that reorder3 can fix up conflicts
-			rl := (*NodeList)(nil)
+			var rl *NodeList
 
 			var cl int
-			for ll := Curfn.Dcl; ll != nil; ll = ll.Next {
+			for ll := Curfn.Func.Dcl; ll != nil; ll = ll.Next {
 				cl = int(ll.N.Class) &^ PHEAP
 				if cl == PAUTO {
 					break
@@ -326,7 +324,7 @@
 			break
 		}
 
-		ll := ascompatte(int(n.Op), nil, 0, Getoutarg(Curfn.Type), n.List, 1, &n.Ninit)
+		ll := ascompatte(int(n.Op), nil, false, Getoutarg(Curfn.Type), n.List, 1, &n.Ninit)
 		n.List = ll
 
 	case ORETJMP:
@@ -466,20 +464,18 @@
 		walkexpr(&n.Right, init)
 		goto ret
 
-	case OSPTR,
-		OITAB:
+	case OSPTR, OITAB:
 		walkexpr(&n.Left, init)
 		goto ret
 
-	case OLEN,
-		OCAP:
+	case OLEN, OCAP:
 		walkexpr(&n.Left, init)
 
 		// replace len(*[10]int) with 10.
 		// delayed until now to preserve side effects.
 		t := n.Left.Type
 
-		if Isptr[t.Etype] != 0 {
+		if Isptr[t.Etype] {
 			t = t.Type
 		}
 		if Isfixedarray(t) {
@@ -490,8 +486,7 @@
 
 		goto ret
 
-	case OLSH,
-		ORSH:
+	case OLSH, ORSH:
 		walkexpr(&n.Left, init)
 		walkexpr(&n.Right, init)
 		t := n.Left.Type
@@ -521,15 +516,13 @@
 		walkexpr(&n.Right, init)
 		goto ret
 
-	case OOR,
-		OXOR:
+	case OOR, OXOR:
 		walkexpr(&n.Left, init)
 		walkexpr(&n.Right, init)
 		walkrotate(&n)
 		goto ret
 
-	case OEQ,
-		ONE:
+	case OEQ, ONE:
 		walkexpr(&n.Left, init)
 		walkexpr(&n.Right, init)
 
@@ -545,21 +538,19 @@
 		safemode = old_safemode
 		goto ret
 
-	case OANDAND,
-		OOROR:
+	case OANDAND, OOROR:
 		walkexpr(&n.Left, init)
 
-		// cannot put side effects from n->right on init,
-		// because they cannot run before n->left is checked.
-		// save elsewhere and store on the eventual n->right.
-		ll := (*NodeList)(nil)
+		// cannot put side effects from n.Right on init,
+		// because they cannot run before n.Left is checked.
+		// save elsewhere and store on the eventual n.Right.
+		var ll *NodeList
 
 		walkexpr(&n.Right, &ll)
 		addinit(&n.Right, ll)
 		goto ret
 
-	case OPRINT,
-		OPRINTN:
+	case OPRINT, OPRINTN:
 		walkexprlist(n.List, init)
 		n = walkprint(n, init)
 		goto ret
@@ -576,8 +567,7 @@
 		n.Addable = 1
 		goto ret
 
-	case OCLOSUREVAR,
-		OCFUNC:
+	case OCLOSUREVAR, OCFUNC:
 		n.Addable = 1
 		goto ret
 
@@ -594,7 +584,7 @@
 		}
 		walkexpr(&n.Left, init)
 		walkexprlist(n.List, init)
-		ll := ascompatte(int(n.Op), n, int(n.Isddd), getinarg(t), n.List, 0, init)
+		ll := ascompatte(int(n.Op), n, n.Isddd, getinarg(t), n.List, 0, init)
 		n.List = reorder1(ll)
 		goto ret
 
@@ -604,9 +594,9 @@
 			// transformclosure already did all preparation work.
 
 			// Append captured variables to argument list.
-			n.List = concat(n.List, n.Left.Enter)
+			n.List = concat(n.List, n.Left.Func.Enter)
 
-			n.Left.Enter = nil
+			n.Left.Func.Enter = nil
 
 			// Replace OCLOSURE with ONAME/PFUNC.
 			n.Left = n.Left.Closure.Nname
@@ -632,7 +622,7 @@
 		walkexpr(&n.Left, init)
 		walkexprlist(n.List, init)
 
-		ll := ascompatte(int(n.Op), n, int(n.Isddd), getinarg(t), n.List, 0, init)
+		ll := ascompatte(int(n.Op), n, n.Isddd, getinarg(t), n.List, 0, init)
 		n.List = reorder1(ll)
 		goto ret
 
@@ -643,8 +633,8 @@
 		}
 		walkexpr(&n.Left, init)
 		walkexprlist(n.List, init)
-		ll := ascompatte(int(n.Op), n, 0, getthis(t), list1(n.Left.Left), 0, init)
-		lr := ascompatte(int(n.Op), n, int(n.Isddd), getinarg(t), n.List, 0, init)
+		ll := ascompatte(int(n.Op), n, false, getthis(t), list1(n.Left.Left), 0, init)
+		lr := ascompatte(int(n.Op), n, n.Isddd, getinarg(t), n.List, 0, init)
 		ll = concat(ll, lr)
 		n.Left.Left = nil
 		ullmancalc(n.Left)
@@ -670,39 +660,38 @@
 		default:
 			walkexpr(&n.Right, init)
 
-			// x = i.(T); n->left is x, n->right->left is i.
-		// orderstmt made sure x is addressable.
 		case ODOTTYPE:
+			// TODO(rsc): The Isfat is for consistency with componentgen and orderexpr.
+			// It needs to be removed in all three places.
+			// That would allow inlining x.(struct{*int}) the same as x.(*int).
+			if isdirectiface(n.Right.Type) && !Isfat(n.Right.Type) && flag_race == 0 {
+				// handled directly during cgen
+				walkexpr(&n.Right, init)
+				break
+			}
+
+			// x = i.(T); n.Left is x, n.Right.Left is i.
+			// orderstmt made sure x is addressable.
 			walkexpr(&n.Right.Left, init)
 
 			n1 := Nod(OADDR, n.Left, nil)
 			r := n.Right // i.(T)
 
-			from := "I"
-
-			to := "T"
-			if isnilinter(r.Left.Type) {
-				from = "E"
-			}
-			if isnilinter(r.Type) {
-				to = "E"
-			} else if Isinter(r.Type) {
-				to = "I"
+			if Debug_typeassert > 0 {
+				Warn("type assertion not inlined")
 			}
 
-			buf := fmt.Sprintf("assert%s2%s", from, to)
-
+			buf := "assert" + type2IET(r.Left.Type) + "2" + type2IET(r.Type)
 			fn := syslook(buf, 1)
-			argtype(fn, r.Left.Type)
-			argtype(fn, r.Type)
+			substArgTypes(fn, r.Left.Type, r.Type)
 
 			n = mkcall1(fn, nil, init, typename(r.Type), r.Left, n1)
 			walkexpr(&n, init)
 			goto ret
 
-			// x = <-c; n->left is x, n->right->left is c.
-		// orderstmt made sure x is addressable.
 		case ORECV:
+			// x = <-c; n.Left is x, n.Right.Left is c.
+			// orderstmt made sure x is addressable.
 			walkexpr(&n.Right.Left, init)
 
 			n1 := Nod(OADDR, n.Left, nil)
@@ -785,12 +774,10 @@
 		p := ""
 		if t.Type.Width <= 128 { // Check ../../runtime/hashmap.go:maxValueSize before changing.
 			switch Simsimtype(t.Down) {
-			case TINT32,
-				TUINT32:
+			case TINT32, TUINT32:
 				p = "mapaccess2_fast32"
 
-			case TINT64,
-				TUINT64:
+			case TINT64, TUINT64:
 				p = "mapaccess2_fast64"
 
 			case TSTRING:
@@ -865,53 +852,88 @@
 		n = mkcall1(mapfndel("mapdelete", t), nil, init, typename(t), map_, key)
 		goto ret
 
-		// a,b = i.(T)
-	// orderstmt made sure a is addressable.
 	case OAS2DOTTYPE:
+		e := n.Rlist.N // i.(T)
+		// TODO(rsc): The Isfat is for consistency with componentgen and orderexpr.
+		// It needs to be removed in all three places.
+		// That would allow inlining x.(struct{*int}) the same as x.(*int).
+		if isdirectiface(e.Type) && !Isfat(e.Type) && flag_race == 0 {
+			// handled directly during gen.
+			walkexprlistsafe(n.List, init)
+			walkexpr(&e.Left, init)
+			goto ret
+		}
+
+		// res, ok = i.(T)
+		// orderstmt made sure a is addressable.
 		*init = concat(*init, n.Ninit)
-
 		n.Ninit = nil
-		r := n.Rlist.N
+
 		walkexprlistsafe(n.List, init)
-		walkexpr(&r.Left, init)
-		var n1 *Node
-		if isblank(n.List.N) {
-			n1 = nodnil()
-		} else {
-			n1 = Nod(OADDR, n.List.N, nil)
-		}
-		n1.Etype = 1 // addr does not escape
+		walkexpr(&e.Left, init)
+		t := e.Type    // T
+		from := e.Left // i
 
-		from := "I"
-
-		to := "T"
-		if isnilinter(r.Left.Type) {
-			from = "E"
-		}
-		if isnilinter(r.Type) {
-			to = "E"
-		} else if Isinter(r.Type) {
-			to = "I"
-		}
-		buf := fmt.Sprintf("assert%s2%s2", from, to)
-
-		fn := syslook(buf, 1)
-		argtype(fn, r.Left.Type)
-		argtype(fn, r.Type)
-
-		t := Types[TBOOL]
+		oktype := Types[TBOOL]
 		ok := n.List.Next.N
 		if !isblank(ok) {
-			t = ok.Type
+			oktype = ok.Type
 		}
-		r = mkcall1(fn, t, init, typename(r.Type), r.Left, n1)
-		n = Nod(OAS, ok, r)
+
+		fromKind := type2IET(from.Type)
+		toKind := type2IET(t)
+
+		// Avoid runtime calls in a few cases of the form _, ok := i.(T).
+		// This is faster and shorter and allows the corresponding assertX2X2
+		// routines to skip nil checks on their last argument.
+		if isblank(n.List.N) {
+			var fast *Node
+			switch {
+			case fromKind == "E" && toKind == "T":
+				tab := Nod(OITAB, from, nil) // type:eface::tab:iface
+				typ := Nod(OCONVNOP, typename(t), nil)
+				typ.Type = Ptrto(Types[TUINTPTR])
+				fast = Nod(OEQ, tab, typ)
+			case fromKind == "I" && toKind == "E",
+				fromKind == "E" && toKind == "E":
+				tab := Nod(OITAB, from, nil)
+				fast = Nod(ONE, nodnil(), tab)
+			}
+			if fast != nil {
+				if Debug_typeassert > 0 {
+					Warn("type assertion (ok only) inlined")
+				}
+				n = Nod(OAS, ok, fast)
+				typecheck(&n, Etop)
+				goto ret
+			}
+		}
+
+		var resptr *Node // &res
+		if isblank(n.List.N) {
+			resptr = nodnil()
+		} else {
+			resptr = Nod(OADDR, n.List.N, nil)
+		}
+		resptr.Etype = 1 // addr does not escape
+
+		if Debug_typeassert > 0 {
+			Warn("type assertion not inlined")
+		}
+		buf := "assert" + fromKind + "2" + toKind + "2"
+		fn := syslook(buf, 1)
+		substArgTypes(fn, from.Type, t)
+		call := mkcall1(fn, oktype, init, typename(t), from, resptr)
+		n = Nod(OAS, ok, call)
 		typecheck(&n, Etop)
 		goto ret
 
-	case ODOTTYPE,
-		ODOTTYPE2:
-		Fatal("walkexpr ODOTTYPE") // should see inside OAS or OAS2 only
+	case ODOTTYPE, ODOTTYPE2:
+		if !isdirectiface(n.Type) || Isfat(n.Type) {
+			Fatal("walkexpr ODOTTYPE") // should see inside OAS only
+		}
+		walkexpr(&n.Left, init)
+		goto ret
 
 	case OCONVIFACE:
 		walkexpr(&n.Left, init)
@@ -928,21 +950,9 @@
 		// Build name of function: convI2E etc.
 		// Not all names are possible
 		// (e.g., we'll never generate convE2E or convE2I).
-		from := "T"
-
-		to := "I"
-		if isnilinter(n.Left.Type) {
-			from = "E"
-		} else if Isinter(n.Left.Type) {
-			from = "I"
-		}
-		if isnilinter(n.Type) {
-			to = "E"
-		}
-		buf := fmt.Sprintf("conv%s2%s", from, to)
-
+		buf := "conv" + type2IET(n.Left.Type) + "2" + type2IET(n.Type)
 		fn := syslook(buf, 1)
-		ll := (*NodeList)(nil)
+		var ll *NodeList
 		if !Isinter(n.Left.Type) {
 			ll = list(ll, typename(n.Left.Type))
 		}
@@ -950,7 +960,7 @@
 			ll = list(ll, typename(n.Type))
 		}
 		if !Isinter(n.Left.Type) && !isnilinter(n.Type) {
-			sym := Pkglookup(fmt.Sprintf("%v.%v", Tconv(n.Left.Type, obj.FmtLeft), Tconv(n.Type, obj.FmtLeft)), itabpkg)
+			sym := Pkglookup(Tconv(n.Left.Type, obj.FmtLeft)+"."+Tconv(n.Type, obj.FmtLeft), itabpkg)
 			if sym.Def == nil {
 				l := Nod(ONAME, nil, nil)
 				l.Sym = sym
@@ -1008,7 +1018,7 @@
 			ll = list(ll, n.Left)
 		} else {
 			// regular types are passed by reference to avoid C vararg calls
-			// orderexpr arranged for n->left to be a temporary for all
+			// orderexpr arranged for n.Left to be a temporary for all
 			// the conversions it could see. comparison of an interface
 			// with a non-interface, especially in a switch on interface value
 			// with non-interface cases, is not visible to orderstmt, so we
@@ -1018,10 +1028,25 @@
 			} else {
 				ll = list(ll, Nod(OADDR, copyexpr(n.Left, n.Left.Type, init), nil))
 			}
+			dowidth(n.Left.Type)
+			r := nodnil()
+			if n.Esc == EscNone && n.Left.Type.Width <= 1024 {
+				// Allocate stack buffer for value stored in interface.
+				r = temp(n.Left.Type)
+				r = Nod(OAS, r, nil) // zero temp
+				typecheck(&r, Etop)
+				*init = list(*init, r)
+				r = Nod(OADDR, r.Left, nil)
+				typecheck(&r, Erv)
+			}
+			ll = list(ll, r)
 		}
 
-		argtype(fn, n.Left.Type)
-		argtype(fn, n.Type)
+		if !Isinter(n.Left.Type) {
+			substArgTypes(fn, n.Left.Type, n.Left.Type, n.Type)
+		} else {
+			substArgTypes(fn, n.Left.Type, n.Type)
+		}
 		dowidth(fn.Type)
 		n = Nod(OCALL, fn, nil)
 		n.List = ll
@@ -1029,10 +1054,9 @@
 		walkexpr(&n, init)
 		goto ret
 
-	case OCONV,
-		OCONVNOP:
+	case OCONV, OCONVNOP:
 		if Thearch.Thechar == '5' {
-			if Isfloat[n.Left.Type.Etype] != 0 {
+			if Isfloat[n.Left.Type.Etype] {
 				if n.Type.Etype == TINT64 {
 					n = mkcall("float64toint64", n.Type, init, conv(n.Left, Types[TFLOAT64]))
 					goto ret
@@ -1044,7 +1068,7 @@
 				}
 			}
 
-			if Isfloat[n.Type.Etype] != 0 {
+			if Isfloat[n.Type.Etype] {
 				if n.Left.Type.Etype == TINT64 {
 					n = mkcall("int64tofloat64", n.Type, init, conv(n.Left, Types[TINT64]))
 					goto ret
@@ -1074,8 +1098,7 @@
 		walkmul(&n, init)
 		goto ret
 
-	case ODIV,
-		OMOD:
+	case ODIV, OMOD:
 		walkexpr(&n.Left, init)
 		walkexpr(&n.Right, init)
 
@@ -1084,7 +1107,7 @@
 		 */
 		et := int(n.Left.Type.Etype)
 
-		if Iscomplex[et] != 0 && n.Op == ODIV {
+		if Iscomplex[et] && n.Op == ODIV {
 			t := n.Type
 			n = mkcall("complex128div", Types[TCOMPLEX128], init, conv(n.Left, Types[TCOMPLEX128]), conv(n.Right, Types[TCOMPLEX128]))
 			n = conv(n, t)
@@ -1092,7 +1115,7 @@
 		}
 
 		// Nothing to do for float divisions.
-		if Isfloat[et] != 0 {
+		if Isfloat[et] {
 			goto ret
 		}
 
@@ -1104,22 +1127,22 @@
 		 * on 32-bit architectures.
 		 */
 		switch n.Op {
-		case OMOD,
-			ODIV:
+		case OMOD, ODIV:
 			if Widthreg >= 8 || (et != TUINT64 && et != TINT64) {
 				goto ret
 			}
+			var fn string
 			if et == TINT64 {
-				namebuf = "int64"
+				fn = "int64"
 			} else {
-				namebuf = "uint64"
+				fn = "uint64"
 			}
 			if n.Op == ODIV {
-				namebuf += "div"
+				fn += "div"
 			} else {
-				namebuf += "mod"
+				fn += "mod"
 			}
-			n = mkcall(namebuf, n.Type, init, conv(n.Left, Types[et]), conv(n.Right, Types[et]))
+			n = mkcall(fn, n.Type, init, conv(n.Left, Types[et]), conv(n.Right, Types[et]))
 
 		default:
 			break
@@ -1142,7 +1165,7 @@
 			goto ret
 		}
 		t := n.Left.Type
-		if t != nil && Isptr[t.Etype] != 0 {
+		if t != nil && Isptr[t.Etype] {
 			t = t.Type
 		}
 		if Isfixedarray(t) {
@@ -1154,7 +1177,7 @@
 				Yyerror("index out of bounds")
 			}
 		} else if Isconst(n.Left, CTSTR) {
-			n.Bounded = bounded(r, int64(len(n.Left.Val.U.Sval.S)))
+			n.Bounded = bounded(r, int64(len(n.Left.Val.U.Sval)))
 			if Debug['m'] != 0 && n.Bounded && !Isconst(n.Right, CTINT) {
 				Warn("index bounds check elided")
 			}
@@ -1167,7 +1190,7 @@
 					// an ideal constant.
 					v := Mpgetfix(n.Right.Val.U.Xval)
 
-					Nodconst(n, n.Type, int64(n.Left.Val.U.Sval.S[v]))
+					Nodconst(n, n.Type, int64(n.Left.Val.U.Sval[v]))
 					n.Typecheck = 1
 				}
 			}
@@ -1191,12 +1214,10 @@
 		p := ""
 		if t.Type.Width <= 128 { // Check ../../runtime/hashmap.go:maxValueSize before changing.
 			switch Simsimtype(t.Down) {
-			case TINT32,
-				TUINT32:
+			case TINT32, TUINT32:
 				p = "mapaccess1_fast32"
 
-			case TINT64,
-				TUINT64:
+			case TINT64, TUINT64:
 				p = "mapaccess1_fast64"
 
 			case TSTRING:
@@ -1239,8 +1260,7 @@
 		fallthrough
 
 		// fallthrough
-	case OSLICEARR,
-		OSLICESTR:
+	case OSLICEARR, OSLICESTR:
 		if n.Right == nil { // already processed
 			goto ret
 		}
@@ -1258,11 +1278,10 @@
 		n.Right.Left = safeexpr(n.Right.Left, init)
 		walkexpr(&n.Right.Right, init)
 		n.Right.Right = safeexpr(n.Right.Right, init)
-		n = sliceany(n, init) // chops n->right, sets n->list
+		n = sliceany(n, init) // chops n.Right, sets n.List
 		goto ret
 
-	case OSLICE3,
-		OSLICE3ARR:
+	case OSLICE3, OSLICE3ARR:
 		if n.Right == nil { // already processed
 			goto ret
 		}
@@ -1282,7 +1301,7 @@
 		n.Right.Right.Left = safeexpr(n.Right.Right.Left, init)
 		walkexpr(&n.Right.Right.Right, init)
 		n.Right.Right.Right = safeexpr(n.Right.Right.Right, init)
-		n = sliceany(n, init) // chops n->right, sets n->list
+		n = sliceany(n, init) // chops n.Right, sets n.List
 		goto ret
 
 	case OADDR:
@@ -1308,7 +1327,7 @@
 	// comparing the lengths instead will yield the same result
 	// without the function call.
 	case OCMPSTR:
-		if (Isconst(n.Left, CTSTR) && len(n.Left.Val.U.Sval.S) == 0) || (Isconst(n.Right, CTSTR) && len(n.Right.Val.U.Sval.S) == 0) {
+		if (Isconst(n.Left, CTSTR) && len(n.Left.Val.U.Sval) == 0) || (Isconst(n.Right, CTSTR) && len(n.Right.Val.U.Sval) == 0) {
 			r := Nod(int(n.Etype), Nod(OLEN, n.Left, nil), Nod(OLEN, n.Right, nil))
 			typecheck(&r, Erv)
 			walkexpr(&r, init)
@@ -1370,7 +1389,7 @@
 		goto ret
 
 	case OAPPEND:
-		if n.Isddd != 0 {
+		if n.Isddd {
 			n = appendslice(n, init) // also works for append(slice, string).
 		} else {
 			n = walkappend(n, init)
@@ -1385,7 +1404,7 @@
 	case OCLOSE:
 		fn := syslook("closechan", 1)
 
-		argtype(fn, n.Left.Type)
+		substArgTypes(fn, n.Left.Type)
 		n = mkcall1(fn, nil, init, n.Left)
 		goto ret
 
@@ -1420,10 +1439,7 @@
 			r = Nod(OADDR, var_, nil)
 		}
 
-		argtype(fn, hmap(t))      // hmap buffer
-		argtype(fn, mapbucket(t)) // bucket buffer
-		argtype(fn, t.Down)       // key type
-		argtype(fn, t.Type)       // value type
+		substArgTypes(fn, hmap(t), mapbucket(t), t.Down, t.Type)
 		n = mkcall1(fn, n.Type, init, typename(n.Type), conv(n.Left, Types[TINT64]), a, r)
 		goto ret
 
@@ -1444,7 +1460,7 @@
 			typecheck(&a, Etop)
 			*init = list(*init, a)
 			r := Nod(OSLICE, var_, Nod(OKEY, nil, l)) // arr[:l]
-			r = conv(r, n.Type)                       // in case n->type is named.
+			r = conv(r, n.Type)                       // in case n.Type is named.
 			typecheck(&r, Erv)
 			walkexpr(&r, init)
 			n = r
@@ -1452,7 +1468,7 @@
 			// makeslice(t *Type, nel int64, max int64) (ary []any)
 			fn := syslook("makeslice", 1)
 
-			argtype(fn, t.Type) // any-1
+			substArgTypes(fn, t.Type) // any-1
 			n = mkcall1(fn, n.Type, init, typename(n.Type), conv(l, Types[TINT64]), conv(r, Types[TINT64]))
 		}
 
@@ -1553,8 +1569,7 @@
 
 		n.Right = cheapexpr(n.Right, init)
 		n.Left = cheapexpr(n.Left, init)
-		argtype(fn, n.Right.Type)
-		argtype(fn, n.Left.Type)
+		substArgTypes(fn, n.Right.Type, n.Left.Type)
 		r := mkcall1(fn, n.Type, init, n.Left, n.Right)
 		if n.Etype == ONE {
 			r = Nod(ONOT, r, nil)
@@ -1572,10 +1587,7 @@
 		n = r
 		goto ret
 
-	case OARRAYLIT,
-		OMAPLIT,
-		OSTRUCTLIT,
-		OPTRLIT:
+	case OARRAYLIT, OMAPLIT, OSTRUCTLIT, OPTRLIT:
 		var_ := temp(n.Type)
 		anylit(0, n, var_, init)
 		n = var_
@@ -1637,9 +1649,6 @@
 }
 
 func ascompatee(op int, nl *NodeList, nr *NodeList, init **NodeList) *NodeList {
-	var ll *NodeList
-	var lr *NodeList
-
 	/*
 	 * check assign expression list to
 	 * a expression list. called in
@@ -1647,17 +1656,17 @@
 	 */
 
 	// ensure order of evaluation for function calls
-	for ll = nl; ll != nil; ll = ll.Next {
+	for ll := nl; ll != nil; ll = ll.Next {
 		ll.N = safeexpr(ll.N, init)
 	}
-	for lr = nr; lr != nil; lr = lr.Next {
+	for lr := nr; lr != nil; lr = lr.Next {
 		lr.N = safeexpr(lr.N, init)
 	}
 
-	nn := (*NodeList)(nil)
-	ll = nl
-	lr = nr
-	for ; ll != nil && lr != nil; (func() { ll = ll.Next; lr = lr.Next })() {
+	var nn *NodeList
+	ll := nl
+	lr := nr
+	for ; ll != nil && lr != nil; ll, lr = ll.Next, lr.Next {
 		// Do not generate 'x = x' during return. See issue 4014.
 		if op == ORETURN && ll.N == lr.N {
 			continue
@@ -1682,7 +1691,7 @@
 	if l.Ullman >= UINF || l.Op == OINDEXMAP {
 		return true
 	}
-	r := Node{}
+	var r Node
 	if needwritebarrier(l, &r) {
 		return true
 	}
@@ -1706,8 +1715,8 @@
 	 */
 	r := Structfirst(&saver, nr)
 
-	nn := (*NodeList)(nil)
-	mm := (*NodeList)(nil)
+	var nn *NodeList
+	var mm *NodeList
 	ucount := 0
 	for ll = nl; ll != nil; ll = ll.Next {
 		if r == nil {
@@ -1757,9 +1766,9 @@
 * package all the arguments that match a ... T parameter into a []T.
  */
 func mkdotargslice(lr0 *NodeList, nn *NodeList, l *Type, fp int, init **NodeList, ddd *Node) *NodeList {
-	esc := EscUnknown
+	esc := uint8(EscUnknown)
 	if ddd != nil {
-		esc = int(ddd.Esc)
+		esc = ddd.Esc
 	}
 
 	tslice := typ(TARRAY)
@@ -1776,7 +1785,7 @@
 			n.Alloc = ddd.Alloc // temporary to use
 		}
 		n.List = lr0
-		n.Esc = uint(esc)
+		n.Esc = esc
 		typecheck(&n, Erv)
 		if n.Type == nil {
 			Fatal("mkdotargslice: typecheck failed")
@@ -1804,7 +1813,7 @@
 		} else {
 			fmt_ += ", "
 		}
-		fmt_ += fmt.Sprintf("%v", Tconv(l, 0))
+		fmt_ += Tconv(l, 0)
 	}
 
 	if first != 0 {
@@ -1826,7 +1835,7 @@
 		} else {
 			fmt_ += ", "
 		}
-		fmt_ += fmt.Sprintf("%v", Tconv(r.Type, 0))
+		fmt_ += Tconv(r.Type, 0)
 	}
 
 	if first != 0 {
@@ -1841,16 +1850,16 @@
  *	return expr-list
  *	func(expr-list)
  */
-func ascompatte(op int, call *Node, isddd int, nl **Type, lr *NodeList, fp int, init **NodeList) *NodeList {
+func ascompatte(op int, call *Node, isddd bool, nl **Type, lr *NodeList, fp int, init **NodeList) *NodeList {
 	var savel Iter
 
 	lr0 := lr
 	l := Structfirst(&savel, nl)
-	r := (*Node)(nil)
+	var r *Node
 	if lr != nil {
 		r = lr.N
 	}
-	nn := (*NodeList)(nil)
+	var nn *NodeList
 
 	// f(g()) where g has multiple return values
 	var a *Node
@@ -1869,7 +1878,7 @@
 
 		// conversions involved.
 		// copy into temporaries.
-		alist := (*NodeList)(nil)
+		var alist *NodeList
 
 		for l := Structfirst(&savel, &r.Type); l != nil; l = structnext(&savel) {
 			a = temp(l.Type)
@@ -1888,7 +1897,7 @@
 	}
 
 loop:
-	if l != nil && l.Isddd != 0 {
+	if l != nil && l.Isddd {
 		// the ddd parameter must be last
 		ll = structnext(&savel)
 
@@ -1900,7 +1909,7 @@
 		// only if we are assigning a single ddd
 		// argument to a ddd parameter then it is
 		// passed thru unencapsulated
-		if r != nil && lr.Next == nil && isddd != 0 && Eqtype(l.Type, r.Type) {
+		if r != nil && lr.Next == nil && isddd && Eqtype(l.Type, r.Type) {
 			a = Nod(OAS, nodarg(l, fp), r)
 			a = convas(a, init)
 			nn = list(nn, a)
@@ -1958,7 +1967,7 @@
 
 	op := int(nn.Op)
 	all := nn.List
-	calls := (*NodeList)(nil)
+	var calls *NodeList
 	notfirst := false
 
 	// Hoist all the argument evaluation up before the lock.
@@ -2004,14 +2013,14 @@
 			} else {
 				on = syslook("printiface", 1)
 			}
-			argtype(on, n.Type) // any-1
-		} else if Isptr[et] != 0 || et == TCHAN || et == TMAP || et == TFUNC || et == TUNSAFEPTR {
+			substArgTypes(on, n.Type) // any-1
+		} else if Isptr[et] || et == TCHAN || et == TMAP || et == TFUNC || et == TUNSAFEPTR {
 			on = syslook("printpointer", 1)
-			argtype(on, n.Type) // any-1
+			substArgTypes(on, n.Type) // any-1
 		} else if Isslice(n.Type) {
 			on = syslook("printslice", 1)
-			argtype(on, n.Type) // any-1
-		} else if Isint[et] != 0 {
+			substArgTypes(on, n.Type) // any-1
+		} else if Isint[et] {
 			if et == TUINT64 {
 				if (t.Sym.Pkg == Runtimepkg || compiling_runtime != 0) && t.Sym.Name == "hex" {
 					on = syslook("printhex", 0)
@@ -2021,9 +2030,9 @@
 			} else {
 				on = syslook("printint", 0)
 			}
-		} else if Isfloat[et] != 0 {
+		} else if Isfloat[et] {
 			on = syslook("printfloat", 0)
-		} else if Iscomplex[et] != 0 {
+		} else if Iscomplex[et] {
 			on = syslook("printcomplex", 0)
 		} else if et == TBOOL {
 			on = syslook("printbool", 0)
@@ -2071,7 +2080,7 @@
 func callnew(t *Type) *Node {
 	dowidth(t)
 	fn := syslook("newobject", 1)
-	argtype(fn, t)
+	substArgTypes(fn, t)
 	return mkcall1(fn, Ptrto(t), nil, typename(t))
 }
 
@@ -2094,9 +2103,7 @@
 
 	case ONAME:
 		switch n.Class {
-		case PAUTO,
-			PPARAM,
-			PPARAMOUT:
+		case PAUTO, PPARAM, PPARAMOUT:
 			return true
 		}
 	}
@@ -2174,12 +2181,9 @@
 	// generate the write barrier directly in that case.
 	// (It does not yet, but the cost of the write barrier will be
 	// small compared to the cost of the allocation.)
-	if r.Reslice != 0 {
+	if r.Reslice {
 		switch r.Op {
-		case OSLICE,
-			OSLICE3,
-			OSLICESTR,
-			OAPPEND:
+		case OSLICE, OSLICE3, OSLICESTR, OAPPEND:
 			break
 
 		default:
@@ -2196,11 +2200,11 @@
 
 // TODO(rsc): Perhaps componentgen should run before this.
 
-var applywritebarrier_bv *Bvec
+var applywritebarrier_bv Bvec
 
 func applywritebarrier(n *Node, init **NodeList) *Node {
 	if n.Left != nil && n.Right != nil && needwritebarrier(n.Left, n.Right) {
-		if Curfn != nil && Curfn.Nowritebarrier {
+		if Curfn != nil && Curfn.Func.Nowritebarrier {
 			Yyerror("write barrier prohibited")
 		}
 		t := n.Left.Type
@@ -2216,7 +2220,7 @@
 			n = mkcall1(writebarrierfn("writebarrieriface", t, n.Right.Type), nil, init, l, n.Right)
 		} else if t.Width <= int64(4*Widthptr) {
 			x := int64(0)
-			if applywritebarrier_bv == nil {
+			if applywritebarrier_bv.b == nil {
 				applywritebarrier_bv = bvalloc(obj.BitsPerPointer * 4)
 			}
 			bvresetall(applywritebarrier_bv)
@@ -2337,9 +2341,9 @@
 		return all
 	}
 
-	g := (*NodeList)(nil) // fncalls assigned to tempnames
-	f := (*Node)(nil)     // last fncall assigned to stack
-	r := (*NodeList)(nil) // non fncalls and tempnames assigned to stack
+	var g *NodeList // fncalls assigned to tempnames
+	var f *Node     // last fncall assigned to stack
+	var r *NodeList // non fncalls and tempnames assigned to stack
 	d := 0
 	var a *Node
 	for l := all; l != nil; l = l.Next {
@@ -2388,9 +2392,9 @@
 	// If a needed expression may be affected by an
 	// earlier assignment, make an early copy of that
 	// expression and use the copy instead.
-	early := (*NodeList)(nil)
+	var early *NodeList
 
-	mapinit := (*NodeList)(nil)
+	var mapinit *NodeList
 	for list := all; list != nil; list = list.Next {
 		l = list.N.Left
 
@@ -2418,16 +2422,14 @@
 		case ONAME:
 			break
 
-		case OINDEX,
-			OINDEXMAP:
+		case OINDEX, OINDEXMAP:
 			reorder3save(&l.Left, all, list, &early)
 			reorder3save(&l.Right, all, list, &early)
 			if l.Op == OINDEXMAP {
 				list.N = convas(list.N, &mapinit)
 			}
 
-		case OIND,
-			ODOTPTR:
+		case OIND, ODOTPTR:
 			reorder3save(&l.Left, all, list, &early)
 		}
 
@@ -2513,10 +2515,8 @@
 			varwrite = 1
 			continue
 
-		case PAUTO,
-			PPARAM,
-			PPARAMOUT:
-			if n.Addrtaken != 0 {
+		case PAUTO, PPARAM, PPARAMOUT:
+			if n.Addrtaken {
 				varwrite = 1
 				continue
 			}
@@ -2565,10 +2565,8 @@
 
 	case ONAME:
 		switch n.Class {
-		case PAUTO,
-			PPARAM,
-			PPARAMOUT:
-			if n.Addrtaken == 0 {
+		case PAUTO, PPARAM, PPARAMOUT:
+			if !n.Addrtaken {
 				return true
 			}
 		}
@@ -2636,7 +2634,7 @@
 
 /*
  * is any name mentioned in l also mentioned in r?
- * called by sinit.c
+ * called by sinit.go
  */
 func vmatch1(l *Node, r *Node) bool {
 	/*
@@ -2648,9 +2646,7 @@
 	switch l.Op {
 	case ONAME:
 		switch l.Class {
-		case PPARAM,
-			PPARAMREF,
-			PAUTO:
+		case PPARAM, PPARAMREF, PAUTO:
 			break
 
 			// assignment to non-stack variable
@@ -2691,7 +2687,7 @@
 	var v *Node
 	var as *Node
 
-	nn := (*NodeList)(nil)
+	var nn *NodeList
 	for t := Structfirst(&savet, argin); t != nil; t = structnext(&savet) {
 		v = t.Nname
 		if v != nil && v.Sym != nil && v.Sym.Name[0] == '~' && v.Sym.Name[1] == 'r' { // unnamed result
@@ -2738,7 +2734,7 @@
 	var savet Iter
 	var v *Node
 
-	nn := (*NodeList)(nil)
+	var nn *NodeList
 	for t := Structfirst(&savet, argin); t != nil; t = structnext(&savet) {
 		v = t.Nname
 		if v == nil || v.Class != PHEAP|PPARAMOUT {
@@ -2761,9 +2757,9 @@
 	nn := paramstoheap(getthis(Curfn.Type), 0)
 	nn = concat(nn, paramstoheap(getinarg(Curfn.Type), 0))
 	nn = concat(nn, paramstoheap(Getoutarg(Curfn.Type), 1))
-	Curfn.Enter = concat(Curfn.Enter, nn)
-	lineno = Curfn.Endlineno
-	Curfn.Exit = returnsfromheap(Getoutarg(Curfn.Type))
+	Curfn.Func.Enter = concat(Curfn.Func.Enter, nn)
+	lineno = Curfn.Func.Endlineno
+	Curfn.Func.Exit = returnsfromheap(Getoutarg(Curfn.Type))
 	lineno = lno
 }
 
@@ -2772,7 +2768,7 @@
 		Fatal("mkcall %v %v", Nconv(fn, 0), Tconv(fn.Type, 0))
 	}
 
-	args := (*NodeList)(nil)
+	var args *NodeList
 	n := fn.Type.Intuple
 	for i := 0; i < n; i++ {
 		args = list(args, va[i])
@@ -2813,8 +2809,13 @@
 		Fatal("chanfn %v", Tconv(t, 0))
 	}
 	fn := syslook(name, 1)
-	for i := 0; i < n; i++ {
-		argtype(fn, t.Type)
+	switch n {
+	default:
+		Fatal("chanfn %d", n)
+	case 1:
+		substArgTypes(fn, t.Type)
+	case 2:
+		substArgTypes(fn, t.Type, t.Type)
 	}
 	return fn
 }
@@ -2824,10 +2825,7 @@
 		Fatal("mapfn %v", Tconv(t, 0))
 	}
 	fn := syslook(name, 1)
-	argtype(fn, t.Down)
-	argtype(fn, t.Type)
-	argtype(fn, t.Down)
-	argtype(fn, t.Type)
+	substArgTypes(fn, t.Down, t.Type, t.Down, t.Type)
 	return fn
 }
 
@@ -2836,16 +2834,13 @@
 		Fatal("mapfn %v", Tconv(t, 0))
 	}
 	fn := syslook(name, 1)
-	argtype(fn, t.Down)
-	argtype(fn, t.Type)
-	argtype(fn, t.Down)
+	substArgTypes(fn, t.Down, t.Type, t.Down)
 	return fn
 }
 
 func writebarrierfn(name string, l *Type, r *Type) *Node {
 	fn := syslook(name, 1)
-	argtype(fn, l)
-	argtype(fn, r)
+	substArgTypes(fn, l, r)
 	return fn
 }
 
@@ -2862,7 +2857,7 @@
 		sz := int64(0)
 		for l := n.List; l != nil; l = l.Next {
 			if n.Op == OLITERAL {
-				sz += int64(len(n.Val.U.Sval.S))
+				sz += int64(len(n.Val.U.Sval))
 			}
 		}
 
@@ -2882,13 +2877,14 @@
 		args = list(args, conv(l.N, Types[TSTRING]))
 	}
 
+	var fn string
 	if c <= 5 {
 		// small numbers of strings use direct runtime helpers.
 		// note: orderexpr knows this cutoff too.
-		namebuf = fmt.Sprintf("concatstring%d", c)
+		fn = fmt.Sprintf("concatstring%d", c)
 	} else {
 		// large numbers of strings are passed to the runtime as a slice.
-		namebuf = "concatstrings"
+		fn = "concatstrings"
 
 		t := typ(TARRAY)
 		t.Type = Types[TSTRING]
@@ -2901,7 +2897,7 @@
 		slice.Esc = EscNone
 	}
 
-	cat := syslook(namebuf, 1)
+	cat := syslook(fn, 1)
 	r := Nod(OCALL, cat, nil)
 	r.List = args
 	typecheck(&r, Erv)
@@ -2937,7 +2933,7 @@
 	l2 := n.List.Next.N
 
 	s := temp(l1.Type) // var s []T
-	l := (*NodeList)(nil)
+	var l *NodeList
 	l = list(l, Nod(OAS, s, l1)) // s = l1
 
 	nt := temp(Types[TINT])
@@ -2949,14 +2945,12 @@
 
 	nif.Ntest = Nod(OGT, nt, Nodintconst(0))
 
-	// instantiate growslice(Type*, []any, int64) []any
-	fn := syslook("growslice", 1)
-
-	argtype(fn, s.Type.Type)
-	argtype(fn, s.Type.Type)
+	// instantiate growslice(Type*, []any, int) []any
+	fn := syslook("growslice", 1) //   growslice(<type>, old []T, n int64) (ret []T)
+	substArgTypes(fn, s.Type.Type, s.Type.Type)
 
 	// s = growslice(T, s, n)
-	nif.Nbody = list1(Nod(OAS, s, mkcall1(fn, s.Type, &nif.Ninit, typename(s.Type), s, conv(nt, Types[TINT64]))))
+	nif.Nbody = list1(Nod(OAS, s, mkcall1(fn, s.Type, &nif.Ninit, typename(s.Type), s, nt)))
 
 	l = list(l, nif)
 
@@ -2967,8 +2961,7 @@
 		nptr1.Etype = 1
 		nptr2 := l2
 		fn := syslook("typedslicecopy", 1)
-		argtype(fn, l1.Type)
-		argtype(fn, l2.Type)
+		substArgTypes(fn, l1.Type, l2.Type)
 		nt := mkcall1(fn, Types[TINT], &l, typename(l1.Type.Type), nptr1, nptr2)
 		l = list(l, nt)
 	} else if flag_race != 0 {
@@ -2984,8 +2977,7 @@
 		} else {
 			fn = syslook("slicecopy", 1)
 		}
-		argtype(fn, l1.Type)
-		argtype(fn, l2.Type)
+		substArgTypes(fn, l1.Type, l2.Type)
 		nt := mkcall1(fn, Types[TINT], &l, nptr1, nptr2, Nodintconst(s.Type.Type.Width))
 		l = list(l, nt)
 	} else {
@@ -2998,8 +2990,7 @@
 		nptr2 := Nod(OSPTR, l2, nil)
 
 		fn := syslook("memmove", 1)
-		argtype(fn, s.Type.Type) // 1 old []any
-		argtype(fn, s.Type.Type) // 2 ret []any
+		substArgTypes(fn, s.Type.Type, s.Type.Type)
 
 		nwid := cheapexpr(conv(Nod(OLEN, l2, nil), Types[TUINTPTR]), &l)
 
@@ -3057,7 +3048,7 @@
 		return nsrc
 	}
 
-	l := (*NodeList)(nil)
+	var l *NodeList
 
 	ns := temp(nsrc.Type)
 	l = list(l, Nod(OAS, ns, nsrc)) // s = src
@@ -3066,11 +3057,10 @@
 	nx := Nod(OIF, nil, nil)       // if cap(s) - len(s) < argc
 	nx.Ntest = Nod(OLT, Nod(OSUB, Nod(OCAP, ns, nil), Nod(OLEN, ns, nil)), na)
 
-	fn := syslook("growslice", 1) //   growslice(<type>, old []T, n int64) (ret []T)
-	argtype(fn, ns.Type.Type)     // 1 old []any
-	argtype(fn, ns.Type.Type)     // 2 ret []any
+	fn := syslook("growslice", 1) //   growslice(<type>, old []T, n int) (ret []T)
+	substArgTypes(fn, ns.Type.Type, ns.Type.Type)
 
-	nx.Nbody = list1(Nod(OAS, ns, mkcall1(fn, ns.Type, &nx.Ninit, typename(ns.Type), ns, conv(na, Types[TINT64]))))
+	nx.Nbody = list1(Nod(OAS, ns, mkcall1(fn, ns.Type, &nx.Ninit, typename(ns.Type), ns, na)))
 
 	l = list(l, nx)
 
@@ -3120,8 +3110,7 @@
 		} else {
 			fn = syslook("slicecopy", 1)
 		}
-		argtype(fn, n.Left.Type)
-		argtype(fn, n.Right.Type)
+		substArgTypes(fn, n.Left.Type, n.Right.Type)
 		return mkcall1(fn, n.Type, init, n.Left, n.Right, Nodintconst(n.Left.Type.Type.Width))
 	}
 
@@ -3129,7 +3118,7 @@
 	walkexpr(&n.Right, init)
 	nl := temp(n.Left.Type)
 	nr := temp(n.Right.Type)
-	l := (*NodeList)(nil)
+	var l *NodeList
 	l = list(l, Nod(OAS, nl, n.Left))
 	l = list(l, Nod(OAS, nr, n.Right))
 
@@ -3151,8 +3140,7 @@
 	// Call memmove.
 	fn := syslook("memmove", 1)
 
-	argtype(fn, nl.Type.Type)
-	argtype(fn, nl.Type.Type)
+	substArgTypes(fn, nl.Type.Type, nl.Type.Type)
 	nwid := temp(Types[TUINTPTR])
 	l = list(l, Nod(OAS, nwid, conv(nlen, Types[TUINTPTR])))
 	nwid = Nod(OMUL, nwid, Nodintconst(nl.Type.Type.Width))
@@ -3235,9 +3223,6 @@
 
 	// Checking src[lb:hb:cb] or src[lb:hb].
 	// if chk0 || chk1 || chk2 { panicslice() }
-	chk0 := (*Node)(nil) // cap(src) < cb
-	chk1 := (*Node)(nil) // cb < hb for src[lb:hb:cb]; cap(src) < hb for src[lb:hb]
-	chk2 := (*Node)(nil) // hb < lb
 
 	// All comparisons are unsigned to avoid testing < 0.
 	bt := Types[Simtype[TUINT]]
@@ -3254,6 +3239,7 @@
 
 	bound = cheapexpr(conv(bound, bt), init)
 
+	var chk0 *Node // cap(src) < cb
 	if cb != nil {
 		cb = cheapexpr(conv(cb, bt), init)
 		if bounded == 0 {
@@ -3264,6 +3250,7 @@
 		Fatal("slice3 with cb == N") // rejected by parser
 	}
 
+	var chk1 *Node // cb < hb for src[lb:hb:cb]; cap(src) < hb for src[lb:hb]
 	if hb != nil {
 		hb = cheapexpr(conv(hb, bt), init)
 		if bounded == 0 {
@@ -3285,6 +3272,7 @@
 		hb = cheapexpr(conv(hb, bt), init)
 	}
 
+	var chk2 *Node // hb < lb
 	if lb != nil {
 		lb = cheapexpr(conv(lb, bt), init)
 		if bounded == 0 {
@@ -3384,8 +3372,7 @@
 
 	if a == AMEM {
 		n := syslook("memequal", 1)
-		argtype(n, t)
-		argtype(n, t)
+		substArgTypes(n, t, t)
 		*needsize = 1
 		return n
 	}
@@ -3421,9 +3408,9 @@
 	// Handle != similarly.
 	// This avoids the allocation that would be required
 	// to convert r to l for comparison.
-	l := (*Node)(nil)
+	var l *Node
 
-	r := (*Node)(nil)
+	var r *Node
 	if Isinter(n.Left.Type) && !Isinter(n.Right.Type) {
 		l = n.Left
 		r = n.Right
@@ -3432,14 +3419,6 @@
 		r = n.Left
 	}
 
-	var call *Node
-	var a *Node
-	var cmpl *Node
-	var cmpr *Node
-	var andor int
-	var expr *Node
-	var needsize int
-	var t *Type
 	if l != nil {
 		x := temp(r.Type)
 		ok := temp(Types[TBOOL])
@@ -3464,12 +3443,13 @@
 			r = Nod(OOROR, Nod(ONOT, ok, nil), Nod(ONE, x, r))
 		}
 		*init = list(*init, expr)
-		goto ret
+		finishcompare(np, n, r, init)
+		return
 	}
 
 	// Must be comparison of array or struct.
 	// Otherwise back end handles it.
-	t = n.Left.Type
+	t := n.Left.Type
 
 	switch t.Etype {
 	default:
@@ -3484,11 +3464,11 @@
 		break
 	}
 
-	cmpl = n.Left
+	cmpl := n.Left
 	for cmpl != nil && cmpl.Op == OCONVNOP {
 		cmpl = cmpl.Left
 	}
-	cmpr = n.Right
+	cmpr := n.Right
 	for cmpr != nil && cmpr.Op == OCONVNOP {
 		cmpr = cmpr.Left
 	}
@@ -3498,7 +3478,7 @@
 	}
 
 	l = temp(Ptrto(t))
-	a = Nod(OAS, l, Nod(OADDR, cmpl, nil))
+	a := Nod(OAS, l, Nod(OADDR, cmpl, nil))
 	a.Right.Etype = 1 // addr does not escape
 	typecheck(&a, Etop)
 	*init = list(*init, a)
@@ -3509,13 +3489,13 @@
 	typecheck(&a, Etop)
 	*init = list(*init, a)
 
-	expr = nil
-	andor = OANDAND
+	andor := OANDAND
 	if n.Op == ONE {
 		andor = OOROR
 	}
 
-	if t.Etype == TARRAY && t.Bound <= 4 && issimple[t.Type.Etype] != 0 {
+	var expr *Node
+	if t.Etype == TARRAY && t.Bound <= 4 && issimple[t.Type.Etype] {
 		// Four or fewer elements of a basic type.
 		// Unroll comparisons.
 		var li *Node
@@ -3534,8 +3514,8 @@
 		if expr == nil {
 			expr = Nodbool(n.Op == OEQ)
 		}
-		r = expr
-		goto ret
+		finishcompare(np, n, expr, init)
+		return
 	}
 
 	if t.Etype == TSTRUCT && countfield(t) <= 4 {
@@ -3560,12 +3540,13 @@
 		if expr == nil {
 			expr = Nodbool(n.Op == OEQ)
 		}
-		r = expr
-		goto ret
+		finishcompare(np, n, expr, init)
+		return
 	}
 
 	// Chose not to inline.  Call equality function directly.
-	call = Nod(OCALL, eqfor(t, &needsize), nil)
+	var needsize int
+	call := Nod(OCALL, eqfor(t, &needsize), nil)
 
 	call.List = list(call.List, l)
 	call.List = list(call.List, r)
@@ -3576,19 +3557,23 @@
 	if n.Op != OEQ {
 		r = Nod(ONOT, r, nil)
 	}
-	goto ret
 
-ret:
-	typecheck(&r, Erv)
-	walkexpr(&r, init)
+	finishcompare(np, n, r, init)
+	return
+}
+
+func finishcompare(np **Node, n, r *Node, init **NodeList) {
+	// Using np here to avoid passing &r to typecheck.
+	*np = r
+	typecheck(np, Erv)
+	walkexpr(np, init)
+	r = *np
 	if r.Type != n.Type {
 		r = Nod(OCONVNOP, r, nil)
 		r.Type = n.Type
 		r.Typecheck = 1
+		*np = r
 	}
-
-	*np = r
-	return
 }
 
 func samecheap(a *Node, b *Node) bool {
@@ -3602,8 +3587,7 @@
 		case ONAME:
 			return a == b
 
-		case ODOT,
-			ODOTPTR:
+		case ODOT, ODOTPTR:
 			ar = a.Right
 			br = b.Right
 			if ar.Op != ONAME || br.Op != ONAME || ar.Sym != br.Sym {
@@ -3626,7 +3610,7 @@
 }
 
 func walkrotate(np **Node) {
-	if Thearch.Thechar == '9' {
+	if Thearch.Thechar == '7' || Thearch.Thechar == '9' {
 		return
 	}
 
@@ -3636,7 +3620,7 @@
 	l := n.Left
 
 	r := n.Right
-	if (n.Op != OOR && n.Op != OXOR) || (l.Op != OLSH && l.Op != ORSH) || (r.Op != OLSH && r.Op != ORSH) || n.Type == nil || Issigned[n.Type.Etype] != 0 || l.Op == r.Op {
+	if (n.Op != OOR && n.Op != OXOR) || (l.Op != OLSH && l.Op != ORSH) || (r.Op != OLSH && r.Op != ORSH) || n.Type == nil || Issigned[n.Type.Etype] || l.Op == r.Op {
 		return
 	}
 
@@ -3653,7 +3637,23 @@
 		if sl >= 0 {
 			sr := int(Mpgetfix(r.Right.Val.U.Xval))
 			if sr >= 0 && sl+sr == w {
-				goto yes
+				// Rewrite left shift half to left rotate.
+				if l.Op == OLSH {
+					n = l
+				} else {
+					n = r
+				}
+				n.Op = OLROT
+
+				// Remove rotate 0 and rotate w.
+				s := int(Mpgetfix(n.Right.Val.U.Xval))
+
+				if s == 0 || s == w {
+					n = n.Left
+				}
+
+				*np = n
+				return
 			}
 		}
 		return
@@ -3661,25 +3661,6 @@
 
 	// TODO: Could allow s and 32-s if s is bounded (maybe s&31 and 32-s&31).
 	return
-
-	// Rewrite left shift half to left rotate.
-yes:
-	if l.Op == OLSH {
-		n = l
-	} else {
-		n = r
-	}
-	n.Op = OLROT
-
-	// Remove rotate 0 and rotate w.
-	s := int(Mpgetfix(n.Right.Val.U.Xval))
-
-	if s == 0 || s == w {
-		n = n.Left
-	}
-
-	*np = n
-	return
 }
 
 /*
@@ -3687,7 +3668,7 @@
  */
 func walkmul(np **Node, init **NodeList) {
 	n := *np
-	if Isint[n.Type.Etype] == 0 {
+	if !Isint[n.Type.Etype] {
 		return
 	}
 
@@ -3761,7 +3742,7 @@
 	// if >= 0, nr is 1<<pow // 1 if nr is negative.
 
 	// TODO(minux)
-	if Thearch.Thechar == '9' {
+	if Thearch.Thechar == '7' || Thearch.Thechar == '9' {
 		return
 	}
 
@@ -3779,8 +3760,8 @@
 	// by a constant
 	w := int(nl.Type.Width * 8)
 
-	s := 0
-	pow := powtwo(nr)
+	s := 0            // 1 if nr is negative.
+	pow := powtwo(nr) // if >= 0, nr is 1<<pow
 	if pow >= 1000 {
 		// negative power of 2
 		s = 1
@@ -3793,11 +3774,118 @@
 		return
 	}
 
-	var n1 *Node
-	var m Magic
-	var n2 *Node
 	if pow < 0 {
-		goto divbymul
+		// try to do division by multiply by (2^w)/d
+		// see hacker's delight chapter 10
+		// TODO: support 64-bit magic multiply here.
+		var m Magic
+		m.W = w
+
+		if Issigned[nl.Type.Etype] {
+			m.Sd = Mpgetfix(nr.Val.U.Xval)
+			Smagic(&m)
+		} else {
+			m.Ud = uint64(Mpgetfix(nr.Val.U.Xval))
+			Umagic(&m)
+		}
+
+		if m.Bad != 0 {
+			return
+		}
+
+		// We have a quick division method so use it
+		// for modulo too.
+		if n.Op == OMOD {
+			// rewrite as A%B = A - (A/B*B).
+			n1 := Nod(ODIV, nl, nr)
+
+			n2 := Nod(OMUL, n1, nr)
+			n = Nod(OSUB, nl, n2)
+			goto ret
+		}
+
+		switch Simtype[nl.Type.Etype] {
+		default:
+			return
+
+			// n1 = nl * magic >> w (HMUL)
+		case TUINT8, TUINT16, TUINT32:
+			nc := Nod(OXXX, nil, nil)
+
+			Nodconst(nc, nl.Type, int64(m.Um))
+			n1 := Nod(OMUL, nl, nc)
+			typecheck(&n1, Erv)
+			n1.Op = OHMUL
+			if m.Ua != 0 {
+				// Select a Go type with (at least) twice the width.
+				var twide *Type
+				switch Simtype[nl.Type.Etype] {
+				default:
+					return
+
+				case TUINT8, TUINT16:
+					twide = Types[TUINT32]
+
+				case TUINT32:
+					twide = Types[TUINT64]
+
+				case TINT8, TINT16:
+					twide = Types[TINT32]
+
+				case TINT32:
+					twide = Types[TINT64]
+				}
+
+				// add numerator (might overflow).
+				// n2 = (n1 + nl)
+				n2 := Nod(OADD, conv(n1, twide), conv(nl, twide))
+
+				// shift by m.s
+				nc := Nod(OXXX, nil, nil)
+
+				Nodconst(nc, Types[TUINT], int64(m.S))
+				n = conv(Nod(ORSH, n2, nc), nl.Type)
+			} else {
+				// n = n1 >> m.s
+				nc := Nod(OXXX, nil, nil)
+
+				Nodconst(nc, Types[TUINT], int64(m.S))
+				n = Nod(ORSH, n1, nc)
+			}
+
+			// n1 = nl * magic >> w
+		case TINT8, TINT16, TINT32:
+			nc := Nod(OXXX, nil, nil)
+
+			Nodconst(nc, nl.Type, m.Sm)
+			n1 := Nod(OMUL, nl, nc)
+			typecheck(&n1, Erv)
+			n1.Op = OHMUL
+			if m.Sm < 0 {
+				// add the numerator.
+				n1 = Nod(OADD, n1, nl)
+			}
+
+			// shift by m.s
+			nc = Nod(OXXX, nil, nil)
+
+			Nodconst(nc, Types[TUINT], int64(m.S))
+			n2 := conv(Nod(ORSH, n1, nc), nl.Type)
+
+			// add 1 iff n1 is negative.
+			nc = Nod(OXXX, nil, nil)
+
+			Nodconst(nc, Types[TUINT], int64(w)-1)
+			n3 := Nod(ORSH, nl, nc) // n4 = -1 iff n1 is negative.
+			n = Nod(OSUB, n2, n3)
+
+			// apply sign.
+			if m.Sd < 0 {
+				n = Nod(OMINUS, n, nil)
+			}
+		}
+
+		goto ret
 	}
 
 	switch pow {
@@ -3816,7 +3904,7 @@
 		}
 
 	default:
-		if Issigned[n.Type.Etype] != 0 {
+		if Issigned[n.Type.Etype] {
 			if n.Op == OMOD {
 				// signed modulo 2^pow is like ANDing
 				// with the last pow bits, but if nl < 0,
@@ -3905,127 +3993,6 @@
 
 	goto ret
 
-	// try to do division by multiply by (2^w)/d
-	// see hacker's delight chapter 10
-	// TODO: support 64-bit magic multiply here.
-divbymul:
-	m.W = w
-
-	if Issigned[nl.Type.Etype] != 0 {
-		m.Sd = Mpgetfix(nr.Val.U.Xval)
-		Smagic(&m)
-	} else {
-		m.Ud = uint64(Mpgetfix(nr.Val.U.Xval))
-		Umagic(&m)
-	}
-
-	if m.Bad != 0 {
-		return
-	}
-
-	// We have a quick division method so use it
-	// for modulo too.
-	if n.Op == OMOD {
-		goto longmod
-	}
-
-	switch Simtype[nl.Type.Etype] {
-	default:
-		return
-
-		// n1 = nl * magic >> w (HMUL)
-	case TUINT8,
-		TUINT16,
-		TUINT32:
-		nc := Nod(OXXX, nil, nil)
-
-		Nodconst(nc, nl.Type, int64(m.Um))
-		n1 := Nod(OMUL, nl, nc)
-		typecheck(&n1, Erv)
-		n1.Op = OHMUL
-		if m.Ua != 0 {
-			// Select a Go type with (at least) twice the width.
-			var twide *Type
-			switch Simtype[nl.Type.Etype] {
-			default:
-				return
-
-			case TUINT8,
-				TUINT16:
-				twide = Types[TUINT32]
-
-			case TUINT32:
-				twide = Types[TUINT64]
-
-			case TINT8,
-				TINT16:
-				twide = Types[TINT32]
-
-			case TINT32:
-				twide = Types[TINT64]
-			}
-
-			// add numerator (might overflow).
-			// n2 = (n1 + nl)
-			n2 := Nod(OADD, conv(n1, twide), conv(nl, twide))
-
-			// shift by m.s
-			nc := Nod(OXXX, nil, nil)
-
-			Nodconst(nc, Types[TUINT], int64(m.S))
-			n = conv(Nod(ORSH, n2, nc), nl.Type)
-		} else {
-			// n = n1 >> m.s
-			nc := Nod(OXXX, nil, nil)
-
-			Nodconst(nc, Types[TUINT], int64(m.S))
-			n = Nod(ORSH, n1, nc)
-		}
-
-		// n1 = nl * magic >> w
-	case TINT8,
-		TINT16,
-		TINT32:
-		nc := Nod(OXXX, nil, nil)
-
-		Nodconst(nc, nl.Type, m.Sm)
-		n1 := Nod(OMUL, nl, nc)
-		typecheck(&n1, Erv)
-		n1.Op = OHMUL
-		if m.Sm < 0 {
-			// add the numerator.
-			n1 = Nod(OADD, n1, nl)
-		}
-
-		// shift by m.s
-		nc = Nod(OXXX, nil, nil)
-
-		Nodconst(nc, Types[TUINT], int64(m.S))
-		n2 := conv(Nod(ORSH, n1, nc), nl.Type)
-
-		// add 1 iff n1 is negative.
-		nc = Nod(OXXX, nil, nil)
-
-		Nodconst(nc, Types[TUINT], int64(w)-1)
-		n3 := Nod(ORSH, nl, nc) // n4 = -1 iff n1 is negative.
-		n = Nod(OSUB, n2, n3)
-
-		// apply sign.
-		if m.Sd < 0 {
-			n = Nod(OMINUS, n, nil)
-		}
-	}
-
-	goto ret
-
-	// rewrite as A%B = A - (A/B*B).
-longmod:
-	n1 = Nod(ODIV, nl, nr)
-
-	n2 = Nod(OMUL, n1, nr)
-	n = Nod(OSUB, nl, n2)
-	goto ret
-
 ret:
 	typecheck(&n, Erv)
 	walkexpr(&n, init)
@@ -4034,11 +4001,11 @@
 
 // return 1 if integer n must be in range [0, max), 0 otherwise
 func bounded(n *Node, max int64) bool {
-	if n.Type == nil || Isint[n.Type.Etype] == 0 {
+	if n.Type == nil || !Isint[n.Type.Etype] {
 		return false
 	}
 
-	sign := int(Issigned[n.Type.Etype])
+	sign := Issigned[n.Type.Etype]
 	bits := int32(8 * n.Type.Width)
 
 	if Smallintconst(n) {
@@ -4060,7 +4027,7 @@
 		}
 
 	case OMOD:
-		if sign == 0 && Smallintconst(n.Right) {
+		if !sign && Smallintconst(n.Right) {
 			v := Mpgetfix(n.Right.Val.U.Xval)
 			if 0 <= v && v <= max {
 				return true
@@ -4068,7 +4035,7 @@
 		}
 
 	case ODIV:
-		if sign == 0 && Smallintconst(n.Right) {
+		if !sign && Smallintconst(n.Right) {
 			v := Mpgetfix(n.Right.Val.U.Xval)
 			for bits > 0 && v >= 2 {
 				bits--
@@ -4077,7 +4044,7 @@
 		}
 
 	case ORSH:
-		if sign == 0 && Smallintconst(n.Right) {
+		if !sign && Smallintconst(n.Right) {
 			v := Mpgetfix(n.Right.Val.U.Xval)
 			if v > int64(bits) {
 				return true
@@ -4086,7 +4053,7 @@
 		}
 	}
 
-	if sign == 0 && bits <= 62 && 1<<uint(bits) <= max {
+	if !sign && bits <= 62 && 1<<uint(bits) <= max {
 		return true
 	}
 
@@ -4102,8 +4069,7 @@
 	default:
 		Fatal("usefield %v", Oconv(int(n.Op), 0))
 
-	case ODOT,
-		ODOTPTR:
+	case ODOT, ODOTPTR:
 		break
 	}
 
@@ -4111,7 +4077,7 @@
 	if field == nil {
 		Fatal("usefield %v %v without paramfld", Tconv(n.Left.Type, 0), Sconv(n.Right.Sym, 0))
 	}
-	if field.Note == nil || !strings.Contains(field.Note.S, "go:\"track\"") {
+	if field.Note == nil || !strings.Contains(*field.Note, "go:\"track\"") {
 		return
 	}
 
@@ -4121,7 +4087,7 @@
 	}
 	field.Lastfn = Curfn
 	field.Outer = n.Left.Type
-	if Isptr[field.Outer.Etype] != 0 {
+	if Isptr[field.Outer.Etype] {
 		field.Outer = field.Outer.Type
 	}
 	if field.Outer.Sym == nil {
@@ -4211,8 +4177,7 @@
 		break
 
 		// Discardable as long as we know it's not division by zero.
-	case ODIV,
-		OMOD:
+	case ODIV, OMOD:
 		if Isconst(n.Right, CTINT) && mpcmpfixc(n.Right.Val.U.Xval, 0) != 0 {
 			break
 		}
@@ -4222,8 +4187,7 @@
 		return false
 
 		// Discardable as long as we know it won't fail because of a bad size.
-	case OMAKECHAN,
-		OMAKEMAP:
+	case OMAKECHAN, OMAKEMAP:
 		if Isconst(n.Left, CTINT) && mpcmpfixc(n.Left.Val.U.Xval, 0) == 0 {
 			break
 		}
@@ -4262,7 +4226,7 @@
 
 	t := Nod(OTFUNC, nil, nil)
 	num := 0
-	printargs := (*NodeList)(nil)
+	var printargs *NodeList
 	var a *Node
 	var buf string
 	for l := n.List; l != nil; l = l.Next {
diff --git a/src/cmd/internal/gc/y.go b/src/cmd/internal/gc/y.go
index b05fe8f..8b272ec 100644
--- a/src/cmd/internal/gc/y.go
+++ b/src/cmd/internal/gc/y.go
@@ -1226,15 +1226,15 @@
 		{
 			if importpkg.Name == "" {
 				importpkg.Name = yyDollar[2].sym.Name
-				Pkglookup(yyDollar[2].sym.Name, nil).Npkg++
+				numImport[yyDollar[2].sym.Name]++
 			} else if importpkg.Name != yyDollar[2].sym.Name {
-				Yyerror("conflicting names %s and %s for package \"%v\"", importpkg.Name, yyDollar[2].sym.Name, Zconv(importpkg.Path, 0))
+				Yyerror("conflicting names %s and %s for package %q", importpkg.Name, yyDollar[2].sym.Name, importpkg.Path)
 			}
 			importpkg.Direct = 1
 			importpkg.Safe = curio.importsafe
 
 			if safemode != 0 && !curio.importsafe {
-				Yyerror("cannot import unsafe package \"%v\"", Zconv(importpkg.Path, 0))
+				Yyerror("cannot import unsafe package %q", importpkg.Path)
 			}
 		}
 	case 20:
@@ -1416,7 +1416,7 @@
 		yyDollar = yyS[yypt-2 : yypt+1]
 		//line go.y:406
 		{
-			yyVAL.node = typedcl1(yyDollar[1].node, yyDollar[2].node, 1)
+			yyVAL.node = typedcl1(yyDollar[1].node, yyDollar[2].node, true)
 		}
 	case 49:
 		yyDollar = yyS[yypt-1 : yypt+1]
@@ -1430,7 +1430,7 @@
 			switch yyVAL.node.Op {
 			case ONAME, ONONAME, OTYPE, OPACK, OLITERAL:
 				yyVAL.node = Nod(OPAREN, yyVAL.node, nil)
-				yyVAL.node.Implicit = 1
+				yyVAL.node.Implicit = true
 				break
 			}
 		}
@@ -1480,7 +1480,7 @@
 		//line go.y:461
 		{
 			yyVAL.node = Nod(OASOP, yyDollar[1].node, Nodintconst(1))
-			yyVAL.node.Implicit = 1
+			yyVAL.node.Implicit = true
 			yyVAL.node.Etype = OADD
 		}
 	case 54:
@@ -1488,7 +1488,7 @@
 		//line go.y:467
 		{
 			yyVAL.node = Nod(OASOP, yyDollar[1].node, Nodintconst(1))
-			yyVAL.node.Implicit = 1
+			yyVAL.node.Implicit = true
 			yyVAL.node.Etype = OSUB
 		}
 	case 55:
@@ -1991,7 +1991,7 @@
 				// Special case for &T{...}: turn into (*T){...}.
 				yyVAL.node = yyDollar[2].node
 				yyVAL.node.Right = Nod(OIND, yyVAL.node.Right, nil)
-				yyVAL.node.Right.Implicit = 1
+				yyVAL.node.Right.Implicit = true
 			} else {
 				yyVAL.node = Nod(OADDR, yyDollar[2].node, nil)
 			}
@@ -2052,7 +2052,7 @@
 		{
 			yyVAL.node = Nod(OCALL, yyDollar[1].node, nil)
 			yyVAL.node.List = yyDollar[3].list
-			yyVAL.node.Isddd = 1
+			yyVAL.node.Isddd = true
 		}
 	case 126:
 		yyDollar = yyS[yypt-1 : yypt+1]
@@ -2069,7 +2069,7 @@
 			if yyDollar[1].node.Op == OPACK {
 				var s *Sym
 				s = restrictlookup(yyDollar[3].sym.Name, yyDollar[1].node.Pkg)
-				yyDollar[1].node.Used = 1
+				yyDollar[1].node.Used = true
 				yyVAL.node = oldname(s)
 				break
 			}
@@ -2175,7 +2175,7 @@
 			switch yyVAL.node.Op {
 			case ONAME, ONONAME, OTYPE, OPACK, OLITERAL:
 				yyVAL.node = Nod(OPAREN, yyVAL.node, nil)
-				yyVAL.node.Implicit = 1
+				yyVAL.node.Implicit = true
 			}
 		}
 	case 143:
@@ -2276,7 +2276,7 @@
 		{
 			var p *Pkg
 
-			if yyDollar[2].val.U.Sval.S == "" {
+			if yyDollar[2].val.U.Sval == "" {
 				p = importpkg
 			} else {
 				if isbadimport(yyDollar[2].val.U.Sval) {
@@ -2292,7 +2292,7 @@
 		{
 			var p *Pkg
 
-			if yyDollar[2].val.U.Sval.S == "" {
+			if yyDollar[2].val.U.Sval == "" {
 				p = importpkg
 			} else {
 				if isbadimport(yyDollar[2].val.U.Sval) {
@@ -2308,7 +2308,7 @@
 		{
 			yyVAL.node = oldname(yyDollar[1].sym)
 			if yyVAL.node.Pack != nil {
-				yyVAL.node.Pack.Used = 1
+				yyVAL.node.Pack.Used = true
 			}
 		}
 	case 163:
@@ -2393,7 +2393,7 @@
 			if yyDollar[1].node.Op == OPACK {
 				var s *Sym
 				s = restrictlookup(yyDollar[3].sym.Name, yyDollar[1].node.Pkg)
-				yyDollar[1].node.Used = 1
+				yyDollar[1].node.Used = true
 				yyVAL.node = oldname(s)
 				break
 			}
@@ -2491,10 +2491,10 @@
 				Yyerror("can only use //go:noescape with external func implementations")
 			}
 			yyVAL.node.Nbody = yyDollar[3].list
-			yyVAL.node.Endlineno = lineno
+			yyVAL.node.Func.Endlineno = lineno
 			yyVAL.node.Noescape = noescape
-			yyVAL.node.Nosplit = nosplit
-			yyVAL.node.Nowritebarrier = nowritebarrier
+			yyVAL.node.Func.Nosplit = nosplit
+			yyVAL.node.Func.Nowritebarrier = nowritebarrier
 			funcbody(yyVAL.node)
 		}
 	case 205:
@@ -2523,7 +2523,7 @@
 			t.Rlist = yyDollar[5].list
 
 			yyVAL.node = Nod(ODCLFUNC, nil, nil)
-			yyVAL.node.Nname = newname(yyDollar[1].sym)
+			yyVAL.node.Nname = newfuncname(yyDollar[1].sym)
 			yyVAL.node.Nname.Defn = yyVAL.node
 			yyVAL.node.Nname.Ntype = t // TODO: check if nname already has an ntype
 			declare(yyVAL.node.Nname, PFUNC)
@@ -2559,8 +2559,8 @@
 			t.Rlist = yyDollar[8].list
 
 			yyVAL.node = Nod(ODCLFUNC, nil, nil)
-			yyVAL.node.Shortname = newname(yyDollar[4].sym)
-			yyVAL.node.Nname = methodname1(yyVAL.node.Shortname, rcvr.Right)
+			yyVAL.node.Func.Shortname = newfuncname(yyDollar[4].sym)
+			yyVAL.node.Nname = methodname1(yyVAL.node.Func.Shortname, rcvr.Right)
 			yyVAL.node.Nname.Defn = yyVAL.node
 			yyVAL.node.Nname.Ntype = t
 			yyVAL.node.Nname.Nointerface = nointerface
@@ -2589,7 +2589,7 @@
 				Yyerror("inconsistent definition for func %v during import\n\t%v\n\t%v", Sconv(s, 0), Tconv(s.Def.Type, 0), Tconv(t, 0))
 			}
 
-			yyVAL.node = newname(s)
+			yyVAL.node = newfuncname(s)
 			yyVAL.node.Type = t
 			declare(yyVAL.node, PFUNC)
 
@@ -2818,7 +2818,7 @@
 			yyVAL.sym = yyDollar[1].sym
 			n = oldname(yyDollar[1].sym)
 			if n.Pack != nil {
-				n.Pack.Used = 1
+				n.Pack.Used = true
 			}
 		}
 	case 237:
@@ -2831,7 +2831,7 @@
 				Yyerror("%v is not a package", Sconv(yyDollar[1].sym, 0))
 				pkg = localpkg
 			} else {
-				yyDollar[1].sym.Def.Used = 1
+				yyDollar[1].sym.Def.Used = true
 				pkg = yyDollar[1].sym.Def.Pkg
 			}
 			yyVAL.sym = restrictlookup(yyDollar[3].sym.Name, pkg)
@@ -3016,7 +3016,7 @@
 			if yyVAL.node.List == nil && Curfn != nil {
 				var l *NodeList
 
-				for l = Curfn.Dcl; l != nil; l = l.Next {
+				for l = Curfn.Func.Dcl; l != nil; l = l.Next {
 					if l.N.Class == PPARAM {
 						continue
 					}
@@ -3226,15 +3226,15 @@
 				break
 			}
 
-			yyDollar[2].node.Inl = yyDollar[3].list
+			yyDollar[2].node.Func.Inl = yyDollar[3].list
 
 			funcbody(yyDollar[2].node)
 			importlist = list(importlist, yyDollar[2].node)
 
 			if Debug['E'] > 0 {
-				print("import [%v] func %lN \n", Zconv(importpkg.Path, 0), yyDollar[2].node)
-				if Debug['m'] > 2 && yyDollar[2].node.Inl != nil {
-					print("inl body:%+H\n", yyDollar[2].node.Inl)
+				print("import [%q] func %lN \n", importpkg.Path, yyDollar[2].node)
+				if Debug['m'] > 2 && yyDollar[2].node.Func.Inl != nil {
+					print("inl body:%+H\n", yyDollar[2].node.Func.Inl)
 				}
 			}
 		}
@@ -3379,7 +3379,7 @@
 			if yyDollar[1].sym != nil {
 				yyVAL.node.Left = newname(yyDollar[1].sym)
 			}
-			yyVAL.node.Isddd = 1
+			yyVAL.node.Isddd = true
 			yyVAL.node.Val = yyDollar[4].val
 		}
 	case 332:
@@ -3394,7 +3394,7 @@
 				yyVAL.node.Val = yyDollar[3].val
 			} else {
 				s = yyDollar[2].typ.Sym
-				if s == nil && Isptr[yyDollar[2].typ.Etype] != 0 {
+				if s == nil && Isptr[yyDollar[2].typ.Etype] {
 					s = yyDollar[2].typ.Type.Sym
 				}
 				p = importpkg
diff --git a/src/cmd/internal/ld/ar.go b/src/cmd/internal/ld/ar.go
index c464a62..0e59016 100644
--- a/src/cmd/internal/ld/ar.go
+++ b/src/cmd/internal/ld/ar.go
@@ -36,9 +36,10 @@
 	SAR_HDR = 16 + 44
 )
 
-var ARMAG string = "!<arch>\n"
-
-var ARFMAG string = "`\n"
+const (
+	ARMAG  = "!<arch>\n"
+	ARFMAG = "`\n"
+)
 
 type ArHdr struct {
 	name string
diff --git a/src/cmd/internal/ld/arch.go b/src/cmd/internal/ld/arch.go
index 3dd6a5f..1b8e1b1 100644
--- a/src/cmd/internal/ld/arch.go
+++ b/src/cmd/internal/ld/arch.go
@@ -10,17 +10,24 @@
 	ByteOrder: binary.LittleEndian,
 	Name:      "arm",
 	Thechar:   '5',
-	Endian:    LittleEndian,
 	Minlc:     4,
 	Ptrsize:   4,
 	Regsize:   4,
 }
 
+var Linkarm64 = LinkArch{
+	ByteOrder: binary.LittleEndian,
+	Name:      "arm64",
+	Thechar:   '7',
+	Minlc:     4,
+	Ptrsize:   8,
+	Regsize:   8,
+}
+
 var Linkamd64 = LinkArch{
 	ByteOrder: binary.LittleEndian,
 	Name:      "amd64",
 	Thechar:   '6',
-	Endian:    LittleEndian,
 	Minlc:     1,
 	Ptrsize:   8,
 	Regsize:   8,
@@ -30,7 +37,6 @@
 	ByteOrder: binary.LittleEndian,
 	Name:      "amd64p32",
 	Thechar:   '6',
-	Endian:    LittleEndian,
 	Minlc:     1,
 	Ptrsize:   4,
 	Regsize:   8,
@@ -40,7 +46,6 @@
 	ByteOrder: binary.LittleEndian,
 	Name:      "386",
 	Thechar:   '8',
-	Endian:    LittleEndian,
 	Minlc:     1,
 	Ptrsize:   4,
 	Regsize:   4,
@@ -50,7 +55,6 @@
 	ByteOrder: binary.BigEndian,
 	Name:      "ppc64",
 	Thechar:   '9',
-	Endian:    BigEndian,
 	Minlc:     4,
 	Ptrsize:   8,
 	Regsize:   8,
@@ -60,7 +64,6 @@
 	ByteOrder: binary.LittleEndian,
 	Name:      "ppc64le",
 	Thechar:   '9',
-	Endian:    LittleEndian,
 	Minlc:     4,
 	Ptrsize:   8,
 	Regsize:   8,
diff --git a/src/cmd/internal/ld/data.go b/src/cmd/internal/ld/data.go
index 381030d..bc2021a 100644
--- a/src/cmd/internal/ld/data.go
+++ b/src/cmd/internal/ld/data.go
@@ -81,9 +81,7 @@
 }
 
 func adduintxx(ctxt *Link, s *LSym, v uint64, wid int) int64 {
-	var off int64
-
-	off = s.Size
+	off := s.Size
 	setuintxx(ctxt, s, off, v, int64(wid))
 	return off
 }
@@ -113,17 +111,14 @@
 }
 
 func Addaddrplus(ctxt *Link, s *LSym, t *LSym, add int64) int64 {
-	var i int64
-	var r *Reloc
-
 	if s.Type == 0 {
 		s.Type = SDATA
 	}
 	s.Reachable = true
-	i = s.Size
+	i := s.Size
 	s.Size += int64(ctxt.Arch.Ptrsize)
 	Symgrow(ctxt, s, s.Size)
-	r = Addrel(s)
+	r := Addrel(s)
 	r.Sym = t
 	r.Off = int32(i)
 	r.Siz = uint8(ctxt.Arch.Ptrsize)
@@ -133,17 +128,14 @@
 }
 
 func Addpcrelplus(ctxt *Link, s *LSym, t *LSym, add int64) int64 {
-	var i int64
-	var r *Reloc
-
 	if s.Type == 0 {
 		s.Type = SDATA
 	}
 	s.Reachable = true
-	i = s.Size
+	i := s.Size
 	s.Size += 4
 	Symgrow(ctxt, s, s.Size)
-	r = Addrel(s)
+	r := Addrel(s)
 	r.Sym = t
 	r.Off = int32(i)
 	r.Add = add
@@ -157,8 +149,6 @@
 }
 
 func setaddrplus(ctxt *Link, s *LSym, off int64, t *LSym, add int64) int64 {
-	var r *Reloc
-
 	if s.Type == 0 {
 		s.Type = SDATA
 	}
@@ -168,7 +158,7 @@
 		Symgrow(ctxt, s, s.Size)
 	}
 
-	r = Addrel(s)
+	r := Addrel(s)
 	r.Sym = t
 	r.Off = int32(off)
 	r.Siz = uint8(ctxt.Arch.Ptrsize)
@@ -182,17 +172,14 @@
 }
 
 func addsize(ctxt *Link, s *LSym, t *LSym) int64 {
-	var i int64
-	var r *Reloc
-
 	if s.Type == 0 {
 		s.Type = SDATA
 	}
 	s.Reachable = true
-	i = s.Size
+	i := s.Size
 	s.Size += int64(ctxt.Arch.Ptrsize)
 	Symgrow(ctxt, s, s.Size)
-	r = Addrel(s)
+	r := Addrel(s)
 	r.Sym = t
 	r.Off = int32(i)
 	r.Siz = uint8(ctxt.Arch.Ptrsize)
@@ -201,17 +188,14 @@
 }
 
 func addaddrplus4(ctxt *Link, s *LSym, t *LSym, add int64) int64 {
-	var i int64
-	var r *Reloc
-
 	if s.Type == 0 {
 		s.Type = SDATA
 	}
 	s.Reachable = true
-	i = s.Size
+	i := s.Size
 	s.Size += 4
 	Symgrow(ctxt, s, s.Size)
-	r = Addrel(s)
+	r := Addrel(s)
 	r.Sym = t
 	r.Off = int32(i)
 	r.Siz = 4
@@ -253,16 +237,12 @@
 }
 
 func listsort(l *LSym, cmp func(*LSym, *LSym) int, nextp func(*LSym) **LSym) *LSym {
-	var l1 *LSym
-	var l2 *LSym
-	var le *LSym
-
 	if l == nil || *nextp(l) == nil {
 		return l
 	}
 
-	l1 = l
-	l2 = l
+	l1 := l
+	l2 := l
 	for {
 		l2 = *nextp(l2)
 		if l2 == nil {
@@ -289,7 +269,7 @@
 		l2 = *nextp(l2)
 	}
 
-	le = l
+	le := l
 
 	for {
 		if l1 == nil {
@@ -332,14 +312,13 @@
 	var r *Reloc
 	var rs *LSym
 	var i16 int16
-	var ri int32
 	var off int32
 	var siz int32
 	var fl int32
 	var o int64
 
 	Ctxt.Cursym = s
-	for ri = 0; ri < int32(len(s.R)); ri++ {
+	for ri := int32(0); ri < int32(len(s.R)); ri++ {
 		r = &s.R[ri]
 		r.Done = 1
 		off = r.Off
@@ -464,6 +443,8 @@
 					if rs.Type != SHOSTOBJ {
 						o += Symaddr(rs)
 					}
+				} else if HEADTYPE == Hwindows {
+					// nothing to do
 				} else {
 					Diag("unhandled pcrel relocation for %s", headstring)
 				}
@@ -484,8 +465,7 @@
 			}
 
 			// r->sym can be null when CALL $(constant) is transformed from absolute PC to relative PC call.
-		case R_CALL,
-			R_PCREL:
+		case R_CALL, R_PCREL:
 			if Linkmode == LinkExternal && r.Sym != nil && r.Sym.Type != SCONST && r.Sym.Sect != Ctxt.Cursym.Sect {
 				r.Done = 0
 
@@ -518,6 +498,13 @@
 					} else {
 						o += int64(r.Siz)
 					}
+				} else if HEADTYPE == Hwindows && Thearch.Thechar == '6' { // only amd64 needs PCREL
+					// PE/COFF's PC32 relocation uses the address after the relocated
+					// bytes as the base. Compensate by skewing the addend.
+					o += int64(r.Siz)
+					// GNU ld always add VirtualAddress of the .text section to the
+					// relocated address, compensate that.
+					o -= int64(s.Sect.(*Section).Vaddr - PEBASE)
 				} else {
 					Diag("unhandled pcrel relocation for %s", headstring)
 				}
@@ -591,34 +578,28 @@
 }
 
 func reloc() {
-	var s *LSym
-
 	if Debug['v'] != 0 {
 		fmt.Fprintf(&Bso, "%5.2f reloc\n", obj.Cputime())
 	}
 	Bflush(&Bso)
 
-	for s = Ctxt.Textp; s != nil; s = s.Next {
+	for s := Ctxt.Textp; s != nil; s = s.Next {
 		relocsym(s)
 	}
-	for s = datap; s != nil; s = s.Next {
+	for s := datap; s != nil; s = s.Next {
 		relocsym(s)
 	}
 }
 
 func dynrelocsym(s *LSym) {
-	var ri int
-	var r *Reloc
-
-	if HEADTYPE == Hwindows {
-		var rel *LSym
-		var targ *LSym
-
-		rel = Linklookup(Ctxt, ".rel", 0)
+	if HEADTYPE == Hwindows && Linkmode != LinkExternal {
+		rel := Linklookup(Ctxt, ".rel", 0)
 		if s == rel {
 			return
 		}
-		for ri = 0; ri < len(s.R); ri++ {
+		var r *Reloc
+		var targ *LSym
+		for ri := 0; ri < len(s.R); ri++ {
 			r = &s.R[ri]
 			targ = r.Sym
 			if targ == nil {
@@ -655,7 +636,8 @@
 		return
 	}
 
-	for ri = 0; ri < len(s.R); ri++ {
+	var r *Reloc
+	for ri := 0; ri < len(s.R); ri++ {
 		r = &s.R[ri]
 		if r.Sym != nil && r.Sym.Type == SDYNIMPORT || r.Type >= 256 {
 			if r.Sym != nil && !r.Sym.Reachable {
@@ -667,8 +649,6 @@
 }
 
 func dynreloc() {
-	var s *LSym
-
 	// -d suppresses dynamic loader format, so we may as well not
 	// compute these sections or mark their symbols as reachable.
 	if Debug['d'] != 0 && HEADTYPE != Hwindows {
@@ -679,10 +659,10 @@
 	}
 	Bflush(&Bso)
 
-	for s = Ctxt.Textp; s != nil; s = s.Next {
+	for s := Ctxt.Textp; s != nil; s = s.Next {
 		dynrelocsym(s)
 	}
-	for s = datap; s != nil; s = s.Next {
+	for s := datap; s != nil; s = s.Next {
 		dynrelocsym(s)
 	}
 	if Iself {
@@ -692,9 +672,6 @@
 
 func blk(start *LSym, addr int64, size int64) {
 	var sym *LSym
-	var eaddr int64
-	var p []byte
-	var ep []byte
 
 	for sym = start; sym != nil; sym = sym.Next {
 		if sym.Type&SSUB == 0 && sym.Value >= addr {
@@ -702,7 +679,9 @@
 		}
 	}
 
-	eaddr = addr + size
+	eaddr := addr + size
+	var ep []byte
+	var p []byte
 	for ; sym != nil; sym = sym.Next {
 		if sym.Type&SSUB != 0 {
 			continue
@@ -746,11 +725,6 @@
 }
 
 func Codeblk(addr int64, size int64) {
-	var sym *LSym
-	var eaddr int64
-	var n int64
-	var q []byte
-
 	if Debug['a'] != 0 {
 		fmt.Fprintf(&Bso, "codeblk [%#x,%#x) at offset %#x\n", addr, addr+size, Cpos())
 	}
@@ -762,6 +736,7 @@
 		return
 	}
 
+	var sym *LSym
 	for sym = Ctxt.Textp; sym != nil; sym = sym.Next {
 		if !sym.Reachable {
 			continue
@@ -771,7 +746,9 @@
 		}
 	}
 
-	eaddr = addr + size
+	eaddr := addr + size
+	var n int64
+	var q []byte
 	for ; sym != nil; sym = sym.Next {
 		if !sym.Reachable {
 			continue
@@ -816,15 +793,6 @@
 }
 
 func Datblk(addr int64, size int64) {
-	var sym *LSym
-	var i int64
-	var eaddr int64
-	var p []byte
-	var ep []byte
-	var typ string
-	var rsname string
-	var r *Reloc
-
 	if Debug['a'] != 0 {
 		fmt.Fprintf(&Bso, "datblk [%#x,%#x) at offset %#x\n", addr, addr+size, Cpos())
 	}
@@ -836,13 +804,20 @@
 		return
 	}
 
+	var sym *LSym
 	for sym = datap; sym != nil; sym = sym.Next {
 		if sym.Value >= addr {
 			break
 		}
 	}
 
-	eaddr = addr + size
+	eaddr := addr + size
+	var ep []byte
+	var i int64
+	var p []byte
+	var r *Reloc
+	var rsname string
+	var typ string
 	for ; sym != nil; sym = sym.Next {
 		if sym.Value >= eaddr {
 			break
@@ -922,21 +897,16 @@
 }
 
 func addstrdata(name string, value string) {
-	var s *LSym
-	var sp *LSym
-	var p string
-	var reachable bool
-
-	p = fmt.Sprintf("%s.str", name)
-	sp = Linklookup(Ctxt, p, 0)
+	p := fmt.Sprintf("%s.str", name)
+	sp := Linklookup(Ctxt, p, 0)
 
 	Addstring(sp, value)
 	sp.Type = SRODATA
 
-	s = Linklookup(Ctxt, name, 0)
+	s := Linklookup(Ctxt, name, 0)
 	s.Size = 0
 	s.Dupok = 1
-	reachable = s.Reachable
+	reachable := s.Reachable
 	Addaddr(Ctxt, s, sp)
 	adduintxx(Ctxt, s, uint64(len(value)), Thearch.Ptrsize)
 
@@ -949,15 +919,12 @@
 }
 
 func Addstring(s *LSym, str string) int64 {
-	var n int
-	var r int32
-
 	if s.Type == 0 {
 		s.Type = SNOPTRDATA
 	}
 	s.Reachable = true
-	r = int32(s.Size)
-	n = len(str) + 1
+	r := int32(s.Size)
+	n := len(str) + 1
 	if s.Name == ".shstrtab" {
 		elfsetstring(str, int(r))
 	}
@@ -968,10 +935,17 @@
 	return int64(r)
 }
 
-func dosymtype() {
-	var s *LSym
+func addinitarrdata(s *LSym) {
+	p := s.Name + ".ptr"
+	sp := Linklookup(Ctxt, p, 0)
+	sp.Type = SINITARR
+	sp.Size = 0
+	sp.Dupok = 1
+	Addaddr(Ctxt, sp, s)
+}
 
-	for s = Ctxt.Allsym; s != nil; s = s.Allsym {
+func dosymtype() {
+	for s := Ctxt.Allsym; s != nil; s = s.Allsym {
 		if len(s.P) > 0 {
 			if s.Type == SBSS {
 				s.Type = SDATA
@@ -980,17 +954,20 @@
 				s.Type = SNOPTRDATA
 			}
 		}
+		// Create a new entry in the .init_array section that points to the
+		// library initializer function.
+		if Flag_shared != 0 && s.Name == INITENTRY {
+			addinitarrdata(s)
+		}
 	}
 }
 
 func symalign(s *LSym) int32 {
-	var align int32
-
 	if s.Align != 0 {
 		return s.Align
 	}
 
-	align = int32(Thearch.Maxalign)
+	align := int32(Thearch.Maxalign)
 	for int64(align) > s.Size && align > 1 {
 		align >>= 1
 	}
@@ -1008,9 +985,8 @@
 // the list of symbols s; the list stops when s->type exceeds type.
 func maxalign(s *LSym, type_ int) int32 {
 	var align int32
-	var max int32
 
-	max = 0
+	max := int32(0)
 	for ; s != nil && int(s.Type) <= type_; s = s.Next {
 		align = symalign(s)
 		if max < align {
@@ -1042,16 +1018,13 @@
 
 // Writes insData block from g->data.
 func proggendataflush(g *ProgGen) {
-	var i int32
-	var s int32
-
 	if g.datasize == 0 {
 		return
 	}
 	proggenemit(g, obj.InsData)
 	proggenemit(g, uint8(g.datasize))
-	s = (g.datasize + obj.PointersPerByte - 1) / obj.PointersPerByte
-	for i = 0; i < s; i++ {
+	s := (g.datasize + obj.PointersPerByte - 1) / obj.PointersPerByte
+	for i := int32(0); i < s; i++ {
 		proggenemit(g, g.data[i])
 	}
 	g.datasize = 0
@@ -1068,9 +1041,7 @@
 
 // Skip v bytes due to alignment, etc.
 func proggenskip(g *ProgGen, off int64, v int64) {
-	var i int64
-
-	for i = off; i < off+v; i++ {
+	for i := off; i < off+v; i++ {
 		if (i % int64(Thearch.Ptrsize)) == 0 {
 			proggendata(g, obj.BitsScalar)
 		}
@@ -1083,7 +1054,7 @@
 
 	proggendataflush(g)
 	proggenemit(g, obj.InsArray)
-	for i = 0; i < int32(Thearch.Ptrsize); (func() { i++; length >>= 8 })() {
+	for i = 0; i < int32(Thearch.Ptrsize); i, length = i+1, length>>8 {
 		proggenemit(g, uint8(length))
 	}
 }
@@ -1101,11 +1072,6 @@
 
 // This function generates GC pointer info for global variables.
 func proggenaddsym(g *ProgGen, s *LSym) {
-	var gcprog *LSym
-	var mask []byte
-	var i int64
-	var size int64
-
 	if s.Size == 0 {
 		return
 	}
@@ -1128,10 +1094,10 @@
 		if (s.Size%int64(Thearch.Ptrsize) != 0) || (g.pos%int64(Thearch.Ptrsize) != 0) {
 			Diag("proggenaddsym: unaligned conservative symbol %s: size=%d pos=%d", s.Name, s.Size, g.pos)
 		}
-		size = (s.Size + int64(Thearch.Ptrsize) - 1) / int64(Thearch.Ptrsize) * int64(Thearch.Ptrsize)
+		size := (s.Size + int64(Thearch.Ptrsize) - 1) / int64(Thearch.Ptrsize) * int64(Thearch.Ptrsize)
 		if size < int64(32*Thearch.Ptrsize) {
 			// Emit small symbols as data.
-			for i = 0; i < size/int64(Thearch.Ptrsize); i++ {
+			for i := int64(0); i < size/int64(Thearch.Ptrsize); i++ {
 				proggendata(g, obj.BitsPointer)
 			}
 		} else {
@@ -1148,7 +1114,7 @@
 		if s.Size < int64(32*Thearch.Ptrsize) {
 			// Emit small symbols as data.
 			// This case also handles unaligned and tiny symbols, so tread carefully.
-			for i = s.Value; i < s.Value+s.Size; i++ {
+			for i := s.Value; i < s.Value+s.Size; i++ {
 				if (i % int64(Thearch.Ptrsize)) == 0 {
 					proggendata(g, obj.BitsScalar)
 				}
@@ -1168,24 +1134,24 @@
 		// gc program, copy directly
 		proggendataflush(g)
 
-		gcprog = decodetype_gcprog(s.Gotype)
-		size = decodetype_size(s.Gotype)
+		gcprog := decodetype_gcprog(s.Gotype)
+		size := decodetype_size(s.Gotype)
 		if (size%int64(Thearch.Ptrsize) != 0) || (g.pos%int64(Thearch.Ptrsize) != 0) {
 			Diag("proggenaddsym: unaligned gcprog symbol %s: size=%d pos=%d", s.Name, s.Size, g.pos)
 		}
-		for i = 0; i < int64(len(gcprog.P)-1); i++ {
+		for i := int64(0); i < int64(len(gcprog.P)-1); i++ {
 			proggenemit(g, uint8(gcprog.P[i]))
 		}
 		g.pos = s.Value + size
 	} else {
 		// gc mask, it's small so emit as data
-		mask = decodetype_gcmask(s.Gotype)
+		mask := decodetype_gcmask(s.Gotype)
 
-		size = decodetype_size(s.Gotype)
+		size := decodetype_size(s.Gotype)
 		if (size%int64(Thearch.Ptrsize) != 0) || (g.pos%int64(Thearch.Ptrsize) != 0) {
 			Diag("proggenaddsym: unaligned gcmask symbol %s: size=%d pos=%d", s.Name, s.Size, g.pos)
 		}
-		for i = 0; i < size; i += int64(Thearch.Ptrsize) {
+		for i := int64(0); i < size; i += int64(Thearch.Ptrsize) {
 			proggendata(g, uint8((mask[i/int64(Thearch.Ptrsize)/2]>>uint64((i/int64(Thearch.Ptrsize)%2)*4+2))&obj.BitsMask))
 		}
 		g.pos = s.Value + size
@@ -1193,9 +1159,7 @@
 }
 
 func growdatsize(datsizep *int64, s *LSym) {
-	var datsize int64
-
-	datsize = *datsizep
+	datsize := *datsizep
 	if s.Size < 0 {
 		Diag("negative size (datsize = %d, s->size = %d)", datsize, s.Size)
 	}
@@ -1206,27 +1170,15 @@
 }
 
 func dodata() {
-	var n int32
-	var datsize int64
-	var sect *Section
-	var segro *Segment
-	var s *LSym
-	var last *LSym
-	var l **LSym
-	var toc *LSym
-	var gcdata *LSym
-	var gcbss *LSym
-	var gen ProgGen
-
 	if Debug['v'] != 0 {
 		fmt.Fprintf(&Bso, "%5.2f dodata\n", obj.Cputime())
 	}
 	Bflush(&Bso)
 
-	last = nil
+	var last *LSym
 	datap = nil
 
-	for s = Ctxt.Allsym; s != nil; s = s.Allsym {
+	for s := Ctxt.Allsym; s != nil; s = s.Allsym {
 		if !s.Reachable || s.Special != 0 {
 			continue
 		}
@@ -1245,7 +1197,7 @@
 		}
 	}
 
-	for s = datap; s != nil; s = s.Next {
+	for s := datap; s != nil; s = s.Next {
 		if int64(len(s.P)) > s.Size {
 			Diag("%s: initialize bounds (%d < %d)", s.Name, int64(s.Size), len(s.P))
 		}
@@ -1265,6 +1217,8 @@
 	dynreloc()
 
 	/* some symbols may no longer belong in datap (Mach-O) */
+	var l **LSym
+	var s *LSym
 	for l = &datap; ; {
 		s = *l
 		if s == nil {
@@ -1299,8 +1253,9 @@
 	}
 
 	/* writable ELF sections */
-	datsize = 0
+	datsize := int64(0)
 
+	var sect *Section
 	for ; s != nil && s.Type < SELFGOT; s = s.Next {
 		sect = addsection(&Segdata, s.Name, 06)
 		sect.Align = symalign(s)
@@ -1315,10 +1270,11 @@
 
 	/* .got (and .toc on ppc64) */
 	if s.Type == SELFGOT {
-		sect = addsection(&Segdata, ".got", 06)
+		sect := addsection(&Segdata, ".got", 06)
 		sect.Align = maxalign(s, SELFGOT)
 		datsize = Rnd(datsize, int64(sect.Align))
 		sect.Vaddr = uint64(datsize)
+		var toc *LSym
 		for ; s != nil && s.Type == SELFGOT; s = s.Next {
 			datsize = aligndatsize(datsize, s)
 			s.Sect = sect
@@ -1363,7 +1319,7 @@
 
 	/* shared library initializer */
 	if Flag_shared != 0 {
-		sect = addsection(&Segdata, ".init_array", 06)
+		sect := addsection(&Segdata, ".init_array", 06)
 		sect.Align = maxalign(s, SINITARR)
 		datsize = Rnd(datsize, int64(sect.Align))
 		sect.Vaddr = uint64(datsize)
@@ -1385,7 +1341,8 @@
 	sect.Vaddr = uint64(datsize)
 	Linklookup(Ctxt, "runtime.data", 0).Sect = sect
 	Linklookup(Ctxt, "runtime.edata", 0).Sect = sect
-	gcdata = Linklookup(Ctxt, "runtime.gcdata", 0)
+	gcdata := Linklookup(Ctxt, "runtime.gcdata", 0)
+	var gen ProgGen
 	proggeninit(&gen, gcdata)
 	for ; s != nil && s.Type < SBSS; s = s.Next {
 		if s.Type == SINITARR {
@@ -1412,7 +1369,7 @@
 	sect.Vaddr = uint64(datsize)
 	Linklookup(Ctxt, "runtime.bss", 0).Sect = sect
 	Linklookup(Ctxt, "runtime.ebss", 0).Sect = sect
-	gcbss = Linklookup(Ctxt, "runtime.gcbss", 0)
+	gcbss := Linklookup(Ctxt, "runtime.gcbss", 0)
 	proggeninit(&gen, gcbss)
 	for ; s != nil && s.Type < SNOPTRBSS; s = s.Next {
 		s.Sect = sect
@@ -1449,7 +1406,7 @@
 	}
 
 	if Iself && Linkmode == LinkExternal && s != nil && s.Type == STLSBSS && HEADTYPE != Hopenbsd {
-		sect = addsection(&Segdata, ".tbss", 06)
+		sect := addsection(&Segdata, ".tbss", 06)
 		sect.Align = int32(Thearch.Ptrsize)
 		sect.Vaddr = 0
 		datsize = 0
@@ -1486,6 +1443,7 @@
 	 * since it's not our decision; that code expects the sections in
 	 * segtext.
 	 */
+	var segro *Segment
 	if Iself && Linkmode == LinkInternal {
 		segro = &Segrodata
 	} else {
@@ -1600,17 +1558,17 @@
 	}
 
 	/* number the sections */
-	n = 1
+	n := int32(1)
 
-	for sect = Segtext.Sect; sect != nil; sect = sect.Next {
+	for sect := Segtext.Sect; sect != nil; sect = sect.Next {
 		sect.Extnum = int16(n)
 		n++
 	}
-	for sect = Segrodata.Sect; sect != nil; sect = sect.Next {
+	for sect := Segrodata.Sect; sect != nil; sect = sect.Next {
 		sect.Extnum = int16(n)
 		n++
 	}
-	for sect = Segdata.Sect; sect != nil; sect = sect.Next {
+	for sect := Segdata.Sect; sect != nil; sect = sect.Next {
 		sect.Extnum = int16(n)
 		n++
 	}
@@ -1618,9 +1576,6 @@
 
 // assign addresses to text
 func textaddress() {
-	var va uint64
-	var sect *Section
-	var sym *LSym
 	var sub *LSym
 
 	addsection(&Segtext, ".text", 05)
@@ -1628,14 +1583,14 @@
 	// Assign PCs in text segment.
 	// Could parallelize, by assigning to text
 	// and then letting threads copy down, but probably not worth it.
-	sect = Segtext.Sect
+	sect := Segtext.Sect
 
 	sect.Align = int32(Funcalign)
 	Linklookup(Ctxt, "runtime.text", 0).Sect = sect
 	Linklookup(Ctxt, "runtime.etext", 0).Sect = sect
-	va = uint64(INITTEXT)
+	va := uint64(INITTEXT)
 	sect.Vaddr = va
-	for sym = Ctxt.Textp; sym != nil; sym = sym.Next {
+	for sym := Ctxt.Textp; sym != nil; sym = sym.Next {
 		sym.Sect = sect
 		if sym.Type&SSUB != 0 {
 			continue
@@ -1664,26 +1619,11 @@
 
 // assign addresses
 func address() {
-	var s *Section
-	var text *Section
-	var data *Section
-	var rodata *Section
-	var symtab *Section
-	var pclntab *Section
-	var noptr *Section
-	var bss *Section
-	var noptrbss *Section
-	var typelink *Section
-	var sym *LSym
-	var sub *LSym
-	var va uint64
-	var vlen int64
-
-	va = uint64(INITTEXT)
+	va := uint64(INITTEXT)
 	Segtext.Rwx = 05
 	Segtext.Vaddr = va
 	Segtext.Fileoff = uint64(HEADR)
-	for s = Segtext.Sect; s != nil; s = s.Next {
+	for s := Segtext.Sect; s != nil; s = s.Next {
 		va = uint64(Rnd(int64(va), int64(s.Align)))
 		s.Vaddr = va
 		va += s.Length
@@ -1704,7 +1644,7 @@
 		Segrodata.Vaddr = va
 		Segrodata.Fileoff = va - Segtext.Vaddr + Segtext.Fileoff
 		Segrodata.Filelen = 0
-		for s = Segrodata.Sect; s != nil; s = s.Next {
+		for s := Segrodata.Sect; s != nil; s = s.Next {
 			va = uint64(Rnd(int64(va), int64(s.Align)))
 			s.Vaddr = va
 			va += s.Length
@@ -1725,11 +1665,12 @@
 	if HEADTYPE == Hplan9 {
 		Segdata.Fileoff = Segtext.Fileoff + Segtext.Filelen
 	}
-	data = nil
-	noptr = nil
-	bss = nil
-	noptrbss = nil
-	for s = Segdata.Sect; s != nil; s = s.Next {
+	var data *Section
+	var noptr *Section
+	var bss *Section
+	var noptrbss *Section
+	var vlen int64
+	for s := Segdata.Sect; s != nil; s = s.Next {
 		vlen = int64(s.Length)
 		if s.Next != nil {
 			vlen = int64(s.Next.Vaddr - s.Vaddr)
@@ -1753,17 +1694,19 @@
 
 	Segdata.Filelen = bss.Vaddr - Segdata.Vaddr
 
-	text = Segtext.Sect
+	text := Segtext.Sect
+	var rodata *Section
 	if Segrodata.Sect != nil {
 		rodata = Segrodata.Sect
 	} else {
 		rodata = text.Next
 	}
-	typelink = rodata.Next
-	symtab = typelink.Next
-	pclntab = symtab.Next
+	typelink := rodata.Next
+	symtab := typelink.Next
+	pclntab := symtab.Next
 
-	for sym = datap; sym != nil; sym = sym.Next {
+	var sub *LSym
+	for sym := datap; sym != nil; sym = sym.Next {
 		Ctxt.Cursym = sym
 		if sym.Sect != nil {
 			sym.Value += int64((sym.Sect.(*Section)).Vaddr)
@@ -1780,7 +1723,7 @@
 	xdefine("runtime.typelink", SRODATA, int64(typelink.Vaddr))
 	xdefine("runtime.etypelink", SRODATA, int64(typelink.Vaddr+typelink.Length))
 
-	sym = Linklookup(Ctxt, "runtime.gcdata", 0)
+	sym := Linklookup(Ctxt, "runtime.gcdata", 0)
 	xdefine("runtime.egcdata", SRODATA, Symaddr(sym)+sym.Size)
 	Linklookup(Ctxt, "runtime.egcdata", 0).Sect = sym.Sect
 
diff --git a/src/cmd/internal/ld/decodesym.go b/src/cmd/internal/ld/decodesym.go
index c7b1a2f..e960f10 100644
--- a/src/cmd/internal/ld/decodesym.go
+++ b/src/cmd/internal/ld/decodesym.go
@@ -11,9 +11,7 @@
 // ../gc/reflect.c stuffs in these.
 
 func decode_reloc(s *LSym, off int32) *Reloc {
-	var i int
-
-	for i = 0; i < len(s.R); i++ {
+	for i := 0; i < len(s.R); i++ {
 		if s.R[i].Off == off {
 			return &s.R[i:][0]
 		}
@@ -22,9 +20,7 @@
 }
 
 func decode_reloc_sym(s *LSym, off int32) *LSym {
-	var r *Reloc
-
-	r = decode_reloc(s, off)
+	r := decode_reloc(s, off)
 	if r == nil {
 		return nil
 	}
@@ -75,9 +71,7 @@
 }
 
 func decodetype_gcmask(s *LSym) []byte {
-	var mask *LSym
-
-	mask = decode_reloc_sym(s, 1*int32(Thearch.Ptrsize)+8+1*int32(Thearch.Ptrsize))
+	mask := decode_reloc_sym(s, 1*int32(Thearch.Ptrsize)+8+1*int32(Thearch.Ptrsize))
 	return mask.P
 }
 
@@ -124,9 +118,7 @@
 }
 
 func decodetype_funcintype(s *LSym, i int) *LSym {
-	var r *Reloc
-
-	r = decode_reloc(s, int32(commonsize())+int32(Thearch.Ptrsize))
+	r := decode_reloc(s, int32(commonsize())+int32(Thearch.Ptrsize))
 	if r == nil {
 		return nil
 	}
@@ -134,9 +126,7 @@
 }
 
 func decodetype_funcouttype(s *LSym, i int) *LSym {
-	var r *Reloc
-
-	r = decode_reloc(s, int32(commonsize())+2*int32(Thearch.Ptrsize)+2*int32(Thearch.Intsize))
+	r := decode_reloc(s, int32(commonsize())+2*int32(Thearch.Ptrsize)+2*int32(Thearch.Intsize))
 	if r == nil {
 		return nil
 	}
@@ -154,16 +144,14 @@
 
 // Type.StructType.fields[]-> name, typ and offset.
 func decodetype_structfieldname(s *LSym, i int) string {
-	var r *Reloc
-
 	// go.string."foo"  0x28 / 0x40
 	s = decode_reloc_sym(s, int32(commonsize())+int32(Thearch.Ptrsize)+2*int32(Thearch.Intsize)+int32(i)*int32(structfieldsize()))
 
 	if s == nil { // embedded structs have a nil name.
 		return ""
 	}
-	r = decode_reloc(s, 0) // s has a pointer to the string data at offset 0
-	if r == nil {          // shouldn't happen.
+	r := decode_reloc(s, 0) // s has a pointer to the string data at offset 0
+	if r == nil {           // shouldn't happen.
 		return ""
 	}
 	return cstring(r.Sym.P[r.Add:])
@@ -177,7 +165,7 @@
 	return int64(decode_inuxi(s.P[commonsize()+Thearch.Ptrsize+2*Thearch.Intsize+i*structfieldsize()+4*Thearch.Ptrsize:], Thearch.Intsize))
 }
 
-// InterfaceTYpe.methods.length
+// InterfaceType.methods.length
 func decodetype_ifacemethodcount(s *LSym) int64 {
 	return int64(decode_inuxi(s.P[commonsize()+Thearch.Ptrsize:], Thearch.Intsize))
 }
diff --git a/src/cmd/internal/ld/dwarf.go b/src/cmd/internal/ld/dwarf.go
index 490795c..37625f1 100644
--- a/src/cmd/internal/ld/dwarf.go
+++ b/src/cmd/internal/ld/dwarf.go
@@ -2,6 +2,16 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
+// TODO/NICETOHAVE:
+//   - eliminate DW_CLS_ if not used
+//   - package info in compilation units
+//   - assign global variables and types to their packages
+//   - gdb uses c syntax, meaning clumsy quoting is needed for go identifiers. eg
+//     ptype struct '[]uint8' and qualifiers need to be quoted away
+//   - lexical scoping is lost, so gdb gets confused as to which 'main.i' you mean.
+//   - file:line info for variables
+//   - make strings a typedef so prettyprinters can see the underlying string type
+
 package ld
 
 import (
@@ -102,9 +112,8 @@
 
 func uleb128enc(v uint64, dst []byte) int {
 	var c uint8
-	var length uint8
 
-	length = 0
+	length := uint8(0)
 	for {
 		c = uint8(v & 0x7f)
 		v >>= 7
@@ -127,9 +136,8 @@
 func sleb128enc(v int64, dst []byte) int {
 	var c uint8
 	var s uint8
-	var length uint8
 
-	length = 0
+	length := uint8(0)
 	for {
 		c = uint8(v & 0x7f)
 		s = uint8(v & 0x40)
@@ -175,10 +183,11 @@
 
 // Go-specific type attributes.
 const (
-	DW_AT_go_kind           = 0x2900
-	DW_AT_go_key            = 0x2901
-	DW_AT_go_elem           = 0x2902
-	DW_AT_internal_location = 253
+	DW_AT_go_kind = 0x2900
+	DW_AT_go_key  = 0x2901
+	DW_AT_go_elem = 0x2902
+
+	DW_AT_internal_location = 253 // params and locals; not emitted
 )
 
 // Index into the abbrevs table below.
@@ -203,7 +212,7 @@
 	DW_ABRV_IFACETYPE
 	DW_ABRV_MAPTYPE
 	DW_ABRV_PTRTYPE
-	DW_ABRV_BARE_PTRTYPE
+	DW_ABRV_BARE_PTRTYPE // only for void*, no DW_AT_type attr to please gdb 6.
 	DW_ABRV_SLICETYPE
 	DW_ABRV_STRINGTYPE
 	DW_ABRV_STRUCTTYPE
@@ -587,12 +596,11 @@
 }
 
 func writeabbrev() {
-	var i int
 	var j int
 	var f *DWAttrForm
 
 	abbrevo = Cpos()
-	for i = 1; i < DW_NABRV; i++ {
+	for i := 1; i < DW_NABRV; i++ {
 		// See section 7.5.3
 		uleb128put(int64(i))
 
@@ -620,9 +628,7 @@
 )
 
 func dwarfhashstr(s string) uint32 {
-	var h uint32
-
-	h = 0
+	h := uint32(0)
 	for s != "" {
 		h = h + h + h + uint32(s[0])
 		s = s[1:]
@@ -637,8 +643,8 @@
 
 type DWAttr struct {
 	link  *DWAttr
-	atr   uint16
-	cls   uint8
+	atr   uint16 // DW_AT_
+	cls   uint8  // DW_CLS_
 	value int64
 	data  interface{}
 }
@@ -648,9 +654,11 @@
 	link   *DWDie
 	child  *DWDie
 	attr   *DWAttr
-	offs   int64
-	hash   []*DWDie
-	hlink  *DWDie
+	// offset into .debug_info section, i.e relative to
+	// infoo. only valid after call to putdie()
+	offs  int64
+	hash  []*DWDie // optional index of children by name, enabled by mkindex()
+	hlink *DWDie   // bucket chain in parent's index
 }
 
 /*
@@ -663,9 +671,7 @@
 var dwglobals DWDie
 
 func newattr(die *DWDie, attr uint16, cls int, value int64, data interface{}) *DWAttr {
-	var a *DWAttr
-
-	a = new(DWAttr)
+	a := new(DWAttr)
 	a.link = die.attr
 	die.attr = a
 	a.atr = attr
@@ -679,15 +685,12 @@
 // name. getattr moves the desired one to the front so
 // frequently searched ones are found faster.
 func getattr(die *DWDie, attr uint16) *DWAttr {
-	var a *DWAttr
-	var b *DWAttr
-
 	if die.attr.atr == attr {
 		return die.attr
 	}
 
-	a = die.attr
-	b = a.link
+	a := die.attr
+	b := a.link
 	for b != nil {
 		if b.atr == attr {
 			a.link = b.link
@@ -707,10 +710,7 @@
 // written out if it is listed in the abbrev).	If its parent is
 // keeping an index, the new DIE will be inserted there.
 func newdie(parent *DWDie, abbrev int, name string) *DWDie {
-	var die *DWDie
-	var h int
-
-	die = new(DWDie)
+	die := new(DWDie)
 	die.abbrev = abbrev
 	die.link = parent.child
 	parent.child = die
@@ -718,7 +718,7 @@
 	newattr(die, DW_AT_name, DW_CLS_STRING, int64(len(name)), name)
 
 	if parent.hash != nil {
-		h = int(dwarfhashstr(name))
+		h := int(dwarfhashstr(name))
 		die.hlink = parent.hash[h]
 		parent.hash[h] = die
 	}
@@ -731,11 +731,9 @@
 }
 
 func walktypedef(die *DWDie) *DWDie {
-	var attr *DWAttr
-
 	// Resolve typedef if present.
 	if die.abbrev == DW_ABRV_TYPEDECL {
-		for attr = die.attr; attr != nil; attr = attr.link {
+		for attr := die.attr; attr != nil; attr = attr.link {
 			if attr.atr == DW_AT_type && attr.cls == DW_CLS_REFERENCE && attr.data != nil {
 				return attr.data.(*DWDie)
 			}
@@ -800,8 +798,7 @@
 }
 
 func find_or_diag(die *DWDie, name string) *DWDie {
-	var r *DWDie
-	r = find(die, name)
+	r := find(die, name)
 	if r == nil {
 		Diag("dwarf find: %s %p has no %s", getattr(die, DW_AT_name).data, die, name)
 		Errorexit()
@@ -811,9 +808,7 @@
 }
 
 func adddwarfrel(sec *LSym, sym *LSym, offsetbase int64, siz int, addend int64) {
-	var r *Reloc
-
-	r = Addrel(sec)
+	r := Addrel(sec)
 	r.Sym = sym
 	r.Xsym = sym
 	r.Off = int32(Cpos() - offsetbase)
@@ -846,10 +841,6 @@
 var fwdcount int
 
 func putattr(abbrev int, form int, cls int, value int64, data interface{}) {
-	var off int64
-	var p []byte
-	var i int
-
 	switch form {
 	case DW_FORM_addr: // address
 		if Linkmode == LinkExternal {
@@ -876,8 +867,8 @@
 
 		value &= 0xff
 		Cput(uint8(value))
-		p = data.([]byte)
-		for i = 0; int64(i) < value; i++ {
+		p := data.([]byte)
+		for i := 0; int64(i) < value; i++ {
 			Cput(uint8(p[i]))
 		}
 
@@ -885,8 +876,8 @@
 		value &= 0xffff
 
 		Thearch.Wput(uint16(value))
-		p = data.([]byte)
-		for i = 0; int64(i) < value; i++ {
+		p := data.([]byte)
+		for i := 0; int64(i) < value; i++ {
 			Cput(uint8(p[i]))
 		}
 
@@ -894,16 +885,16 @@
 		value &= 0xffffffff
 
 		Thearch.Lput(uint32(value))
-		p = data.([]byte)
-		for i = 0; int64(i) < value; i++ {
+		p := data.([]byte)
+		for i := 0; int64(i) < value; i++ {
 			Cput(uint8(p[i]))
 		}
 
 	case DW_FORM_block: // block
 		uleb128put(value)
 
-		p = data.([]byte)
-		for i = 0; int64(i) < value; i++ {
+		p := data.([]byte)
+		for i := 0; int64(i) < value; i++ {
 			Cput(uint8(p[i]))
 		}
 
@@ -953,7 +944,7 @@
 				Thearch.Lput(0) // invalid dwarf, gdb will complain.
 			}
 		} else {
-			off = (data.(*DWDie)).offs
+			off := (data.(*DWDie)).offs
 			if off == 0 {
 				fwdcount++
 			}
@@ -984,10 +975,9 @@
 // Note that we can (and do) add arbitrary attributes to a DIE, but
 // only the ones actually listed in the Abbrev will be written out.
 func putattrs(abbrev int, attr *DWAttr) {
-	var af []DWAttrForm
 	var ap *DWAttr
 
-	for af = abbrevs[abbrev].attr[:]; af[0].attr != 0; af = af[1:] {
+	for af := abbrevs[abbrev].attr[:]; af[0].attr != 0; af = af[1:] {
 		for ap = attr; ap != nil; ap = ap.link {
 			if ap.atr == af[0].attr {
 				putattr(abbrev, int(af[0].form), int(ap.cls), ap.value, ap.data)
@@ -1017,11 +1007,8 @@
 }
 
 func reverselist(list **DWDie) {
-	var curr *DWDie
+	curr := *list
 	var prev *DWDie
-
-	curr = *list
-	prev = nil
 	for curr != nil {
 		var next *DWDie = curr.link
 		curr.link = prev
@@ -1033,10 +1020,8 @@
 }
 
 func reversetree(list **DWDie) {
-	var die *DWDie
-
 	reverselist(list)
-	for die = *list; die != nil; die = die.link {
+	for die := *list; die != nil; die = die.link {
 		if abbrevs[die.abbrev].children != 0 {
 			reversetree(&die.child)
 		}
@@ -1045,9 +1030,8 @@
 
 func newmemberoffsetattr(die *DWDie, offs int32) {
 	var block [20]byte
-	var i int
 
-	i = 0
+	i := 0
 	block[i] = DW_OP_plus_uconst
 	i++
 	i += uleb128enc(uint64(offs), block[i:])
@@ -1063,9 +1047,7 @@
 
 // Lookup predefined types
 func lookup_or_diag(n string) *LSym {
-	var s *LSym
-
-	s = Linkrlookup(Ctxt, n, 0)
+	s := Linkrlookup(Ctxt, n, 0)
 	if s == nil || s.Size == 0 {
 		Diag("dwarf: missing type: %s", n)
 		Errorexit()
@@ -1075,8 +1057,6 @@
 }
 
 func dotypedef(parent *DWDie, name string, def *DWDie) {
-	var die *DWDie
-
 	// Only emit typedefs for real names.
 	if strings.HasPrefix(name, "map[") {
 		return
@@ -1098,23 +1078,13 @@
 	// so that future lookups will find the typedef instead
 	// of the real definition. This hooks the typedef into any
 	// circular definition loops, so that gdb can understand them.
-	die = newdie(parent, DW_ABRV_TYPEDECL, name)
+	die := newdie(parent, DW_ABRV_TYPEDECL, name)
 
 	newrefattr(die, DW_AT_type, def)
 }
 
 // Define gotype, for composite ones recurse into constituents.
 func defgotype(gotype *LSym) *DWDie {
-	var die *DWDie
-	var fld *DWDie
-	var s *LSym
-	var name string
-	var f string
-	var kind uint8
-	var bytesize int64
-	var i int
-	var nfields int
-
 	if gotype == nil {
 		return find_or_diag(&dwtypes, "<unspecified>")
 	}
@@ -1124,9 +1094,9 @@
 		return find_or_diag(&dwtypes, "<unspecified>")
 	}
 
-	name = gotype.Name[5:] // could also decode from Type.string
+	name := gotype.Name[5:] // could also decode from Type.string
 
-	die = find(&dwtypes, name)
+	die := find(&dwtypes, name)
 
 	if die != nil {
 		return die
@@ -1136,8 +1106,8 @@
 		fmt.Printf("new type: %%Y\n", gotype)
 	}
 
-	kind = decodetype_kind(gotype)
-	bytesize = decodetype_size(gotype)
+	kind := decodetype_kind(gotype)
+	bytesize := decodetype_size(gotype)
 
 	switch kind {
 	case obj.KindBool:
@@ -1180,9 +1150,9 @@
 		die = newdie(&dwtypes, DW_ABRV_ARRAYTYPE, name)
 		dotypedef(&dwtypes, name, die)
 		newattr(die, DW_AT_byte_size, DW_CLS_CONSTANT, bytesize, 0)
-		s = decodetype_arrayelem(gotype)
+		s := decodetype_arrayelem(gotype)
 		newrefattr(die, DW_AT_type, defgotype(s))
-		fld = newdie(die, DW_ABRV_ARRAYRANGE, "range")
+		fld := newdie(die, DW_ABRV_ARRAYRANGE, "range")
 
 		// use actual length not upper bound; correct for 0-length arrays.
 		newattr(fld, DW_AT_count, DW_CLS_CONSTANT, decodetype_arraylen(gotype), 0)
@@ -1192,15 +1162,17 @@
 	case obj.KindChan:
 		die = newdie(&dwtypes, DW_ABRV_CHANTYPE, name)
 		newattr(die, DW_AT_byte_size, DW_CLS_CONSTANT, bytesize, 0)
-		s = decodetype_chanelem(gotype)
+		s := decodetype_chanelem(gotype)
 		newrefattr(die, DW_AT_go_elem, defgotype(s))
 
 	case obj.KindFunc:
 		die = newdie(&dwtypes, DW_ABRV_FUNCTYPE, name)
 		dotypedef(&dwtypes, name, die)
 		newrefattr(die, DW_AT_type, find_or_diag(&dwtypes, "void"))
-		nfields = decodetype_funcincount(gotype)
-		for i = 0; i < nfields; i++ {
+		nfields := decodetype_funcincount(gotype)
+		var fld *DWDie
+		var s *LSym
+		for i := 0; i < nfields; i++ {
 			s = decodetype_funcintype(gotype, i)
 			fld = newdie(die, DW_ABRV_FUNCTYPEPARAM, s.Name[5:])
 			newrefattr(fld, DW_AT_type, defgotype(s))
@@ -1210,7 +1182,7 @@
 			newdie(die, DW_ABRV_DOTDOTDOT, "...")
 		}
 		nfields = decodetype_funcoutcount(gotype)
-		for i = 0; i < nfields; i++ {
+		for i := 0; i < nfields; i++ {
 			s = decodetype_funcouttype(gotype, i)
 			fld = newdie(die, DW_ABRV_FUNCTYPEPARAM, s.Name[5:])
 			newrefattr(fld, DW_AT_type, defptrto(defgotype(s)))
@@ -1220,7 +1192,8 @@
 		die = newdie(&dwtypes, DW_ABRV_IFACETYPE, name)
 		dotypedef(&dwtypes, name, die)
 		newattr(die, DW_AT_byte_size, DW_CLS_CONSTANT, bytesize, 0)
-		nfields = int(decodetype_ifacemethodcount(gotype))
+		nfields := int(decodetype_ifacemethodcount(gotype))
+		var s *LSym
 		if nfields == 0 {
 			s = lookup_or_diag("type.runtime.eface")
 		} else {
@@ -1230,7 +1203,7 @@
 
 	case obj.KindMap:
 		die = newdie(&dwtypes, DW_ABRV_MAPTYPE, name)
-		s = decodetype_mapkey(gotype)
+		s := decodetype_mapkey(gotype)
 		newrefattr(die, DW_AT_go_key, defgotype(s))
 		s = decodetype_mapvalue(gotype)
 		newrefattr(die, DW_AT_go_elem, defgotype(s))
@@ -1238,14 +1211,14 @@
 	case obj.KindPtr:
 		die = newdie(&dwtypes, DW_ABRV_PTRTYPE, name)
 		dotypedef(&dwtypes, name, die)
-		s = decodetype_ptrelem(gotype)
+		s := decodetype_ptrelem(gotype)
 		newrefattr(die, DW_AT_type, defgotype(s))
 
 	case obj.KindSlice:
 		die = newdie(&dwtypes, DW_ABRV_SLICETYPE, name)
 		dotypedef(&dwtypes, name, die)
 		newattr(die, DW_AT_byte_size, DW_CLS_CONSTANT, bytesize, 0)
-		s = decodetype_arrayelem(gotype)
+		s := decodetype_arrayelem(gotype)
 		newrefattr(die, DW_AT_go_elem, defgotype(s))
 
 	case obj.KindString:
@@ -1256,8 +1229,11 @@
 		die = newdie(&dwtypes, DW_ABRV_STRUCTTYPE, name)
 		dotypedef(&dwtypes, name, die)
 		newattr(die, DW_AT_byte_size, DW_CLS_CONSTANT, bytesize, 0)
-		nfields = decodetype_structfieldcount(gotype)
-		for i = 0; i < nfields; i++ {
+		nfields := decodetype_structfieldcount(gotype)
+		var f string
+		var fld *DWDie
+		var s *LSym
+		for i := 0; i < nfields; i++ {
 			f = decodetype_structfieldname(gotype, i)
 			s = decodetype_structfieldtype(gotype, i)
 			if f == "" {
@@ -1284,11 +1260,8 @@
 
 // Find or construct *T given T.
 func defptrto(dwtype *DWDie) *DWDie {
-	var ptrname string
-	var die *DWDie
-
-	ptrname = fmt.Sprintf("*%s", getattr(dwtype, DW_AT_name).data)
-	die = find(&dwtypes, ptrname)
+	ptrname := fmt.Sprintf("*%s", getattr(dwtype, DW_AT_name).data)
+	die := find(&dwtypes, ptrname)
 	if die == nil {
 		die = newdie(&dwtypes, DW_ABRV_PTRTYPE, ptrname)
 		newrefattr(die, DW_AT_type, dwtype)
@@ -1325,15 +1298,12 @@
 // Search children (assumed to have DW_TAG_member) for the one named
 // field and set its DW_AT_type to dwtype
 func substitutetype(structdie *DWDie, field string, dwtype *DWDie) {
-	var child *DWDie
-	var a *DWAttr
-
-	child = find_or_diag(structdie, field)
+	child := find_or_diag(structdie, field)
 	if child == nil {
 		return
 	}
 
-	a = getattr(child, DW_AT_type)
+	a := getattr(child, DW_AT_type)
 	if a != nil {
 		a.data = dwtype
 	} else {
@@ -1342,9 +1312,7 @@
 }
 
 func synthesizestringtypes(die *DWDie) {
-	var prototype *DWDie
-
-	prototype = walktypedef(defgotype(lookup_or_diag("type.runtime._string")))
+	prototype := walktypedef(defgotype(lookup_or_diag("type.runtime._string")))
 	if prototype == nil {
 		return
 	}
@@ -1358,14 +1326,12 @@
 }
 
 func synthesizeslicetypes(die *DWDie) {
-	var prototype *DWDie
-	var elem *DWDie
-
-	prototype = walktypedef(defgotype(lookup_or_diag("type.runtime.slice")))
+	prototype := walktypedef(defgotype(lookup_or_diag("type.runtime.slice")))
 	if prototype == nil {
 		return
 	}
 
+	var elem *DWDie
 	for ; die != nil; die = die.link {
 		if die.abbrev != DW_ABRV_SLICETYPE {
 			continue
@@ -1378,14 +1344,13 @@
 
 func mkinternaltypename(base string, arg1 string, arg2 string) string {
 	var buf string
-	var n string
 
 	if arg2 == "" {
 		buf = fmt.Sprintf("%s<%s>", base, arg1)
 	} else {
 		buf = fmt.Sprintf("%s<%s,%s>", base, arg1, arg2)
 	}
-	n = buf
+	n := buf
 	return n
 }
 
@@ -1397,29 +1362,26 @@
 )
 
 func synthesizemaptypes(die *DWDie) {
-	var hash *DWDie
-	var bucket *DWDie
-	var dwh *DWDie
-	var dwhk *DWDie
-	var dwhv *DWDie
-	var dwhb *DWDie
-	var keytype *DWDie
-	var valtype *DWDie
-	var fld *DWDie
-	var t *DWDie
-	var indirect_key int
-	var indirect_val int
-	var keysize int
-	var valsize int
-	var a *DWAttr
-
-	hash = walktypedef(defgotype(lookup_or_diag("type.runtime.hmap")))
-	bucket = walktypedef(defgotype(lookup_or_diag("type.runtime.bmap")))
+	hash := walktypedef(defgotype(lookup_or_diag("type.runtime.hmap")))
+	bucket := walktypedef(defgotype(lookup_or_diag("type.runtime.bmap")))
 
 	if hash == nil {
 		return
 	}
 
+	var a *DWAttr
+	var dwh *DWDie
+	var dwhb *DWDie
+	var dwhk *DWDie
+	var dwhv *DWDie
+	var fld *DWDie
+	var indirect_key int
+	var indirect_val int
+	var keysize int
+	var keytype *DWDie
+	var t *DWDie
+	var valsize int
+	var valtype *DWDie
 	for ; die != nil; die = die.link {
 		if die.abbrev != DW_ABRV_MAPTYPE {
 			continue
@@ -1518,26 +1480,21 @@
 }
 
 func synthesizechantypes(die *DWDie) {
-	var sudog *DWDie
-	var waitq *DWDie
-	var hchan *DWDie
-	var dws *DWDie
-	var dww *DWDie
-	var dwh *DWDie
-	var elemtype *DWDie
-	var a *DWAttr
-	var elemsize int
-	var sudogsize int
-
-	sudog = walktypedef(defgotype(lookup_or_diag("type.runtime.sudog")))
-	waitq = walktypedef(defgotype(lookup_or_diag("type.runtime.waitq")))
-	hchan = walktypedef(defgotype(lookup_or_diag("type.runtime.hchan")))
+	sudog := walktypedef(defgotype(lookup_or_diag("type.runtime.sudog")))
+	waitq := walktypedef(defgotype(lookup_or_diag("type.runtime.waitq")))
+	hchan := walktypedef(defgotype(lookup_or_diag("type.runtime.hchan")))
 	if sudog == nil || waitq == nil || hchan == nil {
 		return
 	}
 
-	sudogsize = int(getattr(sudog, DW_AT_byte_size).value)
+	sudogsize := int(getattr(sudog, DW_AT_byte_size).value)
 
+	var a *DWAttr
+	var dwh *DWDie
+	var dws *DWDie
+	var dww *DWDie
+	var elemsize int
+	var elemtype *DWDie
 	for ; die != nil; die = die.link {
 		if die.abbrev != DW_ABRV_CHANTYPE {
 			continue
@@ -1584,9 +1541,6 @@
 
 // For use with pass.c::genasmsym
 func defdwsymb(sym *LSym, s string, t int, v int64, size int64, ver int, gotype *LSym) {
-	var dv *DWDie
-	var dt *DWDie
-
 	if strings.HasPrefix(s, "go.string.") {
 		return
 	}
@@ -1596,16 +1550,14 @@
 		return
 	}
 
-	dv = nil
+	var dv *DWDie
 
+	var dt *DWDie
 	switch t {
 	default:
 		return
 
-	case 'd',
-		'b',
-		'D',
-		'B':
+	case 'd', 'b', 'D', 'B':
 		dv = newdie(&dwglobals, DW_ABRV_VARIABLE, s)
 		newabslocexprattr(dv, v, sym)
 		if ver == 0 {
@@ -1614,8 +1566,7 @@
 		fallthrough
 
 		// fallthrough
-	case 'a',
-		'p':
+	case 'a', 'p':
 		dt = defgotype(gotype)
 	}
 
@@ -1625,9 +1576,7 @@
 }
 
 func movetomodule(parent *DWDie) {
-	var die *DWDie
-
-	die = dwroot.child.child
+	die := dwroot.child.child
 	for die.link != nil {
 		die = die.link
 	}
@@ -1636,15 +1585,13 @@
 
 // If the pcln table contains runtime/runtime.go, use that to set gdbscript path.
 func finddebugruntimepath(s *LSym) {
-	var i int
-	var p string
-	var f *LSym
-
 	if gdbscript != "" {
 		return
 	}
 
-	for i = 0; i < s.Pcln.Nfile; i++ {
+	var f *LSym
+	var p string
+	for i := 0; i < s.Pcln.Nfile; i++ {
 		f = s.Pcln.File[i]
 		_ = p
 		if i := strings.Index(f.Name, "runtime/runtime.go"); i >= 0 {
@@ -1685,9 +1632,8 @@
 
 func newcfaoffsetattr(die *DWDie, offs int32) {
 	var block [20]byte
-	var i int
 
-	i = 0
+	i := 0
 
 	block[i] = DW_OP_call_frame_cfa
 	i++
@@ -1703,11 +1649,8 @@
 }
 
 func mkvarname(name string, da int) string {
-	var buf string
-	var n string
-
-	buf = fmt.Sprintf("%s#%d", name, da)
-	n = buf
+	buf := fmt.Sprintf("%s#%d", name, da)
+	n := buf
 	return n
 }
 
@@ -1717,8 +1660,6 @@
 
 // flush previous compilation unit.
 func flushunit(dwinfo *DWDie, pc int64, pcsym *LSym, unitstart int64, header_length int32) {
-	var here int64
-
 	if dwinfo != nil && pc != 0 {
 		newattr(dwinfo, DW_AT_high_pc, DW_CLS_ADDRESS, pc+1, pcsym)
 	}
@@ -1728,7 +1669,7 @@
 		uleb128put(1)
 		Cput(DW_LNE_end_sequence)
 
-		here = Cpos()
+		here := Cpos()
 		Cseek(unitstart)
 		Thearch.Lput(uint32(here - unitstart - 4)) // unit_length
 		Thearch.Wput(2)                            // dwarf version
@@ -1738,50 +1679,24 @@
 }
 
 func writelines() {
-	var s *LSym
-	var epcs *LSym
-	var a *Auto
-	var unitstart int64
-	var headerend int64
-	var offs int64
-	var pc int64
-	var epc int64
-	var i int
-	var lang int
-	var da int
-	var dt int
-	var line int
-	var file int
-	var dwinfo *DWDie
-	var dwfunc *DWDie
-	var dwvar *DWDie
-	var dws **DWDie
-	var varhash [HASHSIZE]*DWDie
-	var n string
-	var nn string
-	var pcfile Pciter
-	var pcline Pciter
-	var files []*LSym
-	var f *LSym
-
 	if linesec == nil {
 		linesec = Linklookup(Ctxt, ".dwarfline", 0)
 	}
 	linesec.R = linesec.R[:0]
 
-	unitstart = -1
-	headerend = -1
-	epc = 0
-	epcs = nil
+	unitstart := int64(-1)
+	headerend := int64(-1)
+	epc := int64(0)
+	var epcs *LSym
 	lineo = Cpos()
-	dwinfo = nil
+	var dwinfo *DWDie
 
 	flushunit(dwinfo, epc, epcs, unitstart, int32(headerend-unitstart-10))
 	unitstart = Cpos()
 
-	lang = DW_LANG_Go
+	lang := DW_LANG_Go
 
-	s = Ctxt.Textp
+	s := Ctxt.Textp
 
 	dwinfo = newdie(&dwroot, DW_ABRV_COMPUNIT, "go")
 	newattr(dwinfo, DW_AT_language, DW_CLS_CONSTANT, int64(lang), 0)
@@ -1811,13 +1726,13 @@
 	Cput(1)                // standard_opcode_lengths[9]
 	Cput(0)                // include_directories  (empty)
 
-	files = make([]*LSym, Ctxt.Nhistfile)
+	files := make([]*LSym, Ctxt.Nhistfile)
 
-	for f = Ctxt.Filesyms; f != nil; f = f.Next {
+	for f := Ctxt.Filesyms; f != nil; f = f.Next {
 		files[f.Value-1] = f
 	}
 
-	for i = 0; int32(i) < Ctxt.Nhistfile; i++ {
+	for i := 0; int32(i) < Ctxt.Nhistfile; i++ {
 		strnput(files[i].Name, len(files[i].Name)+4)
 	}
 
@@ -1830,15 +1745,27 @@
 	uleb128put(1 + int64(Thearch.Ptrsize))
 	Cput(DW_LNE_set_address)
 
-	pc = s.Value
-	line = 1
-	file = 1
+	pc := s.Value
+	line := 1
+	file := 1
 	if Linkmode == LinkExternal {
 		adddwarfrel(linesec, s, lineo, Thearch.Ptrsize, 0)
 	} else {
 		addrput(pc)
 	}
 
+	var a *Auto
+	var da int
+	var dt int
+	var dwfunc *DWDie
+	var dws **DWDie
+	var dwvar *DWDie
+	var n string
+	var nn string
+	var offs int64
+	var pcfile Pciter
+	var pcline Pciter
+	var varhash [HASHSIZE]*DWDie
 	for Ctxt.Cursym = Ctxt.Textp; Ctxt.Cursym != nil; Ctxt.Cursym = Ctxt.Cursym.Next {
 		s = Ctxt.Cursym
 
@@ -1953,7 +1880,7 @@
 const (
 	CIERESERVE          = 16
 	DATAALIGNMENTFACTOR = -4
-	FAKERETURNCOLUMN    = 16
+	FAKERETURNCOLUMN    = 16 // TODO gdb6 doesn't like > 15?
 )
 
 func putpccfadelta(deltapc int64, cfa int64) {
@@ -1975,13 +1902,6 @@
 }
 
 func writeframes() {
-	var s *LSym
-	var fdeo int64
-	var fdesize int64
-	var pad int64
-	var pcsp Pciter
-	var nextpc uint32
-
 	if framesec == nil {
 		framesec = Linklookup(Ctxt, ".dwarfframe", 0)
 	}
@@ -2006,7 +1926,7 @@
 	uleb128put(int64(-Thearch.Ptrsize) / DATAALIGNMENTFACTOR) // at cfa - x*4
 
 	// 4 is to exclude the length field.
-	pad = CIERESERVE + frameo + 4 - Cpos()
+	pad := CIERESERVE + frameo + 4 - Cpos()
 
 	if pad < 0 {
 		Diag("dwarf: CIERESERVE too small by %d bytes.", -pad)
@@ -2015,6 +1935,11 @@
 
 	strnput("", int(pad))
 
+	var fdeo int64
+	var fdesize int64
+	var nextpc uint32
+	var pcsp Pciter
+	var s *LSym
 	for Ctxt.Cursym = Ctxt.Textp; Ctxt.Cursym != nil; Ctxt.Cursym = Ctxt.Cursym.Next {
 		s = Ctxt.Cursym
 		if s.Pcln == nil {
@@ -2077,10 +2002,6 @@
 )
 
 func writeinfo() {
-	var compunit *DWDie
-	var unitstart int64
-	var here int64
-
 	fwdcount = 0
 	if infosec == nil {
 		infosec = Linklookup(Ctxt, ".dwarfinfo", 0)
@@ -2092,7 +2013,9 @@
 	}
 	arangessec.R = arangessec.R[:0]
 
-	for compunit = dwroot.child; compunit != nil; compunit = compunit.link {
+	var here int64
+	var unitstart int64
+	for compunit := dwroot.child; compunit != nil; compunit = compunit.link {
 		unitstart = Cpos()
 
 		// Write .debug_info Compilation Unit Header (sec 7.5.1)
@@ -2126,12 +2049,9 @@
  *  because we need die->offs and infoo/infosize;
  */
 func ispubname(die *DWDie) bool {
-	var a *DWAttr
-
 	switch die.abbrev {
-	case DW_ABRV_FUNCTION,
-		DW_ABRV_VARIABLE:
-		a = getattr(die, DW_AT_external)
+	case DW_ABRV_FUNCTION, DW_ABRV_VARIABLE:
+		a := getattr(die, DW_AT_external)
 		return a != nil && a.value != 0
 	}
 
@@ -2143,17 +2063,15 @@
 }
 
 func writepub(ispub func(*DWDie) bool) int64 {
-	var compunit *DWDie
 	var die *DWDie
 	var dwa *DWAttr
 	var unitstart int64
 	var unitend int64
-	var sectionstart int64
 	var here int64
 
-	sectionstart = Cpos()
+	sectionstart := Cpos()
 
-	for compunit = dwroot.child; compunit != nil; compunit = compunit.link {
+	for compunit := dwroot.child; compunit != nil; compunit = compunit.link {
 		unitstart = compunit.offs - COMPUNITHEADERSIZE
 		if compunit.link != nil {
 			unitend = compunit.link.offs - COMPUNITHEADERSIZE
@@ -2192,17 +2110,14 @@
  *  because we need die->offs of dw_globals.
  */
 func writearanges() int64 {
-	var compunit *DWDie
 	var b *DWAttr
 	var e *DWAttr
-	var headersize int
-	var sectionstart int64
 	var value int64
 
-	sectionstart = Cpos()
-	headersize = int(Rnd(4+2+4+1+1, int64(Thearch.Ptrsize))) // don't count unit_length field itself
+	sectionstart := Cpos()
+	headersize := int(Rnd(4+2+4+1+1, int64(Thearch.Ptrsize))) // don't count unit_length field itself
 
-	for compunit = dwroot.child; compunit != nil; compunit = compunit.link {
+	for compunit := dwroot.child; compunit != nil; compunit = compunit.link {
 		b = getattr(compunit, DW_AT_low_pc)
 		if b == nil {
 			continue
@@ -2243,9 +2158,7 @@
 }
 
 func writegdbscript() int64 {
-	var sectionstart int64
-
-	sectionstart = Cpos()
+	sectionstart := Cpos()
 
 	if gdbscript != "" {
 		Cput(1) // magic 1 byte?
@@ -2264,12 +2177,10 @@
 
 func writedwarfreloc(s *LSym) int64 {
 	var i int
-	var ri int
-	var start int64
 	var r *Reloc
 
-	start = Cpos()
-	for ri = 0; ri < len(s.R); ri++ {
+	start := Cpos()
+	for ri := 0; ri < len(s.R); ri++ {
 		r = &s.R[ri]
 		if Iself {
 			i = Thearch.Elfreloc1(r, int64(r.Off))
@@ -2296,9 +2207,6 @@
  *
  */
 func Dwarfemitdebugsections() {
-	var infoe int64
-	var die *DWDie
-
 	if Debug['w'] != 0 { // disable dwarf
 		return
 	}
@@ -2320,7 +2228,7 @@
 	newdie(&dwtypes, DW_ABRV_NULLTYPE, "void")
 	newdie(&dwtypes, DW_ABRV_BARE_PTRTYPE, "unsafe.Pointer")
 
-	die = newdie(&dwtypes, DW_ABRV_BASETYPE, "uintptr") // needed for array size
+	die := newdie(&dwtypes, DW_ABRV_BASETYPE, "uintptr") // needed for array size
 	newattr(die, DW_AT_encoding, DW_CLS_CONSTANT, DW_ATE_unsigned, 0)
 	newattr(die, DW_AT_byte_size, DW_CLS_CONSTANT, int64(Thearch.Ptrsize), 0)
 	newattr(die, DW_AT_go_kind, DW_CLS_CONSTANT, obj.KindUintptr, 0)
@@ -2354,7 +2262,7 @@
 
 	infoo = Cpos()
 	writeinfo()
-	infoe = Cpos()
+	infoe := Cpos()
 	pubnameso = infoe
 	pubtypeso = infoe
 	arangeso = infoe
@@ -2510,9 +2418,7 @@
 }
 
 func dwarfaddelfrelocheader(elfstr int, shdata *ElfShdr, off int64, size int64) {
-	var sh *ElfShdr
-
-	sh = newElfShdr(elfstrdbg[elfstr])
+	sh := newElfShdr(elfstrdbg[elfstr])
 	if Thearch.Thechar == '6' || Thearch.Thechar == '9' {
 		sh.type_ = SHT_RELA
 	} else {
@@ -2531,17 +2437,11 @@
 }
 
 func dwarfaddelfheaders() {
-	var sh *ElfShdr
-	var shinfo *ElfShdr
-	var sharanges *ElfShdr
-	var shline *ElfShdr
-	var shframe *ElfShdr
-
 	if Debug['w'] != 0 { // disable dwarf
 		return
 	}
 
-	sh = newElfShdr(elfstrdbg[ElfStrDebugAbbrev])
+	sh := newElfShdr(elfstrdbg[ElfStrDebugAbbrev])
 	sh.type_ = SHT_PROGBITS
 	sh.off = uint64(abbrevo)
 	sh.size = uint64(abbrevsize)
@@ -2558,7 +2458,7 @@
 	if linesympos > 0 {
 		putelfsymshndx(linesympos, sh.shnum)
 	}
-	shline = sh
+	shline := sh
 
 	sh = newElfShdr(elfstrdbg[ElfStrDebugFrame])
 	sh.type_ = SHT_PROGBITS
@@ -2568,7 +2468,7 @@
 	if framesympos > 0 {
 		putelfsymshndx(framesympos, sh.shnum)
 	}
-	shframe = sh
+	shframe := sh
 
 	sh = newElfShdr(elfstrdbg[ElfStrDebugInfo])
 	sh.type_ = SHT_PROGBITS
@@ -2578,10 +2478,10 @@
 	if infosympos > 0 {
 		putelfsymshndx(infosympos, sh.shnum)
 	}
-	shinfo = sh
+	shinfo := sh
 
 	if pubnamessize > 0 {
-		sh = newElfShdr(elfstrdbg[ElfStrDebugPubNames])
+		sh := newElfShdr(elfstrdbg[ElfStrDebugPubNames])
 		sh.type_ = SHT_PROGBITS
 		sh.off = uint64(pubnameso)
 		sh.size = uint64(pubnamessize)
@@ -2589,16 +2489,16 @@
 	}
 
 	if pubtypessize > 0 {
-		sh = newElfShdr(elfstrdbg[ElfStrDebugPubTypes])
+		sh := newElfShdr(elfstrdbg[ElfStrDebugPubTypes])
 		sh.type_ = SHT_PROGBITS
 		sh.off = uint64(pubtypeso)
 		sh.size = uint64(pubtypessize)
 		sh.addralign = 1
 	}
 
-	sharanges = nil
+	var sharanges *ElfShdr
 	if arangessize != 0 {
-		sh = newElfShdr(elfstrdbg[ElfStrDebugAranges])
+		sh := newElfShdr(elfstrdbg[ElfStrDebugAranges])
 		sh.type_ = SHT_PROGBITS
 		sh.off = uint64(arangeso)
 		sh.size = uint64(arangessize)
@@ -2607,7 +2507,7 @@
 	}
 
 	if gdbscriptsize != 0 {
-		sh = newElfShdr(elfstrdbg[ElfStrGDBScripts])
+		sh := newElfShdr(elfstrdbg[ElfStrGDBScripts])
 		sh.type_ = SHT_PROGBITS
 		sh.off = uint64(gdbscripto)
 		sh.size = uint64(gdbscriptsize)
@@ -2635,20 +2535,15 @@
  * Macho
  */
 func dwarfaddmachoheaders() {
-	var msect *MachoSect
-	var ms *MachoSeg
-	var fakestart int64
-	var nsect int
-
 	if Debug['w'] != 0 { // disable dwarf
 		return
 	}
 
 	// Zero vsize segments won't be loaded in memory, even so they
 	// have to be page aligned in the file.
-	fakestart = abbrevo &^ 0xfff
+	fakestart := abbrevo &^ 0xfff
 
-	nsect = 4
+	nsect := 4
 	if pubnamessize > 0 {
 		nsect++
 	}
@@ -2662,12 +2557,12 @@
 		nsect++
 	}
 
-	ms = newMachoSeg("__DWARF", nsect)
+	ms := newMachoSeg("__DWARF", nsect)
 	ms.fileoffset = uint64(fakestart)
 	ms.filesize = uint64(abbrevo) - uint64(fakestart)
 	ms.vaddr = ms.fileoffset + Segdata.Vaddr - Segdata.Fileoff
 
-	msect = newMachoSect(ms, "__debug_abbrev", "__DWARF")
+	msect := newMachoSect(ms, "__debug_abbrev", "__DWARF")
 	msect.off = uint32(abbrevo)
 	msect.size = uint64(abbrevsize)
 	msect.addr = uint64(msect.off) + Segdata.Vaddr - Segdata.Fileoff
@@ -2692,7 +2587,7 @@
 	ms.filesize += msect.size
 
 	if pubnamessize > 0 {
-		msect = newMachoSect(ms, "__debug_pubnames", "__DWARF")
+		msect := newMachoSect(ms, "__debug_pubnames", "__DWARF")
 		msect.off = uint32(pubnameso)
 		msect.size = uint64(pubnamessize)
 		msect.addr = uint64(msect.off) + Segdata.Vaddr - Segdata.Fileoff
@@ -2700,7 +2595,7 @@
 	}
 
 	if pubtypessize > 0 {
-		msect = newMachoSect(ms, "__debug_pubtypes", "__DWARF")
+		msect := newMachoSect(ms, "__debug_pubtypes", "__DWARF")
 		msect.off = uint32(pubtypeso)
 		msect.size = uint64(pubtypessize)
 		msect.addr = uint64(msect.off) + Segdata.Vaddr - Segdata.Fileoff
@@ -2708,7 +2603,7 @@
 	}
 
 	if arangessize > 0 {
-		msect = newMachoSect(ms, "__debug_aranges", "__DWARF")
+		msect := newMachoSect(ms, "__debug_aranges", "__DWARF")
 		msect.off = uint32(arangeso)
 		msect.size = uint64(arangessize)
 		msect.addr = uint64(msect.off) + Segdata.Vaddr - Segdata.Fileoff
@@ -2717,7 +2612,7 @@
 
 	// TODO(lvd) fix gdb/python to load MachO (16 char section name limit)
 	if gdbscriptsize > 0 {
-		msect = newMachoSect(ms, "__debug_gdb_scripts", "__DWARF")
+		msect := newMachoSect(ms, "__debug_gdb_scripts", "__DWARF")
 		msect.off = uint32(gdbscripto)
 		msect.size = uint64(gdbscriptsize)
 		msect.addr = uint64(msect.off) + Segdata.Vaddr - Segdata.Fileoff
diff --git a/src/cmd/internal/ld/dwarf_defs.go b/src/cmd/internal/ld/dwarf_defs.go
index 5be8389..61389d9 100644
--- a/src/cmd/internal/ld/dwarf_defs.go
+++ b/src/cmd/internal/ld/dwarf_defs.go
@@ -89,21 +89,25 @@
 	DW_TAG_variant_part             = 0x33
 	DW_TAG_variable                 = 0x34
 	DW_TAG_volatile_type            = 0x35
-	DW_TAG_dwarf_procedure          = 0x36
-	DW_TAG_restrict_type            = 0x37
-	DW_TAG_interface_type           = 0x38
-	DW_TAG_namespace                = 0x39
-	DW_TAG_imported_module          = 0x3a
-	DW_TAG_unspecified_type         = 0x3b
-	DW_TAG_partial_unit             = 0x3c
-	DW_TAG_imported_unit            = 0x3d
-	DW_TAG_condition                = 0x3f
-	DW_TAG_shared_type              = 0x40
-	DW_TAG_type_unit                = 0x41
-	DW_TAG_rvalue_reference_type    = 0x42
-	DW_TAG_template_alias           = 0x43
-	DW_TAG_lo_user                  = 0x4080
-	DW_TAG_hi_user                  = 0xffff
+	// Dwarf3
+	DW_TAG_dwarf_procedure  = 0x36
+	DW_TAG_restrict_type    = 0x37
+	DW_TAG_interface_type   = 0x38
+	DW_TAG_namespace        = 0x39
+	DW_TAG_imported_module  = 0x3a
+	DW_TAG_unspecified_type = 0x3b
+	DW_TAG_partial_unit     = 0x3c
+	DW_TAG_imported_unit    = 0x3d
+	DW_TAG_condition        = 0x3f
+	DW_TAG_shared_type      = 0x40
+	// Dwarf4
+	DW_TAG_type_unit             = 0x41
+	DW_TAG_rvalue_reference_type = 0x42
+	DW_TAG_template_alias        = 0x43
+
+	// User defined
+	DW_TAG_lo_user = 0x4080
+	DW_TAG_hi_user = 0xffff
 )
 
 // Table 19
@@ -118,7 +122,7 @@
 	DW_CLS_BLOCK
 	DW_CLS_CONSTANT
 	DW_CLS_FLAG
-	DW_CLS_PTR
+	DW_CLS_PTR // lineptr, loclistptr, macptr, rangelistptr
 	DW_CLS_REFERENCE
 	DW_CLS_ADDRLOC
 	DW_CLS_STRING
@@ -126,185 +130,187 @@
 
 // Table 20
 const (
-	DW_AT_sibling              = 0x01
-	DW_AT_location             = 0x02
-	DW_AT_name                 = 0x03
-	DW_AT_ordering             = 0x09
-	DW_AT_byte_size            = 0x0b
-	DW_AT_bit_offset           = 0x0c
-	DW_AT_bit_size             = 0x0d
-	DW_AT_stmt_list            = 0x10
-	DW_AT_low_pc               = 0x11
-	DW_AT_high_pc              = 0x12
-	DW_AT_language             = 0x13
-	DW_AT_discr                = 0x15
-	DW_AT_discr_value          = 0x16
-	DW_AT_visibility           = 0x17
-	DW_AT_import               = 0x18
-	DW_AT_string_length        = 0x19
-	DW_AT_common_reference     = 0x1a
-	DW_AT_comp_dir             = 0x1b
-	DW_AT_const_value          = 0x1c
-	DW_AT_containing_type      = 0x1d
-	DW_AT_default_value        = 0x1e
-	DW_AT_inline               = 0x20
-	DW_AT_is_optional          = 0x21
-	DW_AT_lower_bound          = 0x22
-	DW_AT_producer             = 0x25
-	DW_AT_prototyped           = 0x27
-	DW_AT_return_addr          = 0x2a
-	DW_AT_start_scope          = 0x2c
-	DW_AT_bit_stride           = 0x2e
-	DW_AT_upper_bound          = 0x2f
-	DW_AT_abstract_origin      = 0x31
-	DW_AT_accessibility        = 0x32
-	DW_AT_address_class        = 0x33
-	DW_AT_artificial           = 0x34
-	DW_AT_base_types           = 0x35
-	DW_AT_calling_convention   = 0x36
-	DW_AT_count                = 0x37
-	DW_AT_data_member_location = 0x38
-	DW_AT_decl_column          = 0x39
-	DW_AT_decl_file            = 0x3a
-	DW_AT_decl_line            = 0x3b
-	DW_AT_declaration          = 0x3c
-	DW_AT_discr_list           = 0x3d
-	DW_AT_encoding             = 0x3e
-	DW_AT_external             = 0x3f
-	DW_AT_frame_base           = 0x40
-	DW_AT_friend               = 0x41
-	DW_AT_identifier_case      = 0x42
-	DW_AT_macro_info           = 0x43
-	DW_AT_namelist_item        = 0x44
-	DW_AT_priority             = 0x45
-	DW_AT_segment              = 0x46
-	DW_AT_specification        = 0x47
-	DW_AT_static_link          = 0x48
-	DW_AT_type                 = 0x49
-	DW_AT_use_location         = 0x4a
-	DW_AT_variable_parameter   = 0x4b
-	DW_AT_virtuality           = 0x4c
-	DW_AT_vtable_elem_location = 0x4d
-	DW_AT_allocated            = 0x4e
-	DW_AT_associated           = 0x4f
-	DW_AT_data_location        = 0x50
-	DW_AT_byte_stride          = 0x51
-	DW_AT_entry_pc             = 0x52
-	DW_AT_use_UTF8             = 0x53
-	DW_AT_extension            = 0x54
-	DW_AT_ranges               = 0x55
-	DW_AT_trampoline           = 0x56
-	DW_AT_call_column          = 0x57
-	DW_AT_call_file            = 0x58
-	DW_AT_call_line            = 0x59
-	DW_AT_description          = 0x5a
-	DW_AT_binary_scale         = 0x5b
-	DW_AT_decimal_scale        = 0x5c
-	DW_AT_small                = 0x5d
-	DW_AT_decimal_sign         = 0x5e
-	DW_AT_digit_count          = 0x5f
-	DW_AT_picture_string       = 0x60
-	DW_AT_mutable              = 0x61
-	DW_AT_threads_scaled       = 0x62
-	DW_AT_explicit             = 0x63
-	DW_AT_object_pointer       = 0x64
-	DW_AT_endianity            = 0x65
-	DW_AT_elemental            = 0x66
-	DW_AT_pure                 = 0x67
-	DW_AT_recursive            = 0x68
-	DW_AT_lo_user              = 0x2000
-	DW_AT_hi_user              = 0x3fff
+	DW_AT_sibling              = 0x01 // reference
+	DW_AT_location             = 0x02 // block, loclistptr
+	DW_AT_name                 = 0x03 // string
+	DW_AT_ordering             = 0x09 // constant
+	DW_AT_byte_size            = 0x0b // block, constant, reference
+	DW_AT_bit_offset           = 0x0c // block, constant, reference
+	DW_AT_bit_size             = 0x0d // block, constant, reference
+	DW_AT_stmt_list            = 0x10 // lineptr
+	DW_AT_low_pc               = 0x11 // address
+	DW_AT_high_pc              = 0x12 // address
+	DW_AT_language             = 0x13 // constant
+	DW_AT_discr                = 0x15 // reference
+	DW_AT_discr_value          = 0x16 // constant
+	DW_AT_visibility           = 0x17 // constant
+	DW_AT_import               = 0x18 // reference
+	DW_AT_string_length        = 0x19 // block, loclistptr
+	DW_AT_common_reference     = 0x1a // reference
+	DW_AT_comp_dir             = 0x1b // string
+	DW_AT_const_value          = 0x1c // block, constant, string
+	DW_AT_containing_type      = 0x1d // reference
+	DW_AT_default_value        = 0x1e // reference
+	DW_AT_inline               = 0x20 // constant
+	DW_AT_is_optional          = 0x21 // flag
+	DW_AT_lower_bound          = 0x22 // block, constant, reference
+	DW_AT_producer             = 0x25 // string
+	DW_AT_prototyped           = 0x27 // flag
+	DW_AT_return_addr          = 0x2a // block, loclistptr
+	DW_AT_start_scope          = 0x2c // constant
+	DW_AT_bit_stride           = 0x2e // constant
+	DW_AT_upper_bound          = 0x2f // block, constant, reference
+	DW_AT_abstract_origin      = 0x31 // reference
+	DW_AT_accessibility        = 0x32 // constant
+	DW_AT_address_class        = 0x33 // constant
+	DW_AT_artificial           = 0x34 // flag
+	DW_AT_base_types           = 0x35 // reference
+	DW_AT_calling_convention   = 0x36 // constant
+	DW_AT_count                = 0x37 // block, constant, reference
+	DW_AT_data_member_location = 0x38 // block, constant, loclistptr
+	DW_AT_decl_column          = 0x39 // constant
+	DW_AT_decl_file            = 0x3a // constant
+	DW_AT_decl_line            = 0x3b // constant
+	DW_AT_declaration          = 0x3c // flag
+	DW_AT_discr_list           = 0x3d // block
+	DW_AT_encoding             = 0x3e // constant
+	DW_AT_external             = 0x3f // flag
+	DW_AT_frame_base           = 0x40 // block, loclistptr
+	DW_AT_friend               = 0x41 // reference
+	DW_AT_identifier_case      = 0x42 // constant
+	DW_AT_macro_info           = 0x43 // macptr
+	DW_AT_namelist_item        = 0x44 // block
+	DW_AT_priority             = 0x45 // reference
+	DW_AT_segment              = 0x46 // block, loclistptr
+	DW_AT_specification        = 0x47 // reference
+	DW_AT_static_link          = 0x48 // block, loclistptr
+	DW_AT_type                 = 0x49 // reference
+	DW_AT_use_location         = 0x4a // block, loclistptr
+	DW_AT_variable_parameter   = 0x4b // flag
+	DW_AT_virtuality           = 0x4c // constant
+	DW_AT_vtable_elem_location = 0x4d // block, loclistptr
+	// Dwarf3
+	DW_AT_allocated      = 0x4e // block, constant, reference
+	DW_AT_associated     = 0x4f // block, constant, reference
+	DW_AT_data_location  = 0x50 // block
+	DW_AT_byte_stride    = 0x51 // block, constant, reference
+	DW_AT_entry_pc       = 0x52 // address
+	DW_AT_use_UTF8       = 0x53 // flag
+	DW_AT_extension      = 0x54 // reference
+	DW_AT_ranges         = 0x55 // rangelistptr
+	DW_AT_trampoline     = 0x56 // address, flag, reference, string
+	DW_AT_call_column    = 0x57 // constant
+	DW_AT_call_file      = 0x58 // constant
+	DW_AT_call_line      = 0x59 // constant
+	DW_AT_description    = 0x5a // string
+	DW_AT_binary_scale   = 0x5b // constant
+	DW_AT_decimal_scale  = 0x5c // constant
+	DW_AT_small          = 0x5d // reference
+	DW_AT_decimal_sign   = 0x5e // constant
+	DW_AT_digit_count    = 0x5f // constant
+	DW_AT_picture_string = 0x60 // string
+	DW_AT_mutable        = 0x61 // flag
+	DW_AT_threads_scaled = 0x62 // flag
+	DW_AT_explicit       = 0x63 // flag
+	DW_AT_object_pointer = 0x64 // reference
+	DW_AT_endianity      = 0x65 // constant
+	DW_AT_elemental      = 0x66 // flag
+	DW_AT_pure           = 0x67 // flag
+	DW_AT_recursive      = 0x68 // flag
+
+	DW_AT_lo_user = 0x2000 // ---
+	DW_AT_hi_user = 0x3fff // ---
 )
 
 // Table 21
 const (
-	DW_FORM_addr      = 0x01
-	DW_FORM_block2    = 0x03
-	DW_FORM_block4    = 0x04
-	DW_FORM_data2     = 0x05
-	DW_FORM_data4     = 0x06
-	DW_FORM_data8     = 0x07
-	DW_FORM_string    = 0x08
-	DW_FORM_block     = 0x09
-	DW_FORM_block1    = 0x0a
-	DW_FORM_data1     = 0x0b
-	DW_FORM_flag      = 0x0c
-	DW_FORM_sdata     = 0x0d
-	DW_FORM_strp      = 0x0e
-	DW_FORM_udata     = 0x0f
-	DW_FORM_ref_addr  = 0x10
-	DW_FORM_ref1      = 0x11
-	DW_FORM_ref2      = 0x12
-	DW_FORM_ref4      = 0x13
-	DW_FORM_ref8      = 0x14
-	DW_FORM_ref_udata = 0x15
-	DW_FORM_indirect  = 0x16
+	DW_FORM_addr      = 0x01 // address
+	DW_FORM_block2    = 0x03 // block
+	DW_FORM_block4    = 0x04 // block
+	DW_FORM_data2     = 0x05 // constant
+	DW_FORM_data4     = 0x06 // constant, lineptr, loclistptr, macptr, rangelistptr
+	DW_FORM_data8     = 0x07 // constant, lineptr, loclistptr, macptr, rangelistptr
+	DW_FORM_string    = 0x08 // string
+	DW_FORM_block     = 0x09 // block
+	DW_FORM_block1    = 0x0a // block
+	DW_FORM_data1     = 0x0b // constant
+	DW_FORM_flag      = 0x0c // flag
+	DW_FORM_sdata     = 0x0d // constant
+	DW_FORM_strp      = 0x0e // string
+	DW_FORM_udata     = 0x0f // constant
+	DW_FORM_ref_addr  = 0x10 // reference
+	DW_FORM_ref1      = 0x11 // reference
+	DW_FORM_ref2      = 0x12 // reference
+	DW_FORM_ref4      = 0x13 // reference
+	DW_FORM_ref8      = 0x14 // reference
+	DW_FORM_ref_udata = 0x15 // reference
+	DW_FORM_indirect  = 0x16 // (see Section 7.5.3)
 )
 
 // Table 24 (#operands, notes)
 const (
-	DW_OP_addr                = 0x03
-	DW_OP_deref               = 0x06
-	DW_OP_const1u             = 0x08
-	DW_OP_const1s             = 0x09
-	DW_OP_const2u             = 0x0a
-	DW_OP_const2s             = 0x0b
-	DW_OP_const4u             = 0x0c
-	DW_OP_const4s             = 0x0d
-	DW_OP_const8u             = 0x0e
-	DW_OP_const8s             = 0x0f
-	DW_OP_constu              = 0x10
-	DW_OP_consts              = 0x11
-	DW_OP_dup                 = 0x12
-	DW_OP_drop                = 0x13
-	DW_OP_over                = 0x14
-	DW_OP_pick                = 0x15
-	DW_OP_swap                = 0x16
-	DW_OP_rot                 = 0x17
-	DW_OP_xderef              = 0x18
-	DW_OP_abs                 = 0x19
-	DW_OP_and                 = 0x1a
-	DW_OP_div                 = 0x1b
-	DW_OP_minus               = 0x1c
-	DW_OP_mod                 = 0x1d
-	DW_OP_mul                 = 0x1e
-	DW_OP_neg                 = 0x1f
-	DW_OP_not                 = 0x20
-	DW_OP_or                  = 0x21
-	DW_OP_plus                = 0x22
-	DW_OP_plus_uconst         = 0x23
-	DW_OP_shl                 = 0x24
-	DW_OP_shr                 = 0x25
-	DW_OP_shra                = 0x26
-	DW_OP_xor                 = 0x27
-	DW_OP_skip                = 0x2f
-	DW_OP_bra                 = 0x28
-	DW_OP_eq                  = 0x29
-	DW_OP_ge                  = 0x2a
-	DW_OP_gt                  = 0x2b
-	DW_OP_le                  = 0x2c
-	DW_OP_lt                  = 0x2d
-	DW_OP_ne                  = 0x2e
-	DW_OP_lit0                = 0x30
-	DW_OP_lit31               = 0x4f
-	DW_OP_reg0                = 0x50
-	DW_OP_reg31               = 0x6f
-	DW_OP_breg0               = 0x70
-	DW_OP_breg31              = 0x8f
-	DW_OP_regx                = 0x90
-	DW_OP_fbreg               = 0x91
-	DW_OP_bregx               = 0x92
-	DW_OP_piece               = 0x93
-	DW_OP_deref_size          = 0x94
-	DW_OP_xderef_size         = 0x95
-	DW_OP_nop                 = 0x96
-	DW_OP_push_object_address = 0x97
-	DW_OP_call2               = 0x98
-	DW_OP_call4               = 0x99
-	DW_OP_call_ref            = 0x9a
-	DW_OP_form_tls_address    = 0x9b
-	DW_OP_call_frame_cfa      = 0x9c
-	DW_OP_bit_piece           = 0x9d
+	DW_OP_addr                = 0x03 // 1 constant address (size target specific)
+	DW_OP_deref               = 0x06 // 0
+	DW_OP_const1u             = 0x08 // 1 1-byte constant
+	DW_OP_const1s             = 0x09 // 1 1-byte constant
+	DW_OP_const2u             = 0x0a // 1 2-byte constant
+	DW_OP_const2s             = 0x0b // 1 2-byte constant
+	DW_OP_const4u             = 0x0c // 1 4-byte constant
+	DW_OP_const4s             = 0x0d // 1 4-byte constant
+	DW_OP_const8u             = 0x0e // 1 8-byte constant
+	DW_OP_const8s             = 0x0f // 1 8-byte constant
+	DW_OP_constu              = 0x10 // 1 ULEB128 constant
+	DW_OP_consts              = 0x11 // 1 SLEB128 constant
+	DW_OP_dup                 = 0x12 // 0
+	DW_OP_drop                = 0x13 // 0
+	DW_OP_over                = 0x14 // 0
+	DW_OP_pick                = 0x15 // 1 1-byte stack index
+	DW_OP_swap                = 0x16 // 0
+	DW_OP_rot                 = 0x17 // 0
+	DW_OP_xderef              = 0x18 // 0
+	DW_OP_abs                 = 0x19 // 0
+	DW_OP_and                 = 0x1a // 0
+	DW_OP_div                 = 0x1b // 0
+	DW_OP_minus               = 0x1c // 0
+	DW_OP_mod                 = 0x1d // 0
+	DW_OP_mul                 = 0x1e // 0
+	DW_OP_neg                 = 0x1f // 0
+	DW_OP_not                 = 0x20 // 0
+	DW_OP_or                  = 0x21 // 0
+	DW_OP_plus                = 0x22 // 0
+	DW_OP_plus_uconst         = 0x23 // 1 ULEB128 addend
+	DW_OP_shl                 = 0x24 // 0
+	DW_OP_shr                 = 0x25 // 0
+	DW_OP_shra                = 0x26 // 0
+	DW_OP_xor                 = 0x27 // 0
+	DW_OP_skip                = 0x2f // 1 signed 2-byte constant
+	DW_OP_bra                 = 0x28 // 1 signed 2-byte constant
+	DW_OP_eq                  = 0x29 // 0
+	DW_OP_ge                  = 0x2a // 0
+	DW_OP_gt                  = 0x2b // 0
+	DW_OP_le                  = 0x2c // 0
+	DW_OP_lt                  = 0x2d // 0
+	DW_OP_ne                  = 0x2e // 0
+	DW_OP_lit0                = 0x30 // 0 ...
+	DW_OP_lit31               = 0x4f // 0 literals 0..31 = (DW_OP_lit0 + literal)
+	DW_OP_reg0                = 0x50 // 0 ..
+	DW_OP_reg31               = 0x6f // 0 reg 0..31 = (DW_OP_reg0 + regnum)
+	DW_OP_breg0               = 0x70 // 1 ...
+	DW_OP_breg31              = 0x8f // 1 SLEB128 offset base register 0..31 = (DW_OP_breg0 + regnum)
+	DW_OP_regx                = 0x90 // 1 ULEB128 register
+	DW_OP_fbreg               = 0x91 // 1 SLEB128 offset
+	DW_OP_bregx               = 0x92 // 2 ULEB128 register followed by SLEB128 offset
+	DW_OP_piece               = 0x93 // 1 ULEB128 size of piece addressed
+	DW_OP_deref_size          = 0x94 // 1 1-byte size of data retrieved
+	DW_OP_xderef_size         = 0x95 // 1 1-byte size of data retrieved
+	DW_OP_nop                 = 0x96 // 0
+	DW_OP_push_object_address = 0x97 // 0
+	DW_OP_call2               = 0x98 // 1 2-byte offset of DIE
+	DW_OP_call4               = 0x99 // 1 4-byte offset of DIE
+	DW_OP_call_ref            = 0x9a // 1 4- or 8-byte offset of DIE
+	DW_OP_form_tls_address    = 0x9b // 0
+	DW_OP_call_frame_cfa      = 0x9c // 0
+	DW_OP_bit_piece           = 0x9d // 2
 	DW_OP_lo_user             = 0xe0
 	DW_OP_hi_user             = 0xff
 )
@@ -371,16 +377,17 @@
 
 // Table 31
 const (
-	DW_LANG_C89            = 0x0001
-	DW_LANG_C              = 0x0002
-	DW_LANG_Ada83          = 0x0003
-	DW_LANG_C_plus_plus    = 0x0004
-	DW_LANG_Cobol74        = 0x0005
-	DW_LANG_Cobol85        = 0x0006
-	DW_LANG_Fortran77      = 0x0007
-	DW_LANG_Fortran90      = 0x0008
-	DW_LANG_Pascal83       = 0x0009
-	DW_LANG_Modula2        = 0x000a
+	DW_LANG_C89         = 0x0001
+	DW_LANG_C           = 0x0002
+	DW_LANG_Ada83       = 0x0003
+	DW_LANG_C_plus_plus = 0x0004
+	DW_LANG_Cobol74     = 0x0005
+	DW_LANG_Cobol85     = 0x0006
+	DW_LANG_Fortran77   = 0x0007
+	DW_LANG_Fortran90   = 0x0008
+	DW_LANG_Pascal83    = 0x0009
+	DW_LANG_Modula2     = 0x000a
+	// Dwarf3
 	DW_LANG_Java           = 0x000b
 	DW_LANG_C99            = 0x000c
 	DW_LANG_Ada95          = 0x000d
@@ -390,10 +397,13 @@
 	DW_LANG_ObjC_plus_plus = 0x0011
 	DW_LANG_UPC            = 0x0012
 	DW_LANG_D              = 0x0013
-	DW_LANG_Python         = 0x0014
-	DW_LANG_Go             = 0x0016
-	DW_LANG_lo_user        = 0x8000
-	DW_LANG_hi_user        = 0xffff
+	// Dwarf4
+	DW_LANG_Python = 0x0014
+	// Dwarf5
+	DW_LANG_Go = 0x0016
+
+	DW_LANG_lo_user = 0x8000
+	DW_LANG_hi_user = 0xffff
 )
 
 // Table 32
@@ -435,15 +445,16 @@
 
 // Table 37
 const (
-	DW_LNS_copy               = 0x01
-	DW_LNS_advance_pc         = 0x02
-	DW_LNS_advance_line       = 0x03
-	DW_LNS_set_file           = 0x04
-	DW_LNS_set_column         = 0x05
-	DW_LNS_negate_stmt        = 0x06
-	DW_LNS_set_basic_block    = 0x07
-	DW_LNS_const_add_pc       = 0x08
-	DW_LNS_fixed_advance_pc   = 0x09
+	DW_LNS_copy             = 0x01
+	DW_LNS_advance_pc       = 0x02
+	DW_LNS_advance_line     = 0x03
+	DW_LNS_set_file         = 0x04
+	DW_LNS_set_column       = 0x05
+	DW_LNS_negate_stmt      = 0x06
+	DW_LNS_set_basic_block  = 0x07
+	DW_LNS_const_add_pc     = 0x08
+	DW_LNS_fixed_advance_pc = 0x09
+	// Dwarf3
 	DW_LNS_set_prologue_end   = 0x0a
 	DW_LNS_set_epilogue_begin = 0x0b
 	DW_LNS_set_isa            = 0x0c
@@ -469,32 +480,37 @@
 
 // Table 40.
 const (
-	DW_CFA_nop                = 0x00
-	DW_CFA_set_loc            = 0x01
-	DW_CFA_advance_loc1       = 0x02
-	DW_CFA_advance_loc2       = 0x03
-	DW_CFA_advance_loc4       = 0x04
-	DW_CFA_offset_extended    = 0x05
-	DW_CFA_restore_extended   = 0x06
-	DW_CFA_undefined          = 0x07
-	DW_CFA_same_value         = 0x08
-	DW_CFA_register           = 0x09
-	DW_CFA_remember_state     = 0x0a
-	DW_CFA_restore_state      = 0x0b
-	DW_CFA_def_cfa            = 0x0c
-	DW_CFA_def_cfa_register   = 0x0d
-	DW_CFA_def_cfa_offset     = 0x0e
-	DW_CFA_def_cfa_expression = 0x0f
-	DW_CFA_expression         = 0x10
-	DW_CFA_offset_extended_sf = 0x11
-	DW_CFA_def_cfa_sf         = 0x12
-	DW_CFA_def_cfa_offset_sf  = 0x13
-	DW_CFA_val_offset         = 0x14
-	DW_CFA_val_offset_sf      = 0x15
-	DW_CFA_val_expression     = 0x16
-	DW_CFA_lo_user            = 0x1c
-	DW_CFA_hi_user            = 0x3f
-	DW_CFA_advance_loc        = 0x1 << 6
-	DW_CFA_offset             = 0x2 << 6
-	DW_CFA_restore            = 0x3 << 6
+	// operand,...
+	DW_CFA_nop              = 0x00
+	DW_CFA_set_loc          = 0x01 // address
+	DW_CFA_advance_loc1     = 0x02 // 1-byte delta
+	DW_CFA_advance_loc2     = 0x03 // 2-byte delta
+	DW_CFA_advance_loc4     = 0x04 // 4-byte delta
+	DW_CFA_offset_extended  = 0x05 // ULEB128 register, ULEB128 offset
+	DW_CFA_restore_extended = 0x06 // ULEB128 register
+	DW_CFA_undefined        = 0x07 // ULEB128 register
+	DW_CFA_same_value       = 0x08 // ULEB128 register
+	DW_CFA_register         = 0x09 // ULEB128 register, ULEB128 register
+	DW_CFA_remember_state   = 0x0a
+	DW_CFA_restore_state    = 0x0b
+
+	DW_CFA_def_cfa            = 0x0c // ULEB128 register, ULEB128 offset
+	DW_CFA_def_cfa_register   = 0x0d // ULEB128 register
+	DW_CFA_def_cfa_offset     = 0x0e // ULEB128 offset
+	DW_CFA_def_cfa_expression = 0x0f // BLOCK
+	DW_CFA_expression         = 0x10 // ULEB128 register, BLOCK
+	DW_CFA_offset_extended_sf = 0x11 // ULEB128 register, SLEB128 offset
+	DW_CFA_def_cfa_sf         = 0x12 // ULEB128 register, SLEB128 offset
+	DW_CFA_def_cfa_offset_sf  = 0x13 // SLEB128 offset
+	DW_CFA_val_offset         = 0x14 // ULEB128, ULEB128
+	DW_CFA_val_offset_sf      = 0x15 // ULEB128, SLEB128
+	DW_CFA_val_expression     = 0x16 // ULEB128, BLOCK
+
+	DW_CFA_lo_user = 0x1c
+	DW_CFA_hi_user = 0x3f
+
+	// Opcodes that take an addend operand.
+	DW_CFA_advance_loc = 0x1 << 6 // +delta
+	DW_CFA_offset      = 0x2 << 6 // +register (ULEB128 offset)
+	DW_CFA_restore     = 0x3 << 6 // +register
 )
diff --git a/src/cmd/internal/ld/elf.go b/src/cmd/internal/ld/elf.go
index ca95fe0..f2d819d 100644
--- a/src/cmd/internal/ld/elf.go
+++ b/src/cmd/internal/ld/elf.go
@@ -5,6 +5,7 @@
 package ld
 
 import (
+	"encoding/binary"
 	"fmt"
 	"os"
 )
@@ -163,6 +164,7 @@
 	EM_ST100             = 60
 	EM_TINYJ             = 61
 	EM_X86_64            = 62
+	EM_AARCH64           = 183
 	EM_486               = 6
 	EM_MIPS_RS4_BE       = 10
 	EM_ALPHA_STD         = 41
@@ -343,6 +345,9 @@
 	R_X86_64_GOTTPOFF      = 22
 	R_X86_64_TPOFF32       = 23
 	R_X86_64_COUNT         = 24
+	R_AARCH64_ABS64        = 257
+	R_AARCH64_ABS32        = 258
+	R_AARCH64_CALL26       = 283
 	R_ALPHA_NONE           = 0
 	R_ALPHA_REFLONG        = 1
 	R_ALPHA_REFQUAD        = 2
@@ -693,12 +698,6 @@
  * marshal a 32-bit representation from the 64-bit structure.
  */
 
-var numelfphdr int
-
-var numelfshdr int
-
-var elfstrsize int
-
 var Elfstrdat []byte
 
 /*
@@ -755,15 +754,14 @@
 	switch Thearch.Thechar {
 	// 64-bit architectures
 	case '9':
-		if Ctxt.Arch.Endian == BigEndian {
+		if Ctxt.Arch.ByteOrder == binary.BigEndian {
 			ehdr.flags = 1 /* Version 1 ABI */
 		} else {
 			ehdr.flags = 2 /* Version 2 ABI */
 		}
 		fallthrough
 
-		// fallthrough
-	case '6':
+	case '6', '7':
 		elf64 = 1
 
 		ehdr.phoff = ELF64HDRSIZE      /* Must be be ELF64HDRSIZE: first PHdr must follow ELF header */
@@ -775,6 +773,7 @@
 		// we use EABI on both linux/arm and freebsd/arm.
 	// 32-bit architectures
 	case '5':
+		// we use EABI on both linux/arm and freebsd/arm.
 		if HEADTYPE == Hlinux || HEADTYPE == Hfreebsd {
 			ehdr.flags = 0x5000002 // has entry point, Version5 EABI
 		}
@@ -803,13 +802,11 @@
 }
 
 func elf32phdr(e *ElfPhdr) {
-	var frag int
-
 	if e.type_ == PT_LOAD {
 		// Correct ELF loaders will do this implicitly,
 		// but buggy ELF loaders like the one in some
 		// versions of QEMU won't.
-		frag = int(e.vaddr & (e.align - 1))
+		frag := int(e.vaddr & (e.align - 1))
 
 		e.off -= uint64(frag)
 		e.vaddr -= uint64(frag)
@@ -855,16 +852,14 @@
 }
 
 func elfwriteshdrs() uint32 {
-	var i int
-
 	if elf64 != 0 {
-		for i = 0; i < int(ehdr.shnum); i++ {
+		for i := 0; i < int(ehdr.shnum); i++ {
 			elf64shdr(shdr[i])
 		}
 		return uint32(ehdr.shnum) * ELF64SHDRSIZE
 	}
 
-	for i = 0; i < int(ehdr.shnum); i++ {
+	for i := 0; i < int(ehdr.shnum); i++ {
 		elf32shdr(shdr[i])
 	}
 	return uint32(ehdr.shnum) * ELF32SHDRSIZE
@@ -882,25 +877,21 @@
 }
 
 func elfwritephdrs() uint32 {
-	var i int
-
 	if elf64 != 0 {
-		for i = 0; i < int(ehdr.phnum); i++ {
+		for i := 0; i < int(ehdr.phnum); i++ {
 			elf64phdr(phdr[i])
 		}
 		return uint32(ehdr.phnum) * ELF64PHDRSIZE
 	}
 
-	for i = 0; i < int(ehdr.phnum); i++ {
+	for i := 0; i < int(ehdr.phnum); i++ {
 		elf32phdr(phdr[i])
 	}
 	return uint32(ehdr.phnum) * ELF32PHDRSIZE
 }
 
 func newElfPhdr() *ElfPhdr {
-	var e *ElfPhdr
-
-	e = new(ElfPhdr)
+	e := new(ElfPhdr)
 	if ehdr.phnum >= NSECT {
 		Diag("too many phdrs")
 	} else {
@@ -916,9 +907,7 @@
 }
 
 func newElfShdr(name int64) *ElfShdr {
-	var e *ElfShdr
-
-	e = new(ElfShdr)
+	e := new(ElfShdr)
 	e.name = uint32(name)
 	e.shnum = int(ehdr.shnum)
 	if ehdr.shnum >= NSECT {
@@ -936,9 +925,7 @@
 }
 
 func elf64writehdr() uint32 {
-	var i int
-
-	for i = 0; i < EI_NIDENT; i++ {
+	for i := 0; i < EI_NIDENT; i++ {
 		Cput(ehdr.ident[i])
 	}
 	Thearch.Wput(ehdr.type_)
@@ -958,9 +945,7 @@
 }
 
 func elf32writehdr() uint32 {
-	var i int
-
-	for i = 0; i < EI_NIDENT; i++ {
+	for i := 0; i < EI_NIDENT; i++ {
 		Cput(ehdr.ident[i])
 	}
 	Thearch.Wput(ehdr.type_)
@@ -1036,10 +1021,8 @@
 }
 
 func elfinterp(sh *ElfShdr, startva uint64, resoff uint64, p string) int {
-	var n int
-
 	interp = p
-	n = len(interp) + 1
+	n := len(interp) + 1
 	sh.addr = startva + resoff - uint64(n)
 	sh.off = resoff - uint64(n)
 	sh.size = uint64(n)
@@ -1048,9 +1031,7 @@
 }
 
 func elfwriteinterp() int {
-	var sh *ElfShdr
-
-	sh = elfshname(".interp")
+	sh := elfshname(".interp")
 	Cseek(int64(sh.off))
 	coutbuf.w.WriteString(interp)
 	Cput(0)
@@ -1058,9 +1039,7 @@
 }
 
 func elfnote(sh *ElfShdr, startva uint64, resoff uint64, sz int) int {
-	var n uint64
-
-	n = 3*4 + uint64(sz) + resoff%4
+	n := 3*4 + uint64(sz) + resoff%4
 
 	sh.type_ = SHT_NOTE
 	sh.flags = SHF_ALLOC
@@ -1073,9 +1052,7 @@
 }
 
 func elfwritenotehdr(str string, namesz uint32, descsz uint32, tag uint32) *ElfShdr {
-	var sh *ElfShdr
-
-	sh = elfshname(str)
+	sh := elfshname(str)
 
 	// Write Elf_Note header.
 	Cseek(int64(sh.off))
@@ -1092,23 +1069,19 @@
 	ELF_NOTE_NETBSD_NAMESZ  = 7
 	ELF_NOTE_NETBSD_DESCSZ  = 4
 	ELF_NOTE_NETBSD_TAG     = 1
-	ELF_NOTE_NETBSD_VERSION = 599000000
+	ELF_NOTE_NETBSD_VERSION = 599000000 /* NetBSD 5.99 */
 )
 
 var ELF_NOTE_NETBSD_NAME = []byte("NetBSD\x00")
 
 func elfnetbsdsig(sh *ElfShdr, startva uint64, resoff uint64) int {
-	var n int
-
-	n = int(Rnd(ELF_NOTE_NETBSD_NAMESZ, 4) + Rnd(ELF_NOTE_NETBSD_DESCSZ, 4))
+	n := int(Rnd(ELF_NOTE_NETBSD_NAMESZ, 4) + Rnd(ELF_NOTE_NETBSD_DESCSZ, 4))
 	return elfnote(sh, startva, resoff, n)
 }
 
 func elfwritenetbsdsig() int {
-	var sh *ElfShdr
-
 	// Write Elf_Note header.
-	sh = elfwritenotehdr(".note.netbsd.ident", ELF_NOTE_NETBSD_NAMESZ, ELF_NOTE_NETBSD_DESCSZ, ELF_NOTE_NETBSD_TAG)
+	sh := elfwritenotehdr(".note.netbsd.ident", ELF_NOTE_NETBSD_NAMESZ, ELF_NOTE_NETBSD_DESCSZ, ELF_NOTE_NETBSD_TAG)
 
 	if sh == nil {
 		return 0
@@ -1134,17 +1107,13 @@
 var ELF_NOTE_OPENBSD_NAME = []byte("OpenBSD\x00")
 
 func elfopenbsdsig(sh *ElfShdr, startva uint64, resoff uint64) int {
-	var n int
-
-	n = ELF_NOTE_OPENBSD_NAMESZ + ELF_NOTE_OPENBSD_DESCSZ
+	n := ELF_NOTE_OPENBSD_NAMESZ + ELF_NOTE_OPENBSD_DESCSZ
 	return elfnote(sh, startva, resoff, n)
 }
 
 func elfwriteopenbsdsig() int {
-	var sh *ElfShdr
-
 	// Write Elf_Note header.
-	sh = elfwritenotehdr(".note.openbsd.ident", ELF_NOTE_OPENBSD_NAMESZ, ELF_NOTE_OPENBSD_DESCSZ, ELF_NOTE_OPENBSD_TAG)
+	sh := elfwritenotehdr(".note.openbsd.ident", ELF_NOTE_OPENBSD_NAMESZ, ELF_NOTE_OPENBSD_DESCSZ, ELF_NOTE_OPENBSD_TAG)
 
 	if sh == nil {
 		return 0
@@ -1159,9 +1128,6 @@
 }
 
 func addbuildinfo(val string) {
-	var ov string
-	var i int
-	var b int
 	var j int
 
 	if val[0] != '0' || val[1] != 'x' {
@@ -1169,9 +1135,10 @@
 		Exit(2)
 	}
 
-	ov = val
+	ov := val
 	val = val[2:]
-	i = 0
+	i := 0
+	var b int
 	for val != "" {
 		if len(val) == 1 {
 			fmt.Fprintf(os.Stderr, "%s: -B argument must have even number of digits: %s\n", os.Args[0], ov)
@@ -1179,7 +1146,7 @@
 		}
 
 		b = 0
-		for j = 0; j < 2; (func() { j++; val = val[1:] })() {
+		for j = 0; j < 2; j, val = j+1, val[1:] {
 			b *= 16
 			if val[0] >= '0' && val[0] <= '9' {
 				b += int(val[0]) - '0'
@@ -1215,16 +1182,12 @@
 var ELF_NOTE_BUILDINFO_NAME = []byte("GNU\x00")
 
 func elfbuildinfo(sh *ElfShdr, startva uint64, resoff uint64) int {
-	var n int
-
-	n = int(ELF_NOTE_BUILDINFO_NAMESZ + Rnd(int64(len(buildinfo)), 4))
+	n := int(ELF_NOTE_BUILDINFO_NAMESZ + Rnd(int64(len(buildinfo)), 4))
 	return elfnote(sh, startva, resoff, n)
 }
 
 func elfwritebuildinfo() int {
-	var sh *ElfShdr
-
-	sh = elfwritenotehdr(".note.gnu.build-id", ELF_NOTE_BUILDINFO_NAMESZ, uint32(len(buildinfo)), ELF_NOTE_BUILDINFO_TAG)
+	sh := elfwritenotehdr(".note.gnu.build-id", ELF_NOTE_BUILDINFO_NAMESZ, uint32(len(buildinfo)), ELF_NOTE_BUILDINFO_TAG)
 	if sh == nil {
 		return 0
 	}
@@ -1253,7 +1216,6 @@
 
 func addelflib(list **Elflib, file string, vers string) *Elfaux {
 	var lib *Elflib
-	var aux *Elfaux
 
 	for lib = *list; lib != nil; lib = lib.next {
 		if lib.file == file {
@@ -1266,75 +1228,59 @@
 	*list = lib
 
 havelib:
-	for aux = lib.aux; aux != nil; aux = aux.next {
+	for aux := lib.aux; aux != nil; aux = aux.next {
 		if aux.vers == vers {
-			goto haveaux
+			return aux
 		}
 	}
-	aux = new(Elfaux)
+	aux := new(Elfaux)
 	aux.next = lib.aux
 	aux.vers = vers
 	lib.aux = aux
 
-haveaux:
 	return aux
 }
 
 func elfdynhash() {
-	var s *LSym
-	var sy *LSym
-	var dynstr *LSym
-	var i int
-	var j int
-	var nbucket int
-	var b int
-	var nfile int
-	var hc uint32
-	var chain []uint32
-	var buckets []uint32
-	var nsym int
-	var name string
-	var need []*Elfaux
-	var needlib *Elflib
-	var l *Elflib
-	var x *Elfaux
-
 	if !Iself {
 		return
 	}
 
-	nsym = Nelfsym
-	s = Linklookup(Ctxt, ".hash", 0)
+	nsym := Nelfsym
+	s := Linklookup(Ctxt, ".hash", 0)
 	s.Type = SELFROSECT
 	s.Reachable = true
 
-	i = nsym
-	nbucket = 1
+	i := nsym
+	nbucket := 1
 	for i > 0 {
 		nbucket++
 		i >>= 1
 	}
 
-	needlib = nil
-	need = make([]*Elfaux, nsym)
-	chain = make([]uint32, nsym)
-	buckets = make([]uint32, nbucket)
+	var needlib *Elflib
+	need := make([]*Elfaux, nsym)
+	chain := make([]uint32, nsym)
+	buckets := make([]uint32, nbucket)
 	if need == nil || chain == nil || buckets == nil {
 		Ctxt.Cursym = nil
 		Diag("out of memory")
 		Errorexit()
 	}
 
-	for i = 0; i < nsym; i++ {
+	for i := 0; i < nsym; i++ {
 		need[i] = nil
 	}
-	for i = 0; i < nsym; i++ {
+	for i := 0; i < nsym; i++ {
 		chain[i] = 0
 	}
-	for i = 0; i < nbucket; i++ {
+	for i := 0; i < nbucket; i++ {
 		buckets[i] = 0
 	}
-	for sy = Ctxt.Allsym; sy != nil; sy = sy.Allsym {
+	var b int
+	var hc uint32
+	var name string
+	for sy := Ctxt.Allsym; sy != nil; sy = sy.Allsym {
 		if sy.Dynid <= 0 {
 			continue
 		}
@@ -1353,20 +1299,22 @@
 
 	Adduint32(Ctxt, s, uint32(nbucket))
 	Adduint32(Ctxt, s, uint32(nsym))
-	for i = 0; i < nbucket; i++ {
+	for i := 0; i < nbucket; i++ {
 		Adduint32(Ctxt, s, buckets[i])
 	}
-	for i = 0; i < nsym; i++ {
+	for i := 0; i < nsym; i++ {
 		Adduint32(Ctxt, s, chain[i])
 	}
 
 	// version symbols
-	dynstr = Linklookup(Ctxt, ".dynstr", 0)
+	dynstr := Linklookup(Ctxt, ".dynstr", 0)
 
 	s = Linklookup(Ctxt, ".gnu.version_r", 0)
 	i = 2
-	nfile = 0
-	for l = needlib; l != nil; l = l.next {
+	nfile := 0
+	var j int
+	var x *Elfaux
+	for l := needlib; l != nil; l = l.next {
 		nfile++
 
 		// header
@@ -1404,7 +1352,7 @@
 	// version references
 	s = Linklookup(Ctxt, ".gnu.version", 0)
 
-	for i = 0; i < nsym; i++ {
+	for i := 0; i < nsym; i++ {
 		if i == 0 {
 			Adduint16(Ctxt, s, 0) // first entry - no symbol
 		} else if need[i] == nil {
@@ -1422,15 +1370,16 @@
 		elfwritedynentsym(s, DT_VERSYM, Linklookup(Ctxt, ".gnu.version", 0))
 	}
 
-	if Thearch.Thechar == '6' || Thearch.Thechar == '9' {
-		sy = Linklookup(Ctxt, ".rela.plt", 0)
+	switch Thearch.Thechar {
+	case '6', '7', '9':
+		sy := Linklookup(Ctxt, ".rela.plt", 0)
 		if sy.Size > 0 {
 			Elfwritedynent(s, DT_PLTREL, DT_RELA)
 			elfwritedynentsymsize(s, DT_PLTRELSZ, sy)
 			elfwritedynentsym(s, DT_JMPREL, sy)
 		}
-	} else {
-		sy = Linklookup(Ctxt, ".rel.plt", 0)
+	default:
+		sy := Linklookup(Ctxt, ".rel.plt", 0)
 		if sy.Size > 0 {
 			Elfwritedynent(s, DT_PLTREL, DT_REL)
 			elfwritedynentsymsize(s, DT_PLTRELSZ, sy)
@@ -1442,9 +1391,7 @@
 }
 
 func elfphload(seg *Segment) *ElfPhdr {
-	var ph *ElfPhdr
-
-	ph = newElfPhdr()
+	ph := newElfPhdr()
 	ph.type_ = PT_LOAD
 	if seg.Rwx&4 != 0 {
 		ph.flags |= PF_R
@@ -1466,45 +1413,37 @@
 }
 
 func elfshname(name string) *ElfShdr {
-	var i int
 	var off int
 	var sh *ElfShdr
 
-	for i = 0; i < nelfstr; i++ {
+	for i := 0; i < nelfstr; i++ {
 		if name == elfstr[i].s {
 			off = elfstr[i].off
-			goto found
+			for i = 0; i < int(ehdr.shnum); i++ {
+				sh = shdr[i]
+				if sh.name == uint32(off) {
+					return sh
+				}
+			}
+
+			sh = newElfShdr(int64(off))
+			return sh
 		}
 	}
 
 	Diag("cannot find elf name %s", name)
 	Errorexit()
 	return nil
-
-found:
-	for i = 0; i < int(ehdr.shnum); i++ {
-		sh = shdr[i]
-		if sh.name == uint32(off) {
-			return sh
-		}
-	}
-
-	sh = newElfShdr(int64(off))
-	return sh
 }
 
 func elfshalloc(sect *Section) *ElfShdr {
-	var sh *ElfShdr
-
-	sh = elfshname(sect.Name)
+	sh := elfshname(sect.Name)
 	sect.Elfsect = sh
 	return sh
 }
 
 func elfshbits(sect *Section) *ElfShdr {
-	var sh *ElfShdr
-
-	sh = elfshalloc(sect)
+	sh := elfshalloc(sect)
 	if sh.type_ > 0 {
 		return sh
 	}
@@ -1539,11 +1478,6 @@
 }
 
 func elfshreloc(sect *Section) *ElfShdr {
-	var typ int
-	var sh *ElfShdr
-	var prefix string
-	var buf string
-
 	// If main section is SHT_NOBITS, nothing to relocate.
 	// Also nothing to relocate in .shstrtab.
 	if sect.Vaddr >= sect.Seg.Vaddr+sect.Seg.Filelen {
@@ -1553,6 +1487,8 @@
 		return nil
 	}
 
+	var prefix string
+	var typ int
 	if Thearch.Thechar == '6' || Thearch.Thechar == '9' {
 		prefix = ".rela"
 		typ = SHT_RELA
@@ -1561,8 +1497,8 @@
 		typ = SHT_REL
 	}
 
-	buf = fmt.Sprintf("%s%s", prefix, sect.Name)
-	sh = elfshname(buf)
+	buf := fmt.Sprintf("%s%s", prefix, sect.Name)
+	sh := elfshname(buf)
 	sh.type_ = uint32(typ)
 	sh.entsize = uint64(Thearch.Regsize) * 2
 	if typ == SHT_RELA {
@@ -1577,11 +1513,6 @@
 }
 
 func elfrelocsect(sect *Section, first *LSym) {
-	var ri int
-	var sym *LSym
-	var eaddr int32
-	var r *Reloc
-
 	// If main section is SHT_NOBITS, nothing to relocate.
 	// Also nothing to relocate in .shstrtab.
 	if sect.Vaddr >= sect.Seg.Vaddr+sect.Seg.Filelen {
@@ -1592,6 +1523,7 @@
 	}
 
 	sect.Reloff = uint64(Cpos())
+	var sym *LSym
 	for sym = first; sym != nil; sym = sym.Next {
 		if !sym.Reachable {
 			continue
@@ -1601,7 +1533,9 @@
 		}
 	}
 
-	eaddr = int32(sect.Vaddr + sect.Length)
+	eaddr := int32(sect.Vaddr + sect.Length)
+	var r *Reloc
+	var ri int
 	for ; sym != nil; sym = sym.Next {
 		if !sym.Reachable {
 			continue
@@ -1634,35 +1568,29 @@
 }
 
 func Elfemitreloc() {
-	var sect *Section
-
 	for Cpos()&7 != 0 {
 		Cput(0)
 	}
 
 	elfrelocsect(Segtext.Sect, Ctxt.Textp)
-	for sect = Segtext.Sect.Next; sect != nil; sect = sect.Next {
+	for sect := Segtext.Sect.Next; sect != nil; sect = sect.Next {
 		elfrelocsect(sect, datap)
 	}
-	for sect = Segrodata.Sect; sect != nil; sect = sect.Next {
+	for sect := Segrodata.Sect; sect != nil; sect = sect.Next {
 		elfrelocsect(sect, datap)
 	}
-	for sect = Segdata.Sect; sect != nil; sect = sect.Next {
+	for sect := Segdata.Sect; sect != nil; sect = sect.Next {
 		elfrelocsect(sect, datap)
 	}
 }
 
 func doelf() {
-	var s *LSym
-	var shstrtab *LSym
-	var dynstr *LSym
-
 	if !Iself {
 		return
 	}
 
 	/* predefine strings we need for section headers */
-	shstrtab = Linklookup(Ctxt, ".shstrtab", 0)
+	shstrtab := Linklookup(Ctxt, ".shstrtab", 0)
 
 	shstrtab.Type = SELFROSECT
 	shstrtab.Reachable = true
@@ -1703,7 +1631,8 @@
 		Debug['s'] = 0
 		Debug['d'] = 1
 
-		if Thearch.Thechar == '6' || Thearch.Thechar == '9' {
+		switch Thearch.Thechar {
+		case '6', '7', '9':
 			Addstring(shstrtab, ".rela.text")
 			Addstring(shstrtab, ".rela.rodata")
 			Addstring(shstrtab, ".rela.typelink")
@@ -1711,7 +1640,8 @@
 			Addstring(shstrtab, ".rela.gopclntab")
 			Addstring(shstrtab, ".rela.noptrdata")
 			Addstring(shstrtab, ".rela.data")
-		} else {
+
+		default:
 			Addstring(shstrtab, ".rel.text")
 			Addstring(shstrtab, ".rel.rodata")
 			Addstring(shstrtab, ".rel.typelink")
@@ -1742,7 +1672,7 @@
 
 	Addstring(shstrtab, ".shstrtab")
 
-	if Debug['d'] == 0 {
+	if Debug['d'] == 0 { /* -d suppresses dynamic loader format */
 		Addstring(shstrtab, ".interp")
 		Addstring(shstrtab, ".hash")
 		Addstring(shstrtab, ".got")
@@ -1766,7 +1696,7 @@
 		Addstring(shstrtab, ".gnu.version_r")
 
 		/* dynamic symbol table - first entry all zeros */
-		s = Linklookup(Ctxt, ".dynsym", 0)
+		s := Linklookup(Ctxt, ".dynsym", 0)
 
 		s.Type = SELFROSECT
 		s.Reachable = true
@@ -1784,12 +1714,13 @@
 		if s.Size == 0 {
 			Addstring(s, "")
 		}
-		dynstr = s
+		dynstr := s
 
 		/* relocation table */
-		if Thearch.Thechar == '6' || Thearch.Thechar == '9' {
+		switch Thearch.Thechar {
+		case '6', '7', '9':
 			s = Linklookup(Ctxt, ".rela", 0)
-		} else {
+		default:
 			s = Linklookup(Ctxt, ".rel", 0)
 		}
 		s.Reachable = true
@@ -1803,7 +1734,7 @@
 
 		/* ppc64 glink resolver */
 		if Thearch.Thechar == '9' {
-			s = Linklookup(Ctxt, ".glink", 0)
+			s := Linklookup(Ctxt, ".glink", 0)
 			s.Reachable = true
 			s.Type = SELFRXSECT
 		}
@@ -1831,9 +1762,10 @@
 
 		Thearch.Elfsetupplt()
 
-		if Thearch.Thechar == '6' || Thearch.Thechar == '9' {
+		switch Thearch.Thechar {
+		case '6', '7', '9':
 			s = Linklookup(Ctxt, ".rela.plt", 0)
-		} else {
+		default:
 			s = Linklookup(Ctxt, ".rel.plt", 0)
 		}
 		s.Reachable = true
@@ -1866,11 +1798,12 @@
 		}
 		elfwritedynentsym(s, DT_STRTAB, Linklookup(Ctxt, ".dynstr", 0))
 		elfwritedynentsymsize(s, DT_STRSZ, Linklookup(Ctxt, ".dynstr", 0))
-		if Thearch.Thechar == '6' || Thearch.Thechar == '9' {
+		switch Thearch.Thechar {
+		case '6', '7', '9':
 			elfwritedynentsym(s, DT_RELA, Linklookup(Ctxt, ".rela", 0))
 			elfwritedynentsymsize(s, DT_RELASZ, Linklookup(Ctxt, ".rela", 0))
 			Elfwritedynent(s, DT_RELAENT, ELF64RELASIZE)
-		} else {
+		default:
 			elfwritedynentsym(s, DT_REL, Linklookup(Ctxt, ".rel", 0))
 			elfwritedynentsymsize(s, DT_RELSZ, Linklookup(Ctxt, ".rel", 0))
 			Elfwritedynent(s, DT_RELENT, ELF32RELSIZE)
@@ -1900,8 +1833,7 @@
 
 // Do not write DT_NULL.  elfdynhash will finish it.
 func shsym(sh *ElfShdr, s *LSym) {
-	var addr int64
-	addr = Symaddr(s)
+	addr := Symaddr(s)
 	if sh.flags&SHF_ALLOC != 0 {
 		sh.addr = uint64(addr)
 	}
@@ -1919,35 +1851,22 @@
 }
 
 func Asmbelfsetup() {
-	var sect *Section
-
 	/* This null SHdr must appear before all others */
 	elfshname("")
 
-	for sect = Segtext.Sect; sect != nil; sect = sect.Next {
+	for sect := Segtext.Sect; sect != nil; sect = sect.Next {
 		elfshalloc(sect)
 	}
-	for sect = Segrodata.Sect; sect != nil; sect = sect.Next {
+	for sect := Segrodata.Sect; sect != nil; sect = sect.Next {
 		elfshalloc(sect)
 	}
-	for sect = Segdata.Sect; sect != nil; sect = sect.Next {
+	for sect := Segdata.Sect; sect != nil; sect = sect.Next {
 		elfshalloc(sect)
 	}
 }
 
 func Asmbelf(symo int64) {
-	var a int64
-	var o int64
-	var startva int64
-	var resoff int64
-	var eh *ElfEhdr
-	var ph *ElfPhdr
-	var pph *ElfPhdr
-	var pnote *ElfPhdr
-	var sh *ElfShdr
-	var sect *Section
-
-	eh = getElfEhdr()
+	eh := getElfEhdr()
 	switch Thearch.Thechar {
 	default:
 		Diag("unknown architecture in asmbelf")
@@ -1960,6 +1879,9 @@
 	case '6':
 		eh.machine = EM_X86_64
 
+	case '7':
+		eh.machine = EM_AARCH64
+
 	case '8':
 		eh.machine = EM_386
 
@@ -1967,10 +1889,11 @@
 		eh.machine = EM_PPC64
 	}
 
-	startva = INITTEXT - int64(HEADR)
-	resoff = ELFRESERVE
+	startva := INITTEXT - int64(HEADR)
+	resoff := int64(ELFRESERVE)
 
-	pph = nil
+	var pph *ElfPhdr
+	var pnote *ElfPhdr
 	if Linkmode == LinkExternal {
 		/* skip program headers */
 		eh.phoff = 0
@@ -1995,7 +1918,7 @@
 	 * Except on NaCl where it must not be loaded.
 	 */
 	if HEADTYPE != Hnacl {
-		o = int64(Segtext.Vaddr - pph.vaddr)
+		o := int64(Segtext.Vaddr - pph.vaddr)
 		Segtext.Vaddr -= uint64(o)
 		Segtext.Length += uint64(o)
 		o = int64(Segtext.Fileoff - pph.off)
@@ -2003,9 +1926,9 @@
 		Segtext.Filelen += uint64(o)
 	}
 
-	if Debug['d'] == 0 {
+	if Debug['d'] == 0 { /* -d suppresses dynamic loader format */
 		/* interpreter */
-		sh = elfshname(".interp")
+		sh := elfshname(".interp")
 
 		sh.type_ = SHT_PROGBITS
 		sh.flags = SHF_ALLOC
@@ -2034,7 +1957,7 @@
 
 		resoff -= int64(elfinterp(sh, uint64(startva), uint64(resoff), interpreter))
 
-		ph = newElfPhdr()
+		ph := newElfPhdr()
 		ph.type_ = PT_INTERP
 		ph.flags = PF_R
 		phsh(ph, sh)
@@ -2042,7 +1965,7 @@
 
 	pnote = nil
 	if HEADTYPE == Hnetbsd || HEADTYPE == Hopenbsd {
-		sh = nil
+		var sh *ElfShdr
 		switch HEADTYPE {
 		case Hnetbsd:
 			sh = elfshname(".note.netbsd.ident")
@@ -2060,7 +1983,7 @@
 	}
 
 	if len(buildinfo) > 0 {
-		sh = elfshname(".note.gnu.build-id")
+		sh := elfshname(".note.gnu.build-id")
 		resoff -= int64(elfbuildinfo(sh, uint64(startva), uint64(resoff)))
 
 		if pnote == nil {
@@ -2082,7 +2005,7 @@
 
 	/* Dynamic linking sections */
 	if Debug['d'] == 0 {
-		sh = elfshname(".dynsym")
+		sh := elfshname(".dynsym")
 		sh.type_ = SHT_DYNSYM
 		sh.flags = SHF_ALLOC
 		if elf64 != 0 {
@@ -2103,7 +2026,7 @@
 		shsym(sh, Linklookup(Ctxt, ".dynstr", 0))
 
 		if elfverneed != 0 {
-			sh = elfshname(".gnu.version")
+			sh := elfshname(".gnu.version")
 			sh.type_ = SHT_GNU_VERSYM
 			sh.flags = SHF_ALLOC
 			sh.addralign = 2
@@ -2121,9 +2044,8 @@
 		}
 
 		switch eh.machine {
-		case EM_X86_64,
-			EM_PPC64:
-			sh = elfshname(".rela.plt")
+		case EM_X86_64, EM_PPC64, EM_AARCH64:
+			sh := elfshname(".rela.plt")
 			sh.type_ = SHT_RELA
 			sh.flags = SHF_ALLOC
 			sh.entsize = ELF64RELASIZE
@@ -2141,7 +2063,7 @@
 			shsym(sh, Linklookup(Ctxt, ".rela", 0))
 
 		default:
-			sh = elfshname(".rel.plt")
+			sh := elfshname(".rel.plt")
 			sh.type_ = SHT_REL
 			sh.flags = SHF_ALLOC
 			sh.entsize = ELF32RELSIZE
@@ -2159,7 +2081,7 @@
 		}
 
 		if eh.machine == EM_PPC64 {
-			sh = elfshname(".glink")
+			sh := elfshname(".glink")
 			sh.type_ = SHT_PROGBITS
 			sh.flags = SHF_ALLOC + SHF_EXECINSTR
 			sh.addralign = 4
@@ -2187,7 +2109,7 @@
 		// On ppc64, .got comes from the input files, so don't
 		// create it here, and .got.plt is not used.
 		if eh.machine != EM_PPC64 {
-			sh = elfshname(".got")
+			sh := elfshname(".got")
 			sh.type_ = SHT_PROGBITS
 			sh.flags = SHF_ALLOC + SHF_WRITE
 			sh.entsize = uint64(Thearch.Regsize)
@@ -2219,7 +2141,7 @@
 		sh.addralign = uint64(Thearch.Regsize)
 		sh.link = uint32(elfshname(".dynstr").shnum)
 		shsym(sh, Linklookup(Ctxt, ".dynamic", 0))
-		ph = newElfPhdr()
+		ph := newElfPhdr()
 		ph.type_ = PT_DYNAMIC
 		ph.flags = PF_R + PF_W
 		phsh(ph, sh)
@@ -2231,7 +2153,7 @@
 		// not currently support it. This is handled
 		// appropriately in runtime/cgo.
 		if Ctxt.Tlsoffset != 0 && HEADTYPE != Hopenbsd {
-			ph = newElfPhdr()
+			ph := newElfPhdr()
 			ph.type_ = PT_TLS
 			ph.flags = PF_R
 			ph.memsz = uint64(-Ctxt.Tlsoffset)
@@ -2240,7 +2162,7 @@
 	}
 
 	if HEADTYPE == Hlinux {
-		ph = newElfPhdr()
+		ph := newElfPhdr()
 		ph.type_ = PT_GNU_STACK
 		ph.flags = PF_W + PF_R
 		ph.align = uint64(Thearch.Regsize)
@@ -2252,7 +2174,7 @@
 	}
 
 elfobj:
-	sh = elfshname(".shstrtab")
+	sh := elfshname(".shstrtab")
 	sh.type_ = SHT_STRTAB
 	sh.addralign = 1
 	shsym(sh, Linklookup(Ctxt, ".shstrtab", 0))
@@ -2264,29 +2186,29 @@
 		elfshname(".strtab")
 	}
 
-	for sect = Segtext.Sect; sect != nil; sect = sect.Next {
+	for sect := Segtext.Sect; sect != nil; sect = sect.Next {
 		elfshbits(sect)
 	}
-	for sect = Segrodata.Sect; sect != nil; sect = sect.Next {
+	for sect := Segrodata.Sect; sect != nil; sect = sect.Next {
 		elfshbits(sect)
 	}
-	for sect = Segdata.Sect; sect != nil; sect = sect.Next {
+	for sect := Segdata.Sect; sect != nil; sect = sect.Next {
 		elfshbits(sect)
 	}
 
 	if Linkmode == LinkExternal {
-		for sect = Segtext.Sect; sect != nil; sect = sect.Next {
+		for sect := Segtext.Sect; sect != nil; sect = sect.Next {
 			elfshreloc(sect)
 		}
-		for sect = Segrodata.Sect; sect != nil; sect = sect.Next {
+		for sect := Segrodata.Sect; sect != nil; sect = sect.Next {
 			elfshreloc(sect)
 		}
-		for sect = Segdata.Sect; sect != nil; sect = sect.Next {
+		for sect := Segdata.Sect; sect != nil; sect = sect.Next {
 			elfshreloc(sect)
 		}
 
 		// add a .note.GNU-stack section to mark the stack as non-executable
-		sh = elfshname(".note.GNU-stack")
+		sh := elfshname(".note.GNU-stack")
 
 		sh.type_ = SHT_PROGBITS
 		sh.addralign = 1
@@ -2296,7 +2218,7 @@
 	// generate .tbss section for dynamic internal linking (except for OpenBSD)
 	// external linking generates .tbss in data.c
 	if Linkmode == LinkInternal && Debug['d'] == 0 && HEADTYPE != Hopenbsd {
-		sh = elfshname(".tbss")
+		sh := elfshname(".tbss")
 		sh.type_ = SHT_NOBITS
 		sh.addralign = uint64(Thearch.Regsize)
 		sh.size = uint64(-Ctxt.Tlsoffset)
@@ -2304,7 +2226,7 @@
 	}
 
 	if Debug['s'] == 0 {
-		sh = elfshname(".symtab")
+		sh := elfshname(".symtab")
 		sh.type_ = SHT_SYMTAB
 		sh.off = uint64(symo)
 		sh.size = uint64(Symsize)
@@ -2342,7 +2264,7 @@
 	} else {
 		eh.ident[EI_CLASS] = ELFCLASS32
 	}
-	if Ctxt.Arch.Endian == BigEndian {
+	if Ctxt.Arch.ByteOrder == binary.BigEndian {
 		eh.ident[EI_DATA] = ELFDATA2MSB
 	} else {
 		eh.ident[EI_DATA] = ELFDATA2LSB
@@ -2367,7 +2289,7 @@
 	}
 
 	Cseek(0)
-	a = 0
+	a := int64(0)
 	a += int64(elfwritehdr())
 	a += int64(elfwritephdrs())
 	a += int64(elfwriteshdrs())
diff --git a/src/cmd/internal/ld/fmt.go b/src/cmd/internal/ld/fmt.go
deleted file mode 100644
index 86096e6..0000000
--- a/src/cmd/internal/ld/fmt.go
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * The authors of this software are Rob Pike and Ken Thompson.
- *              Copyright (c) 2002 by Lucent Technologies.
- * Permission to use, copy, modify, and distribute this software for any
- * purpose without fee is hereby granted, provided that this entire notice
- * is included in all copies of any software which is or includes a copy
- * or modification of this software and in all copies of the supporting
- * documentation for such software.
- * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
- * WARRANTY.  IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY
- * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
- * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
- */
-
-package ld
-
-// (The comments in this file were copied from the manpage files rune.3,
-// isalpharune.3, and runestrcat.3. Some formatting changes were also made
-// to conform to Google style. /JRM 11/11/05)
-
-type Fmt struct {
-	runes     uint8
-	start     interface{}
-	to        interface{}
-	stop      interface{}
-	flush     func(*Fmt) int
-	farg      interface{}
-	nfmt      int
-	args      []interface{}
-	r         uint
-	width     int
-	prec      int
-	flags     uint32
-	decimal   string
-	thousands string
-	grouping  string
-}
-
-const (
-	FmtWidth    = 1
-	FmtLeft     = FmtWidth << 1
-	FmtPrec     = FmtLeft << 1
-	FmtSharp    = FmtPrec << 1
-	FmtSpace    = FmtSharp << 1
-	FmtSign     = FmtSpace << 1
-	FmtApost    = FmtSign << 1
-	FmtZero     = FmtApost << 1
-	FmtUnsigned = FmtZero << 1
-	FmtShort    = FmtUnsigned << 1
-	FmtLong     = FmtShort << 1
-	FmtVLong    = FmtLong << 1
-	FmtComma    = FmtVLong << 1
-	FmtByte     = FmtComma << 1
-	FmtLDouble  = FmtByte << 1
-	FmtFlag     = FmtLDouble << 1
-)
-
-var fmtdoquote func(int) int
-
-/* Edit .+1,/^$/ | cfn $PLAN9/src/lib9/fmt/?*.c | grep -v static |grep -v __ */
diff --git a/src/cmd/internal/ld/go.go b/src/cmd/internal/ld/go.go
index cd85c8b..c50e82b 100644
--- a/src/cmd/internal/ld/go.go
+++ b/src/cmd/internal/ld/go.go
@@ -9,8 +9,8 @@
 	"cmd/internal/obj"
 	"fmt"
 	"os"
+	"strconv"
 	"strings"
-	"unicode/utf8"
 )
 
 // go-specific code shared across loaders (5l, 6l, 8l).
@@ -38,56 +38,27 @@
  *	package import data
  */
 type Import struct {
-	hash   *Import
-	prefix string
+	prefix string // "type", "var", "func", "const"
 	name   string
 	def    string
 	file   string
 }
 
-const (
-	NIHASH = 1024
-)
+// importmap records type information about imported symbols to detect inconsistencies.
+// Entries are keyed by qualified symbol name (e.g., "runtime.Callers" or "net/url.Error").
+var importmap = map[string]*Import{}
 
-var ihash [NIHASH]*Import
-
-var nimport int
-
-func hashstr(name string) int {
-	var h uint32
-	var cp string
-
-	h = 0
-	for cp = name; cp != ""; cp = cp[1:] {
-		h = h*1119 + uint32(cp[0])
+func lookupImport(name string) *Import {
+	if x, ok := importmap[name]; ok {
+		return x
 	}
-	h &= 0xffffff
-	return int(h)
-}
-
-func ilookup(name string) *Import {
-	var h int
-	var x *Import
-
-	h = hashstr(name) % NIHASH
-	for x = ihash[h]; x != nil; x = x.hash {
-		if x.name[0] == name[0] && x.name == name {
-			return x
-		}
-	}
-	x = new(Import)
-	x.name = name
-	x.hash = ihash[h]
-	ihash[h] = x
-	nimport++
+	x := &Import{name: name}
+	importmap[name] = x
 	return x
 }
 
 func ldpkg(f *Biobuf, pkg string, length int64, filename string, whence int) {
-	var bdata []byte
-	var data string
 	var p0, p1 int
-	var name string
 
 	if Debug['g'] != 0 {
 		return
@@ -101,7 +72,7 @@
 		return
 	}
 
-	bdata = make([]byte, length)
+	bdata := make([]byte, length)
 	if int64(Bread(f, bdata)) != length {
 		fmt.Fprintf(os.Stderr, "%s: short pkg read %s\n", os.Args[0], filename)
 		if Debug['u'] != 0 {
@@ -109,7 +80,7 @@
 		}
 		return
 	}
-	data = string(bdata)
+	data := string(bdata)
 
 	// first \n$$ marks beginning of exports - skip rest of line
 	p0 = strings.Index(data, "\n$$")
@@ -122,7 +93,7 @@
 	}
 
 	p0 += 3
-	for p0 < len(data) && data[0] != '\n' {
+	for p0 < len(data) && data[p0] != '\n' {
 		p0++
 	}
 
@@ -137,7 +108,7 @@
 	}
 	p1 += p0
 
-	for p0 < p1 && (data[p0] == ' ' || data[0] == '\t' || data[0] == '\n') {
+	for p0 < p1 && (data[p0] == ' ' || data[p0] == '\t' || data[p0] == '\n') {
 		p0++
 	}
 	if p0 < p1 {
@@ -153,7 +124,7 @@
 		for p0 < p1 && (data[p0] == ' ' || data[p0] == '\t' || data[p0] == '\n') {
 			p0++
 		}
-		name = data[p0:]
+		pname := p0
 		for p0 < p1 && data[p0] != ' ' && data[p0] != '\t' && data[p0] != '\n' {
 			p0++
 		}
@@ -163,16 +134,12 @@
 			Errorexit()
 		}
 
-		name = name[:p1-p0]
+		name := data[pname:p0]
+		for p0 < p1 && data[p0] != '\n' {
+			p0++
+		}
 		if p0 < p1 {
-			if data[p0] == '\n' {
-				p0++
-			} else {
-				p0++
-				for p0 < p1 && data[p0] != '\n' {
-					p0++
-				}
-			}
+			p0++
 		}
 
 		if pkg == "main" && name != "main" {
@@ -221,16 +188,13 @@
 }
 
 func loadpkgdata(file string, pkg string, data string) {
-	var p string
 	var prefix string
 	var name string
 	var def string
-	var x *Import
 
-	file = file
-	p = data
+	p := data
 	for parsepkgdata(file, pkg, &p, &prefix, &name, &def) > 0 {
-		x = ilookup(name)
+		x := lookupImport(name)
 		if x.prefix == "" {
 			x.prefix = prefix
 			x.def = def
@@ -250,15 +214,8 @@
 }
 
 func parsepkgdata(file string, pkg string, pp *string, prefixp *string, namep *string, defp *string) int {
-	var p string
-	var prefix string
-	var name string
-	var def string
-	var meth string
-	var inquote bool
-
 	// skip white space
-	p = *pp
+	p := *pp
 
 loop:
 	for len(p) > 0 && (p[0] == ' ' || p[0] == '\t' || p[0] == '\n') {
@@ -269,7 +226,7 @@
 	}
 
 	// prefix: (var|type|func|const)
-	prefix = p
+	prefix := p
 
 	if len(p) < 7 {
 		return -1
@@ -288,7 +245,7 @@
 			p = p[1:]
 		}
 		p = p[1:]
-		name := p
+		line := p
 		for len(p) > 0 && p[0] != '\n' {
 			p = p[1:]
 		}
@@ -297,9 +254,16 @@
 			nerrors++
 			return -1
 		}
-		name = name[:len(name)-len(p)]
+		line = line[:len(line)-len(p)]
+		line = strings.TrimSuffix(line, " // indirect")
+		path, err := strconv.Unquote(line)
+		if err != nil {
+			fmt.Fprintf(os.Stderr, "%s: %s: confused in import path: %q\n", os.Args[0], file, line)
+			nerrors++
+			return -1
+		}
 		p = p[1:]
-		imported(pkg, name)
+		imported(pkg, path)
 		goto loop
 	} else {
 		fmt.Fprintf(os.Stderr, "%s: %s: confused in pkg data near <<%.40s>>\n", os.Args[0], file, prefix)
@@ -310,9 +274,9 @@
 	prefix = prefix[:len(prefix)-len(p)-1]
 
 	// name: a.b followed by space
-	name = p
+	name := p
 
-	inquote = false
+	inquote := false
 	for len(p) > 0 {
 		if p[0] == ' ' && !inquote {
 			break
@@ -334,7 +298,7 @@
 	p = p[1:]
 
 	// def: free form to new line
-	def = p
+	def := p
 
 	for len(p) > 0 && p[0] != '\n' {
 		p = p[1:]
@@ -347,6 +311,7 @@
 	p = p[1:]
 
 	// include methods on successive lines in def of named type
+	var meth string
 	for parsemethod(&p, &meth) > 0 {
 		if defbuf == nil {
 			defbuf = new(bytes.Buffer)
@@ -372,10 +337,8 @@
 }
 
 func parsemethod(pp *string, methp *string) int {
-	var p string
-
 	// skip white space
-	p = *pp
+	p := *pp
 
 	for len(p) > 0 && (p[0] == ' ' || p[0] == '\t') {
 		p = p[1:]
@@ -415,7 +378,6 @@
 
 func loadcgo(file string, pkg string, p string) {
 	var next string
-	var p0 string
 	var q string
 	var f []string
 	var local string
@@ -423,7 +385,7 @@
 	var lib string
 	var s *LSym
 
-	p0 = ""
+	p0 := ""
 	for ; p != ""; p = next {
 		if i := strings.Index(p, "\n"); i >= 0 {
 			p, next = p[:i], p[i+1:]
@@ -500,11 +462,6 @@
 		}
 
 		if f[0] == "cgo_export_static" || f[0] == "cgo_export_dynamic" {
-			// TODO: Remove once we know Windows is okay.
-			if f[0] == "cgo_export_static" && HEADTYPE == Hwindows {
-				continue
-			}
-
 			if len(f) < 2 || len(f) > 3 {
 				goto err
 			}
@@ -610,10 +567,9 @@
 
 func markflood() {
 	var a *Auto
-	var s *LSym
 	var i int
 
-	for s = markq; s != nil; s = s.Queue {
+	for s := markq; s != nil; s = s.Queue {
 		if s.Type == STEXT {
 			if Debug['v'] > 1 {
 				fmt.Fprintf(&Bso, "marktext %s\n", s.Name)
@@ -659,38 +615,32 @@
 }
 
 func deadcode() {
-	var i int
-	var s *LSym
-	var last *LSym
-	var p *LSym
-	var fmt_ string
-
 	if Debug['v'] != 0 {
 		fmt.Fprintf(&Bso, "%5.2f deadcode\n", obj.Cputime())
 	}
 
 	mark(Linklookup(Ctxt, INITENTRY, 0))
-	for i = 0; i < len(markextra); i++ {
+	for i := 0; i < len(markextra); i++ {
 		mark(Linklookup(Ctxt, markextra[i], 0))
 	}
 
-	for i = 0; i < len(dynexp); i++ {
+	for i := 0; i < len(dynexp); i++ {
 		mark(dynexp[i])
 	}
 
 	markflood()
 
 	// keep each beginning with 'typelink.' if the symbol it points at is being kept.
-	for s = Ctxt.Allsym; s != nil; s = s.Allsym {
+	for s := Ctxt.Allsym; s != nil; s = s.Allsym {
 		if strings.HasPrefix(s.Name, "go.typelink.") {
 			s.Reachable = len(s.R) == 1 && s.R[0].Sym.Reachable
 		}
 	}
 
 	// remove dead text but keep file information (z symbols).
-	last = nil
+	var last *LSym
 
-	for s = Ctxt.Textp; s != nil; s = s.Next {
+	for s := Ctxt.Textp; s != nil; s = s.Next {
 		if !s.Reachable {
 			continue
 		}
@@ -710,7 +660,7 @@
 		last.Next = nil
 	}
 
-	for s = Ctxt.Allsym; s != nil; s = s.Allsym {
+	for s := Ctxt.Allsym; s != nil; s = s.Allsym {
 		if strings.HasPrefix(s.Name, "go.weak.") {
 			s.Special = 1 // do not lay out in data segment
 			s.Reachable = true
@@ -719,18 +669,19 @@
 	}
 
 	// record field tracking references
-	fmt_ = ""
-
-	for s = Ctxt.Allsym; s != nil; s = s.Allsym {
+	var buf bytes.Buffer
+	var p *LSym
+	for s := Ctxt.Allsym; s != nil; s = s.Allsym {
 		if strings.HasPrefix(s.Name, "go.track.") {
 			s.Special = 1 // do not lay out in data segment
 			s.Hide = 1
 			if s.Reachable {
-				fmt_ += fmt.Sprintf("%s", s.Name[9:])
+				buf.WriteString(s.Name[9:])
 				for p = s.Reachparent; p != nil; p = p.Reachparent {
-					fmt_ += fmt.Sprintf("\t%s", p.Name)
+					buf.WriteString("\t")
+					buf.WriteString(p.Name)
 				}
-				fmt_ += fmt.Sprintf("\n")
+				buf.WriteString("\n")
 			}
 
 			s.Type = SCONST
@@ -741,20 +692,19 @@
 	if tracksym == "" {
 		return
 	}
-	s = Linklookup(Ctxt, tracksym, 0)
+	s := Linklookup(Ctxt, tracksym, 0)
 	if !s.Reachable {
 		return
 	}
-	addstrdata(tracksym, fmt_)
+	addstrdata(tracksym, buf.String())
 }
 
 func doweak() {
-	var s *LSym
 	var t *LSym
 
 	// resolve weak references only if
 	// target symbol will be in binary anyway.
-	for s = Ctxt.Allsym; s != nil; s = s.Allsym {
+	for s := Ctxt.Allsym; s != nil; s = s.Allsym {
 		if strings.HasPrefix(s.Name, "go.weak.") {
 			t = Linkrlookup(Ctxt, s.Name[8:], int(s.Version))
 			if t != nil && t.Type != 0 && t.Reachable {
@@ -772,129 +722,70 @@
 }
 
 func addexport() {
-	var i int
-
 	if HEADTYPE == Hdarwin {
 		return
 	}
 
-	for i = 0; i < len(dynexp); i++ {
+	for i := 0; i < len(dynexp); i++ {
 		Thearch.Adddynsym(Ctxt, dynexp[i])
 	}
 }
 
-/* %Z from gc, for quoting import paths */
-func Zconv(s string, flag int) string {
-	// NOTE: Keep in sync with gc Zconv.
-	var n int
-	var fp string
-	for i := 0; i < len(s); i += n {
-		var r rune
-		r, n = utf8.DecodeRuneInString(s[i:])
-		switch r {
-		case utf8.RuneError:
-			if n == 1 {
-				fp += fmt.Sprintf("\\x%02x", s[i])
-				break
-			}
-			fallthrough
-
-			// fall through
-		default:
-			if r < ' ' {
-				fp += fmt.Sprintf("\\x%02x", r)
-				break
-			}
-
-			fp += string(r)
-
-		case '\t':
-			fp += "\\t"
-
-		case '\n':
-			fp += "\\n"
-
-		case '"',
-			'\\':
-			fp += `\` + string(r)
-
-		case 0xFEFF: // BOM, basically disallowed in source code
-			fp += "\\uFEFF"
-		}
-	}
-
-	return fp
-}
-
 type Pkg struct {
-	mark    uint8
-	checked uint8
-	next    *Pkg
-	path_   string
+	mark    bool
+	checked bool
+	path    string
 	impby   []*Pkg
-	all     *Pkg
 }
 
-var phash [1024]*Pkg
+var (
+	// pkgmap records the imported-by relationship between packages.
+	// Entries are keyed by package path (e.g., "runtime" or "net/url").
+	pkgmap = map[string]*Pkg{}
 
-var pkgall *Pkg
+	pkgall []*Pkg
+)
 
-func getpkg(path_ string) *Pkg {
-	var p *Pkg
-	var h int
-
-	h = hashstr(path_) % len(phash)
-	for p = phash[h]; p != nil; p = p.next {
-		if p.path_ == path_ {
-			return p
-		}
+func lookupPkg(path string) *Pkg {
+	if p, ok := pkgmap[path]; ok {
+		return p
 	}
-	p = new(Pkg)
-	p.path_ = path_
-	p.next = phash[h]
-	phash[h] = p
-	p.all = pkgall
-	pkgall = p
+	p := &Pkg{path: path}
+	pkgmap[path] = p
+	pkgall = append(pkgall, p)
 	return p
 }
 
-func imported(pkg string, import_ string) {
-	var p *Pkg
-	var i *Pkg
-
+// imported records that package pkg imports package imp.
+func imported(pkg, imp string) {
 	// everyone imports runtime, even runtime.
-	if import_ == "\"runtime\"" {
+	if imp == "runtime" {
 		return
 	}
 
-	pkg = fmt.Sprintf("\"%v\"", Zconv(pkg, 0)) // turn pkg path into quoted form, freed below
-	p = getpkg(pkg)
-	i = getpkg(import_)
+	p := lookupPkg(pkg)
+	i := lookupPkg(imp)
 	i.impby = append(i.impby, p)
 }
 
-func cycle(p *Pkg) *Pkg {
-	var i int
-	var bad *Pkg
-
-	if p.checked != 0 {
+func (p *Pkg) cycle() *Pkg {
+	if p.checked {
 		return nil
 	}
 
-	if p.mark != 0 {
+	if p.mark {
 		nerrors++
 		fmt.Printf("import cycle:\n")
-		fmt.Printf("\t%s\n", p.path_)
+		fmt.Printf("\t%s\n", p.path)
 		return p
 	}
 
-	p.mark = 1
-	for i = 0; i < len(p.impby); i++ {
-		bad = cycle(p.impby[i])
-		if bad != nil {
-			p.mark = 0
-			p.checked = 1
-			fmt.Printf("\timports %s\n", p.path_)
+	p.mark = true
+	for _, q := range p.impby {
+		if bad := q.cycle(); bad != nil {
+			p.mark = false
+			p.checked = true
+			fmt.Printf("\timports %s\n", p.path)
 			if bad == p {
 				return nil
 			}
@@ -902,16 +793,14 @@
 		}
 	}
 
-	p.checked = 1
-	p.mark = 0
+	p.checked = true
+	p.mark = false
 	return nil
 }
 
 func importcycles() {
-	var p *Pkg
-
-	for p = pkgall; p != nil; p = p.all {
-		cycle(p)
+	for _, p := range pkgall {
+		p.cycle()
 	}
 }
 
diff --git a/src/cmd/internal/ld/ld.go b/src/cmd/internal/ld/ld.go
index 99f2fab..a0f1f32 100644
--- a/src/cmd/internal/ld/ld.go
+++ b/src/cmd/internal/ld/ld.go
@@ -86,10 +86,7 @@
  *	pkg: package import path, e.g. container/vector
  */
 func addlibpath(ctxt *Link, srcref string, objref string, file string, pkg string) {
-	var i int
-	var l *Library
-
-	for i = 0; i < len(ctxt.Library); i++ {
+	for i := 0; i < len(ctxt.Library); i++ {
 		if file == ctxt.Library[i].File {
 			return
 		}
@@ -100,23 +97,13 @@
 	}
 
 	ctxt.Library = append(ctxt.Library, Library{})
-	l = &ctxt.Library[len(ctxt.Library)-1]
+	l := &ctxt.Library[len(ctxt.Library)-1]
 	l.Objref = objref
 	l.Srcref = srcref
 	l.File = file
 	l.Pkg = pkg
 }
 
-var fnuxi8 [8]uint8
-
-var fnuxi4 [4]uint8
-
-var inuxi1 [1]uint8
-
-var inuxi2 [2]uint8
-
-var inuxi8 [8]uint8
-
 func atolwhex(s string) int64 {
 	n, _ := strconv.ParseInt(s, 0, 64)
 	return n
diff --git a/src/cmd/internal/ld/ldelf.go b/src/cmd/internal/ld/ldelf.go
index c50e995..beb62b7 100644
--- a/src/cmd/internal/ld/ldelf.go
+++ b/src/cmd/internal/ld/ldelf.go
@@ -37,94 +37,125 @@
 THE SOFTWARE.
 */
 const (
-	ElfClassNone = 0 + iota
-	ElfClass32
-	ElfClass64
-	ElfDataNone = 0 + iota - 3
-	ElfDataLsb
-	ElfDataMsb
-	ElfTypeNone = 0 + iota - 6
-	ElfTypeRelocatable
-	ElfTypeExecutable
-	ElfTypeSharedObject
-	ElfTypeCore
-	ElfMachNone = 0 + iota - 11
-	ElfMach32100
-	ElfMachSparc
-	ElfMach386
-	ElfMach68000
-	ElfMach88000
-	ElfMach486
-	ElfMach860
-	ElfMachMips
-	ElfMachS370
-	ElfMachMipsLe
-	ElfMachParisc = 15
-	ElfMachVpp500 = 17 + iota - 23
-	ElfMachSparc32Plus
-	ElfMach960
-	ElfMachPower
-	ElfMachPower64
-	ElfMachS390
-	ElfMachV800 = 36 + iota - 29
-	ElfMachFr20
-	ElfMachRh32
-	ElfMachRce
-	ElfMachArm
-	ElfMachAlpha
-	ElfMachSH
-	ElfMachSparc9
-	ElfMachAmd64  = 62
-	ElfAbiNone    = 0
-	ElfAbiSystemV = 0 + iota - 39
-	ElfAbiHPUX
-	ElfAbiNetBSD
-	ElfAbiLinux
-	ElfAbiSolaris = 6 + iota - 43
-	ElfAbiAix
-	ElfAbiIrix
-	ElfAbiFreeBSD
-	ElfAbiTru64
-	ElfAbiModesto
-	ElfAbiOpenBSD
+	ElfClassNone = 0
+	ElfClass32   = 1
+	ElfClass64   = 2
+)
+
+const (
+	ElfDataNone = 0
+	ElfDataLsb  = 1
+	ElfDataMsb  = 2
+)
+
+const (
+	ElfTypeNone         = 0
+	ElfTypeRelocatable  = 1
+	ElfTypeExecutable   = 2
+	ElfTypeSharedObject = 3
+	ElfTypeCore         = 4
+)
+
+const (
+	ElfMachNone        = 0
+	ElfMach32100       = 1
+	ElfMachSparc       = 2
+	ElfMach386         = 3
+	ElfMach68000       = 4
+	ElfMach88000       = 5
+	ElfMach486         = 6
+	ElfMach860         = 7
+	ElfMachMips        = 8
+	ElfMachS370        = 9
+	ElfMachMipsLe      = 10
+	ElfMachParisc      = 15
+	ElfMachVpp500      = 17
+	ElfMachSparc32Plus = 18
+	ElfMach960         = 19
+	ElfMachPower       = 20
+	ElfMachPower64     = 21
+	ElfMachS390        = 22
+	ElfMachV800        = 36
+	ElfMachFr20        = 37
+	ElfMachRh32        = 38
+	ElfMachRce         = 39
+	ElfMachArm         = 40
+	ElfMachAlpha       = 41
+	ElfMachSH          = 42
+	ElfMachSparc9      = 43
+	ElfMachAmd64       = 62
+	ElfMachArm64       = 183
+)
+
+const (
+	ElfAbiNone     = 0
+	ElfAbiSystemV  = 0
+	ElfAbiHPUX     = 1
+	ElfAbiNetBSD   = 2
+	ElfAbiLinux    = 3
+	ElfAbiSolaris  = 6
+	ElfAbiAix      = 7
+	ElfAbiIrix     = 8
+	ElfAbiFreeBSD  = 9
+	ElfAbiTru64    = 10
+	ElfAbiModesto  = 11
+	ElfAbiOpenBSD  = 12
 	ElfAbiARM      = 97
 	ElfAbiEmbedded = 255
-	ElfSectNone    = 0 + iota - 52
-	ElfSectProgbits
-	ElfSectSymtab
-	ElfSectStrtab
-	ElfSectRela
-	ElfSectHash
-	ElfSectDynamic
-	ElfSectNote
-	ElfSectNobits
-	ElfSectRel
-	ElfSectShlib
-	ElfSectDynsym
+)
+
+const (
+	ElfSectNone      = 0
+	ElfSectProgbits  = 1
+	ElfSectSymtab    = 2
+	ElfSectStrtab    = 3
+	ElfSectRela      = 4
+	ElfSectHash      = 5
+	ElfSectDynamic   = 6
+	ElfSectNote      = 7
+	ElfSectNobits    = 8
+	ElfSectRel       = 9
+	ElfSectShlib     = 10
+	ElfSectDynsym    = 11
 	ElfSectFlagWrite = 0x1
 	ElfSectFlagAlloc = 0x2
 	ElfSectFlagExec  = 0x4
-	ElfSymBindLocal  = 0 + iota - 67
-	ElfSymBindGlobal
-	ElfSymBindWeak
-	ElfSymTypeNone = 0 + iota - 70
-	ElfSymTypeObject
-	ElfSymTypeFunc
-	ElfSymTypeSection
-	ElfSymTypeFile
+)
+
+const (
+	ElfSymBindLocal  = 0
+	ElfSymBindGlobal = 1
+	ElfSymBindWeak   = 2
+)
+
+const (
+	ElfSymTypeNone    = 0
+	ElfSymTypeObject  = 1
+	ElfSymTypeFunc    = 2
+	ElfSymTypeSection = 3
+	ElfSymTypeFile    = 4
+)
+
+const (
 	ElfSymShnNone   = 0
 	ElfSymShnAbs    = 0xFFF1
 	ElfSymShnCommon = 0xFFF2
-	ElfProgNone     = 0 + iota - 78
-	ElfProgLoad
-	ElfProgDynamic
-	ElfProgInterp
-	ElfProgNote
-	ElfProgShlib
-	ElfProgPhdr
-	ElfProgFlagExec     = 0x1
-	ElfProgFlagWrite    = 0x2
-	ElfProgFlagRead     = 0x4
+)
+
+const (
+	ElfProgNone      = 0
+	ElfProgLoad      = 1
+	ElfProgDynamic   = 2
+	ElfProgInterp    = 3
+	ElfProgNote      = 4
+	ElfProgShlib     = 5
+	ElfProgPhdr      = 6
+	ElfProgFlagExec  = 0x1
+	ElfProgFlagWrite = 0x2
+	ElfProgFlagRead  = 0x4
+)
+
+const (
 	ElfNotePrStatus     = 1
 	ElfNotePrFpreg      = 2
 	ElfNotePrPsinfo     = 3
@@ -235,8 +266,8 @@
 
 type ElfObj struct {
 	f         *Biobuf
-	base      int64
-	length    int64
+	base      int64 // offset in f where ELF begins
+	length    int64 // length of ELF
 	is64      int
 	name      string
 	e         binary.ByteOrder
@@ -285,39 +316,34 @@
 }
 
 func ldelf(f *Biobuf, pkg string, length int64, pn string) {
-	var err error
-	var base int32
-	var add uint64
-	var info uint64
-	var name string
-	var i int
-	var j int
-	var rela int
-	var is64 int
-	var n int
-	var flag int
-	var hdrbuf [64]uint8
-	var p []byte
-	var hdr *ElfHdrBytes
-	var elfobj *ElfObj
-	var sect *ElfSect
-	var rsect *ElfSect
-	var sym ElfSym
-	var e binary.ByteOrder
-	var r []Reloc
-	var rp *Reloc
-	var s *LSym
-	var symbols []*LSym
-
-	symbols = nil
-
 	if Debug['v'] != 0 {
 		fmt.Fprintf(&Bso, "%5.2f ldelf %s\n", obj.Cputime(), pn)
 	}
 
 	Ctxt.Version++
-	base = int32(Boffset(f))
+	base := int32(Boffset(f))
 
+	var add uint64
+	var e binary.ByteOrder
+	var elfobj *ElfObj
+	var err error
+	var flag int
+	var hdr *ElfHdrBytes
+	var hdrbuf [64]uint8
+	var info uint64
+	var is64 int
+	var j int
+	var n int
+	var name string
+	var p []byte
+	var r []Reloc
+	var rela int
+	var rp *Reloc
+	var rsect *ElfSect
+	var s *LSym
+	var sect *ElfSect
+	var sym ElfSym
+	var symbols []*LSym
 	if Bread(f, hdrbuf[:]) != len(hdrbuf) {
 		goto bad
 	}
@@ -348,10 +374,8 @@
 
 	is64 = 0
 	if hdr.Ident[4] == ElfClass64 {
-		var hdr *ElfHdrBytes64
-
 		is64 = 1
-		hdr = new(ElfHdrBytes64)
+		hdr := new(ElfHdrBytes64)
 		binary.Read(bytes.NewReader(hdrbuf[:]), binary.BigEndian, hdr) // only byte arrays; byte order doesn't matter
 		elfobj.type_ = uint32(e.Uint16(hdr.Type[:]))
 		elfobj.machine = uint32(e.Uint16(hdr.Machine[:]))
@@ -409,6 +433,12 @@
 			return
 		}
 
+	case '7':
+		if e != binary.LittleEndian || elfobj.machine != ElfMachArm64 || hdr.Ident[4] != ElfClass64 {
+			Diag("%s: elf object but not arm64", pn)
+			return
+		}
+
 	case '8':
 		if e != binary.LittleEndian || elfobj.machine != ElfMach386 || hdr.Ident[4] != ElfClass32 {
 			Diag("%s: elf object but not 386", pn)
@@ -426,7 +456,7 @@
 	elfobj.sect = make([]ElfSect, elfobj.shnum)
 
 	elfobj.nsect = uint(elfobj.shnum)
-	for i = 0; uint(i) < elfobj.nsect; i++ {
+	for i := 0; uint(i) < elfobj.nsect; i++ {
 		if Bseek(f, int64(uint64(base)+elfobj.shoff+uint64(int64(i)*int64(elfobj.shentsize))), 0) < 0 {
 			goto bad
 		}
@@ -478,7 +508,7 @@
 	if err = elfmap(elfobj, sect); err != nil {
 		goto bad
 	}
-	for i = 0; uint(i) < elfobj.nsect; i++ {
+	for i := 0; uint(i) < elfobj.nsect; i++ {
 		if elfobj.sect[i].nameoff != 0 {
 			elfobj.sect[i].name = cstring(sect.base[elfobj.sect[i].nameoff:])
 		}
@@ -517,7 +547,7 @@
 	// as well use one large chunk.
 
 	// create symbols for elfmapped sections
-	for i = 0; uint(i) < elfobj.nsect; i++ {
+	for i := 0; uint(i) < elfobj.nsect; i++ {
 		sect = &elfobj.sect[i]
 		if (sect.type_ != ElfSectProgbits && sect.type_ != ElfSectNobits) || sect.flags&ElfSectFlagAlloc == 0 {
 			continue
@@ -572,7 +602,7 @@
 		Errorexit()
 	}
 
-	for i = 1; i < elfobj.nsymtab; i++ {
+	for i := 1; i < elfobj.nsymtab; i++ {
 		if err = readelfsym(elfobj, i, &sym, 1); err != nil {
 			goto bad
 		}
@@ -601,7 +631,7 @@
 		}
 		sect = &elfobj.sect[sym.shndx:][0]
 		if sect.sym == nil {
-			if strings.HasPrefix(sym.name, ".Linfo_string") {
+			if strings.HasPrefix(sym.name, ".Linfo_string") { // clang does this
 				continue
 			}
 			Diag("%s: sym#%d: ignoring %s in section %d (type %d)", pn, i, sym.name, sym.shndx, sym.type_)
@@ -645,7 +675,7 @@
 
 	// Sort outer lists by address, adding to textp.
 	// This keeps textp in increasing address order.
-	for i = 0; uint(i) < elfobj.nsect; i++ {
+	for i := 0; uint(i) < elfobj.nsect; i++ {
 		s = elfobj.sect[i].sym
 		if s == nil {
 			continue
@@ -676,7 +706,7 @@
 	}
 
 	// load relocations
-	for i = 0; uint(i) < elfobj.nsect; i++ {
+	for i := 0; uint(i) < elfobj.nsect; i++ {
 		rsect = &elfobj.sect[i]
 		if rsect.type_ != ElfSectRela && rsect.type_ != ElfSectRel {
 			continue
@@ -782,9 +812,7 @@
 }
 
 func section(elfobj *ElfObj, name string) *ElfSect {
-	var i int
-
-	for i = 0; uint(i) < elfobj.nsect; i++ {
+	for i := 0; uint(i) < elfobj.nsect; i++ {
 		if elfobj.sect[i].name != "" && name != "" && elfobj.sect[i].name == name {
 			return &elfobj.sect[i]
 		}
@@ -812,8 +840,6 @@
 }
 
 func readelfsym(elfobj *ElfObj, i int, sym *ElfSym, needSym int) (err error) {
-	var s *LSym
-
 	if i >= elfobj.nsymtab || i < 0 {
 		err = fmt.Errorf("invalid elf symbol index")
 		return err
@@ -845,7 +871,7 @@
 		sym.other = b.Other
 	}
 
-	s = nil
+	var s *LSym
 	if sym.name == "_GLOBAL_OFFSET_TABLE_" {
 		sym.name = ".got"
 	}
@@ -859,9 +885,7 @@
 	case ElfSymTypeSection:
 		s = elfobj.sect[sym.shndx].sym
 
-	case ElfSymTypeObject,
-		ElfSymTypeFunc,
-		ElfSymTypeNone:
+	case ElfSymTypeObject, ElfSymTypeFunc, ElfSymTypeNone:
 		switch sym.bind {
 		case ElfSymBindGlobal:
 			if needSym != 0 {
@@ -882,7 +906,7 @@
 
 		case ElfSymBindLocal:
 			if Thearch.Thechar == '5' && (strings.HasPrefix(sym.name, "$a") || strings.HasPrefix(sym.name, "$d")) {
-				// binutils for arm generate these elfmapping
+				// binutils for arm generate these mapping
 				// symbols, ignore these
 				break
 			}
@@ -940,11 +964,8 @@
 }
 
 func (x rbyoff) Less(i, j int) bool {
-	var a *Reloc
-	var b *Reloc
-
-	a = &x[i]
-	b = &x[j]
+	a := &x[i]
+	b := &x[j]
 	if a.Off < b.Off {
 		return true
 	}
diff --git a/src/cmd/internal/ld/ldmacho.go b/src/cmd/internal/ld/ldmacho.go
index e762318..9ed4093 100644
--- a/src/cmd/internal/ld/ldmacho.go
+++ b/src/cmd/internal/ld/ldmacho.go
@@ -41,8 +41,8 @@
 
 type LdMachoObj struct {
 	f          *Biobuf
-	base       int64
-	length     int64
+	base       int64 // off in f where Mach-O begins
+	length     int64 // length of Mach-O
 	is64       bool
 	name       string
 	e          binary.ByteOrder
@@ -172,13 +172,8 @@
 )
 
 func unpackcmd(p []byte, m *LdMachoObj, c *LdMachoCmd, type_ uint, sz uint) int {
-	var e4 func([]byte) uint32
-	var e8 func([]byte) uint64
-	var s *LdMachoSect
-	var i int
-
-	e4 = m.e.Uint32
-	e8 = m.e.Uint64
+	e4 := m.e.Uint32
+	e8 := m.e.Uint64
 
 	c.type_ = int(type_)
 	c.size = uint32(sz)
@@ -204,7 +199,8 @@
 			return -1
 		}
 		p = p[56:]
-		for i = 0; uint32(i) < c.seg.nsect; i++ {
+		var s *LdMachoSect
+		for i := 0; uint32(i) < c.seg.nsect; i++ {
 			s = &c.seg.sect[i]
 			s.name = cstring(p[0:16])
 			s.segname = cstring(p[16:32])
@@ -238,7 +234,8 @@
 			return -1
 		}
 		p = p[72:]
-		for i = 0; uint32(i) < c.seg.nsect; i++ {
+		var s *LdMachoSect
+		for i := 0; uint32(i) < c.seg.nsect; i++ {
 			s = &c.seg.sect[i]
 			s.name = cstring(p[0:16])
 			s.segname = cstring(p[16:32])
@@ -293,24 +290,19 @@
 }
 
 func macholoadrel(m *LdMachoObj, sect *LdMachoSect) int {
-	var rel []LdMachoRel
-	var r *LdMachoRel
-	var buf []byte
-	var p []byte
-	var i int
-	var n int
-	var v uint32
-
 	if sect.rel != nil || sect.nreloc == 0 {
 		return 0
 	}
-	rel = make([]LdMachoRel, sect.nreloc)
-	n = int(sect.nreloc * 8)
-	buf = make([]byte, n)
+	rel := make([]LdMachoRel, sect.nreloc)
+	n := int(sect.nreloc * 8)
+	buf := make([]byte, n)
 	if Bseek(m.f, m.base+int64(sect.reloff), 0) < 0 || Bread(m.f, buf) != n {
 		return -1
 	}
-	for i = 0; uint32(i) < sect.nreloc; i++ {
+	var p []byte
+	var r *LdMachoRel
+	var v uint32
+	for i := 0; uint32(i) < sect.nreloc; i++ {
 		r = &rel[i]
 		p = buf[i*8:]
 		r.addr = m.e.Uint32(p)
@@ -347,56 +339,44 @@
 }
 
 func macholoaddsym(m *LdMachoObj, d *LdMachoDysymtab) int {
-	var p []byte
-	var i int
-	var n int
+	n := int(d.nindirectsyms)
 
-	n = int(d.nindirectsyms)
-
-	p = make([]byte, n*4)
+	p := make([]byte, n*4)
 	if Bseek(m.f, m.base+int64(d.indirectsymoff), 0) < 0 || Bread(m.f, p) != len(p) {
 		return -1
 	}
 
 	d.indir = make([]uint32, n)
-	for i = 0; i < n; i++ {
+	for i := 0; i < n; i++ {
 		d.indir[i] = m.e.Uint32(p[4*i:])
 	}
 	return 0
 }
 
 func macholoadsym(m *LdMachoObj, symtab *LdMachoSymtab) int {
-	var strbuf []byte
-	var symbuf []byte
-	var p []byte
-	var i int
-	var n int
-	var symsize int
-	var sym []LdMachoSym
-	var s *LdMachoSym
-	var v uint32
-
 	if symtab.sym != nil {
 		return 0
 	}
 
-	strbuf = make([]byte, symtab.strsize)
+	strbuf := make([]byte, symtab.strsize)
 	if Bseek(m.f, m.base+int64(symtab.stroff), 0) < 0 || Bread(m.f, strbuf) != len(strbuf) {
 		return -1
 	}
 
-	symsize = 12
+	symsize := 12
 	if m.is64 {
 		symsize = 16
 	}
-	n = int(symtab.nsym * uint32(symsize))
-	symbuf = make([]byte, n)
+	n := int(symtab.nsym * uint32(symsize))
+	symbuf := make([]byte, n)
 	if Bseek(m.f, m.base+int64(symtab.symoff), 0) < 0 || Bread(m.f, symbuf) != len(symbuf) {
 		return -1
 	}
-	sym = make([]LdMachoSym, symtab.nsym)
-	p = symbuf
-	for i = 0; uint32(i) < symtab.nsym; i++ {
+	sym := make([]LdMachoSym, symtab.nsym)
+	p := symbuf
+	var s *LdMachoSym
+	var v uint32
+	for i := 0; uint32(i) < symtab.nsym; i++ {
 		s = &sym[i]
 		v = m.e.Uint32(p)
 		if v >= symtab.strsize {
@@ -421,13 +401,11 @@
 
 func ldmacho(f *Biobuf, pkg string, length int64, pn string) {
 	var err error
-	var i int
 	var j int
 	var is64 bool
 	var secaddr uint64
 	var hdr [7 * 4]uint8
 	var cmdp []byte
-	var tmp [4]uint8
 	var dat []byte
 	var ncmd uint32
 	var cmdsz uint32
@@ -436,7 +414,6 @@
 	var off uint32
 	var m *LdMachoObj
 	var e binary.ByteOrder
-	var base int64
 	var sect *LdMachoSect
 	var rel *LdMachoRel
 	var rpi int
@@ -452,7 +429,7 @@
 	var name string
 
 	Ctxt.Version++
-	base = Boffset(f)
+	base := Boffset(f)
 	if Bread(f, hdr[:]) != len(hdr) {
 		goto bad
 	}
@@ -475,6 +452,7 @@
 	}
 
 	if is64 {
+		var tmp [4]uint8
 		Bread(f, tmp[:4]) // skip reserved word in header
 	}
 
@@ -524,7 +502,7 @@
 	symtab = nil
 	dsymtab = nil
 
-	for i = 0; uint32(i) < ncmd; i++ {
+	for i := 0; uint32(i) < ncmd; i++ {
 		ty = e.Uint32(cmdp)
 		sz = e.Uint32(cmdp[4:])
 		m.cmd[i].off = off
@@ -581,7 +559,7 @@
 		goto bad
 	}
 
-	for i = 0; uint32(i) < c.seg.nsect; i++ {
+	for i := 0; uint32(i) < c.seg.nsect; i++ {
 		sect = &c.seg.sect[i]
 		if sect.segname != "__TEXT" && sect.segname != "__DATA" {
 			continue
@@ -623,8 +601,7 @@
 
 	// enter sub-symbols into symbol table.
 	// have to guess sizes from next symbol.
-	for i = 0; uint32(i) < symtab.nsym; i++ {
-		var v int
+	for i := 0; uint32(i) < symtab.nsym; i++ {
 		sym = &symtab.sym[i]
 		if sym.type_&N_STAB != 0 {
 			continue
@@ -636,7 +613,7 @@
 		if name[0] == '_' && name[1] != '\x00' {
 			name = name[1:]
 		}
-		v = 0
+		v := 0
 		if sym.type_&N_EXT == 0 {
 			v = Ctxt.Version
 		}
@@ -688,7 +665,7 @@
 
 	// Sort outer lists by address, adding to textp.
 	// This keeps textp in increasing address order.
-	for i = 0; uint32(i) < c.seg.nsect; i++ {
+	for i := 0; uint32(i) < c.seg.nsect; i++ {
 		sect = &c.seg.sect[i]
 		s = sect.sym
 		if s == nil {
@@ -730,7 +707,7 @@
 	}
 
 	// load relocations
-	for i = 0; uint32(i) < c.seg.nsect; i++ {
+	for i := 0; uint32(i) < c.seg.nsect; i++ {
 		sect = &c.seg.sect[i]
 		s = sect.sym
 		if s == nil {
@@ -742,13 +719,11 @@
 		}
 		r = make([]Reloc, sect.nreloc)
 		rpi = 0
+	Reloc:
 		for j = 0; uint32(j) < sect.nreloc; j++ {
 			rp = &r[rpi]
 			rel = &sect.rel[j]
 			if rel.scattered != 0 {
-				var k int
-				var ks *LdMachoSect
-
 				if Thearch.Thechar != '8' {
 					// mach-o only uses scattered relocation on 32-bit platforms
 					Diag("unexpected scattered relocation")
@@ -792,54 +767,53 @@
 
 				// now consider the desired symbol.
 				// find the section where it lives.
-				for k = 0; uint32(k) < c.seg.nsect; k++ {
+				var ks *LdMachoSect
+				for k := 0; uint32(k) < c.seg.nsect; k++ {
 					ks = &c.seg.sect[k]
 					if ks.addr <= uint64(rel.value) && uint64(rel.value) < ks.addr+ks.size {
-						goto foundk
+						if ks.sym != nil {
+							rp.Sym = ks.sym
+							rp.Add += int64(uint64(rel.value) - ks.addr)
+						} else if ks.segname == "__IMPORT" && ks.name == "__pointers" {
+							// handle reference to __IMPORT/__pointers.
+							// how much worse can this get?
+							// why are we supporting 386 on the mac anyway?
+							rp.Type = 512 + MACHO_FAKE_GOTPCREL
+
+							// figure out which pointer this is a reference to.
+							k = int(uint64(ks.res1) + (uint64(rel.value)-ks.addr)/4)
+
+							// load indirect table for __pointers
+							// fetch symbol number
+							if dsymtab == nil || k < 0 || uint32(k) >= dsymtab.nindirectsyms || dsymtab.indir == nil {
+								err = fmt.Errorf("invalid scattered relocation: indirect symbol reference out of range")
+								goto bad
+							}
+
+							k = int(dsymtab.indir[k])
+							if k < 0 || uint32(k) >= symtab.nsym {
+								err = fmt.Errorf("invalid scattered relocation: symbol reference out of range")
+								goto bad
+							}
+
+							rp.Sym = symtab.sym[k].sym
+						} else {
+							err = fmt.Errorf("unsupported scattered relocation: reference to %s/%s", ks.segname, ks.name)
+							goto bad
+						}
+
+						rpi++
+
+						// skip #1 of 2 rel; continue skips #2 of 2.
+						j++
+
+						continue Reloc
 					}
 				}
 
 				err = fmt.Errorf("unsupported scattered relocation: invalid address %#x", rel.addr)
 				goto bad
 
-			foundk:
-				if ks.sym != nil {
-					rp.Sym = ks.sym
-					rp.Add += int64(uint64(rel.value) - ks.addr)
-				} else if ks.segname == "__IMPORT" && ks.name == "__pointers" {
-					// handle reference to __IMPORT/__pointers.
-					// how much worse can this get?
-					// why are we supporting 386 on the mac anyway?
-					rp.Type = 512 + MACHO_FAKE_GOTPCREL
-
-					// figure out which pointer this is a reference to.
-					k = int(uint64(ks.res1) + (uint64(rel.value)-ks.addr)/4)
-
-					// load indirect table for __pointers
-					// fetch symbol number
-					if dsymtab == nil || k < 0 || uint32(k) >= dsymtab.nindirectsyms || dsymtab.indir == nil {
-						err = fmt.Errorf("invalid scattered relocation: indirect symbol reference out of range")
-						goto bad
-					}
-
-					k = int(dsymtab.indir[k])
-					if k < 0 || uint32(k) >= symtab.nsym {
-						err = fmt.Errorf("invalid scattered relocation: symbol reference out of range")
-						goto bad
-					}
-
-					rp.Sym = symtab.sym[k].sym
-				} else {
-					err = fmt.Errorf("unsupported scattered relocation: reference to %s/%s", ks.segname, ks.name)
-					goto bad
-				}
-
-				rpi++
-
-				// skip #1 of 2 rel; continue skips #2 of 2.
-				j++
-
-				continue
 			}
 
 			rp.Siz = rel.length
diff --git a/src/cmd/internal/ld/ldpe.go b/src/cmd/internal/ld/ldpe.go
index 247e829..e124d81 100644
--- a/src/cmd/internal/ld/ldpe.go
+++ b/src/cmd/internal/ld/ldpe.go
@@ -58,7 +58,7 @@
 	IMAGE_SYM_CLASS_MEMBER_OF_ENUM   = 16
 	IMAGE_SYM_CLASS_REGISTER_PARAM   = 17
 	IMAGE_SYM_CLASS_BIT_FIELD        = 18
-	IMAGE_SYM_CLASS_FAR_EXTERNAL     = 68
+	IMAGE_SYM_CLASS_FAR_EXTERNAL     = 68 /* Not in PECOFF v8 spec */
 	IMAGE_SYM_CLASS_BLOCK            = 100
 	IMAGE_SYM_CLASS_FUNCTION         = 101
 	IMAGE_SYM_CLASS_END_OF_STRUCT    = 102
@@ -127,36 +127,31 @@
 }
 
 func ldpe(f *Biobuf, pkg string, length int64, pn string) {
-	var err error
-	var name string
-	var base int32
-	var l uint32
-	var i int
-	var j int
-	var numaux int
-	var peobj *PeObj
-	var sect *PeSect
-	var rsect *PeSect
-	var symbuf [18]uint8
-	var s *LSym
-	var r []Reloc
-	var rp *Reloc
-	var sym *PeSym
-
 	if Debug['v'] != 0 {
 		fmt.Fprintf(&Bso, "%5.2f ldpe %s\n", obj.Cputime(), pn)
 	}
 
-	sect = nil
+	var sect *PeSect
 	Ctxt.Version++
-	base = int32(Boffset(f))
+	base := int32(Boffset(f))
 
-	peobj = new(PeObj)
+	peobj := new(PeObj)
 	peobj.f = f
 	peobj.base = uint32(base)
 	peobj.name = pn
 
 	// read header
+	var err error
+	var j int
+	var l uint32
+	var name string
+	var numaux int
+	var r []Reloc
+	var rp *Reloc
+	var rsect *PeSect
+	var s *LSym
+	var sym *PeSym
+	var symbuf [18]uint8
 	if err = binary.Read(f, binary.LittleEndian, &peobj.fh); err != nil {
 		goto bad
 	}
@@ -165,7 +160,7 @@
 	peobj.sect = make([]PeSect, peobj.fh.NumberOfSections)
 
 	peobj.nsect = uint(peobj.fh.NumberOfSections)
-	for i = 0; i < int(peobj.fh.NumberOfSections); i++ {
+	for i := 0; i < int(peobj.fh.NumberOfSections); i++ {
 		if err = binary.Read(f, binary.LittleEndian, &peobj.sect[i].sh); err != nil {
 			goto bad
 		}
@@ -189,7 +184,7 @@
 	}
 
 	// rewrite section names if they start with /
-	for i = 0; i < int(peobj.fh.NumberOfSections); i++ {
+	for i := 0; i < int(peobj.fh.NumberOfSections); i++ {
 		if peobj.sect[i].name == "" {
 			continue
 		}
@@ -205,7 +200,7 @@
 
 	peobj.npesym = uint(peobj.fh.NumberOfSymbols)
 	Bseek(f, int64(base)+int64(peobj.fh.PointerToSymbolTable), 0)
-	for i = 0; uint32(i) < peobj.fh.NumberOfSymbols; i += numaux + 1 {
+	for i := 0; uint32(i) < peobj.fh.NumberOfSymbols; i += numaux + 1 {
 		Bseek(f, int64(base)+int64(peobj.fh.PointerToSymbolTable)+int64(len(symbuf))*int64(i), 0)
 		if Bread(f, symbuf[:]) != len(symbuf) {
 			goto bad
@@ -230,7 +225,7 @@
 	}
 
 	// create symbols for mapped sections
-	for i = 0; uint(i) < peobj.nsect; i++ {
+	for i := 0; uint(i) < peobj.nsect; i++ {
 		sect = &peobj.sect[i]
 		if sect.sh.Characteristics&IMAGE_SCN_MEM_DISCARDABLE != 0 {
 			continue
@@ -277,7 +272,7 @@
 	}
 
 	// load relocations
-	for i = 0; uint(i) < peobj.nsect; i++ {
+	for i := 0; uint(i) < peobj.nsect; i++ {
 		rsect = &peobj.sect[i]
 		if rsect.sym == nil || rsect.sh.NumberOfRelocations == 0 {
 			continue
@@ -298,12 +293,9 @@
 			if Bread(f, symbuf[:10]) != 10 {
 				goto bad
 			}
-			var rva uint32
-			var symindex uint32
-			var type_ uint16
-			rva = Le32(symbuf[0:])
-			symindex = Le32(symbuf[4:])
-			type_ = Le16(symbuf[8:])
+			rva := Le32(symbuf[0:])
+			symindex := Le32(symbuf[4:])
+			type_ := Le16(symbuf[8:])
 			if err = readpesym(peobj, int(symindex), &sym); err != nil {
 				goto bad
 			}
@@ -320,16 +312,14 @@
 				Diag("%s: unknown relocation type %d;", pn, type_)
 				fallthrough
 
-			case IMAGE_REL_I386_REL32,
-				IMAGE_REL_AMD64_REL32,
+			case IMAGE_REL_I386_REL32, IMAGE_REL_AMD64_REL32,
 				IMAGE_REL_AMD64_ADDR32, // R_X86_64_PC32
 				IMAGE_REL_AMD64_ADDR32NB:
 				rp.Type = R_PCREL
 
 				rp.Add = int64(int32(Le32(rsect.base[rp.Off:])))
 
-			case IMAGE_REL_I386_DIR32NB,
-				IMAGE_REL_I386_DIR32:
+			case IMAGE_REL_I386_DIR32NB, IMAGE_REL_I386_DIR32:
 				rp.Type = R_ADDR
 
 				// load addend from image
@@ -360,7 +350,7 @@
 	}
 
 	// enter sub-symbols into symbol table.
-	for i = 0; uint(i) < peobj.npesym; i++ {
+	for i := 0; uint(i) < peobj.npesym; i++ {
 		if peobj.pesym[i].name == "" {
 			continue
 		}
@@ -429,7 +419,7 @@
 
 	// Sort outer lists by address, adding to textp.
 	// This keeps textp in increasing address order.
-	for i = 0; uint(i) < peobj.nsect; i++ {
+	for i := 0; uint(i) < peobj.nsect; i++ {
 		s = peobj.sect[i].sym
 		if s == nil {
 			continue
@@ -486,18 +476,15 @@
 }
 
 func readpesym(peobj *PeObj, i int, y **PeSym) (err error) {
-	var s *LSym
-	var sym *PeSym
-	var name string
-
 	if uint(i) >= peobj.npesym || i < 0 {
 		err = fmt.Errorf("invalid pe symbol index")
 		return err
 	}
 
-	sym = &peobj.pesym[i]
+	sym := &peobj.pesym[i]
 	*y = sym
 
+	var name string
 	if issect(sym) {
 		name = peobj.sect[sym.sectnum-1].sym.Name
 	} else {
@@ -515,20 +502,18 @@
 		name = name[:i]
 	}
 
+	var s *LSym
 	switch sym.type_ {
 	default:
 		err = fmt.Errorf("%s: invalid symbol type %d", sym.name, sym.type_)
 		return err
 
-	case IMAGE_SYM_DTYPE_FUNCTION,
-		IMAGE_SYM_DTYPE_NULL:
+	case IMAGE_SYM_DTYPE_FUNCTION, IMAGE_SYM_DTYPE_NULL:
 		switch sym.sclass {
 		case IMAGE_SYM_CLASS_EXTERNAL: //global
 			s = Linklookup(Ctxt, name, 0)
 
-		case IMAGE_SYM_CLASS_NULL,
-			IMAGE_SYM_CLASS_STATIC,
-			IMAGE_SYM_CLASS_LABEL:
+		case IMAGE_SYM_CLASS_NULL, IMAGE_SYM_CLASS_STATIC, IMAGE_SYM_CLASS_LABEL:
 			s = Linklookup(Ctxt, name, Ctxt.Version)
 			s.Dupok = 1
 
diff --git a/src/cmd/internal/ld/lib.go b/src/cmd/internal/ld/lib.go
index bc58fff..e4b1820 100644
--- a/src/cmd/internal/ld/lib.go
+++ b/src/cmd/internal/ld/lib.go
@@ -99,28 +99,21 @@
 	Elfsetupplt      func()
 	Gentext          func()
 	Machoreloc1      func(*Reloc, int64) int
+	PEreloc1         func(*Reloc, int64) bool
 	Lput             func(uint32)
 	Wput             func(uint16)
 	Vput             func(uint64)
 }
 
-var Thearch Arch
-
-var datap *LSym
-
-var Debug [128]int
-
-var literal string
-
-var Lcsize int32
-
-var rpath string
-
-var Spsize int32
-
-var symlist *LSym
-
-var Symsize int32
+var (
+	Thearch Arch
+	datap   *LSym
+	Debug   [128]int
+	Lcsize  int32
+	rpath   string
+	Spsize  int32
+	Symsize int32
+)
 
 // Terrible but standard terminology.
 // A segment describes a block of file to load into memory.
@@ -129,15 +122,15 @@
 
 const (
 	MAXIO   = 8192
-	MINFUNC = 16
+	MINFUNC = 16 // minimum size for a function
 )
 
 type Segment struct {
-	Rwx     uint8
-	Vaddr   uint64
-	Length  uint64
-	Fileoff uint64
-	Filelen uint64
+	Rwx     uint8  // permission as usual unix bits (5 = r-x etc)
+	Vaddr   uint64 // virtual address
+	Length  uint64 // length in memory
+	Fileoff uint64 // file offset
+	Filelen uint64 // length on disk
 	Sect    *Section
 }
 
@@ -155,65 +148,36 @@
 	Rellen  uint64
 }
 
-var Thestring string
-
-var Thelinkarch *LinkArch
-
-var outfile string
-
-var ndynexp int
-
-var dynexp []*LSym
-
-var nldflag int
-
-var ldflag []string
-
-var havedynamic int
-
-var Funcalign int
-
-var iscgo bool
-
-var elfglobalsymndx int
-
-var flag_installsuffix string
-
-var flag_race int
-
-var Flag_shared int
-
-var tracksym string
-
-var interpreter string
-
-var tmpdir string
-
-var extld string
-
-var extldflags string
-
-var debug_s int // backup old value of debug['s']
-
-var Ctxt *Link
-
-var HEADR int32
-
-var HEADTYPE int32
-
-var INITRND int32
-
-var INITTEXT int64
-
-var INITDAT int64
-
-var INITENTRY string /* entry point */
-
-var nerrors int
-
-var Linkmode int
-
-var liveness int64
+var (
+	Thestring          string
+	Thelinkarch        *LinkArch
+	outfile            string
+	dynexp             []*LSym
+	ldflag             []string
+	havedynamic        int
+	Funcalign          int
+	iscgo              bool
+	elfglobalsymndx    int
+	flag_installsuffix string
+	flag_race          int
+	Flag_shared        int
+	tracksym           string
+	interpreter        string
+	tmpdir             string
+	extld              string
+	extldflags         string
+	debug_s            int // backup old value of debug['s']
+	Ctxt               *Link
+	HEADR              int32
+	HEADTYPE           int32
+	INITRND            int32
+	INITTEXT           int64
+	INITDAT            int64
+	INITENTRY          string /* entry point */
+	nerrors            int
+	Linkmode           int
+	liveness           int64
+)
 
 // for dynexport field of LSym
 const (
@@ -221,19 +185,12 @@
 	CgoExportStatic  = 1 << 1
 )
 
-var Segtext Segment
-
-var Segrodata Segment
-
-var Segdata Segment
-
-var Segdwarf Segment
-
-type Endian struct {
-	e16 func([]byte) uint16
-	e32 func([]byte) uint32
-	e64 func([]byte) uint64
-}
+var (
+	Segtext   Segment
+	Segrodata Segment
+	Segdata   Segment
+	Segdwarf  Segment
+)
 
 /* set by call to mywhatsys() */
 
@@ -244,37 +201,34 @@
 	Pkgdef
 )
 
-var headstring string
-
-// buffered output
-
-var Bso Biobuf
-
-var coutbuf Biobuf
+var (
+	headstring string
+	// buffered output
+	Bso     Biobuf
+	coutbuf Biobuf
+)
 
 const (
+	// Whether to assume that the external linker is "gold"
+	// (http://sourceware.org/ml/binutils/2008-03/msg00162.html).
 	AssumeGoldLinker = 0
 )
 
-var symname string = "__.GOSYMDEF"
+const (
+	symname = "__.GOSYMDEF"
+	pkgname = "__.PKGDEF"
+)
 
-var pkgname string = "__.PKGDEF"
-
-var cout *os.File
-
-var version int
-
-// Set if we see an object compiled by the host compiler that is not
-// from a package that is known to support internal linking mode.
-var externalobj int = 0
-
-var goroot string
-
-var goarch string
-
-var goos string
-
-var theline string
+var (
+	cout *os.File
+	// Set if we see an object compiled by the host compiler that is not
+	// from a package that is known to support internal linking mode.
+	externalobj = false
+	goroot      string
+	goarch      string
+	goos        string
+	theline     string
+)
 
 func Lflag(arg string) {
 	Ctxt.Libdir = append(Ctxt.Libdir, arg)
@@ -294,16 +248,13 @@
 }
 
 func libinit() {
-	var suffix string
-	var suffixsep string
-
 	Funcalign = Thearch.Funcalign
 	mywhatsys() // get goroot, goarch, goos
 
 	// add goroot to the end of the libdir list.
-	suffix = ""
+	suffix := ""
 
-	suffixsep = ""
+	suffixsep := ""
 	if flag_installsuffix != "" {
 		suffixsep = "_"
 		suffix = flag_installsuffix
@@ -353,11 +304,9 @@
 
 func loadinternal(name string) {
 	var pname string
-	var i int
-	var found int
 
-	found = 0
-	for i = 0; i < len(Ctxt.Libdir); i++ {
+	found := 0
+	for i := 0; i < len(Ctxt.Libdir); i++ {
 		pname = fmt.Sprintf("%s/%s.a", Ctxt.Libdir[i], name)
 		if Debug['v'] != 0 {
 			fmt.Fprintf(&Bso, "searching for %s.a in %s\n", name, pname)
@@ -375,15 +324,8 @@
 }
 
 func loadlib() {
-	var i int
-	var w int
-	var x int
-	var s *LSym
-	var tlsg *LSym
-	var cgostrsym string
-
 	if Flag_shared != 0 {
-		s = Linklookup(Ctxt, "runtime.islibrary", 0)
+		s := Linklookup(Ctxt, "runtime.islibrary", 0)
 		s.Dupok = 1
 		Adduint8(Ctxt, s, 1)
 	}
@@ -396,6 +338,7 @@
 		loadinternal("runtime/race")
 	}
 
+	var i int
 	for i = 0; i < len(Ctxt.Library); i++ {
 		if Debug['v'] > 1 {
 			fmt.Fprintf(&Bso, "%5.2f autolib: %s (from %s)\n", obj.Cputime(), Ctxt.Library[i].File, Ctxt.Library[i].Objref)
@@ -405,7 +348,7 @@
 	}
 
 	if Linkmode == LinkAuto {
-		if iscgo && externalobj != 0 {
+		if iscgo && externalobj {
 			Linkmode = LinkExternal
 		} else {
 			Linkmode = LinkInternal
@@ -436,30 +379,12 @@
 		if i < len(Ctxt.Library) {
 			objfile(Ctxt.Library[i].File, Ctxt.Library[i].Pkg)
 		}
-
-		// Pretend that we really imported the package.
-		s = Linklookup(Ctxt, "go.importpath.runtime/cgo.", 0)
-
-		s.Type = SDATA
-		s.Dupok = 1
-		s.Reachable = true
-
-		// Provided by the code that imports the package.
-		// Since we are simulating the import, we have to provide this string.
-		cgostrsym = "go.string.\"runtime/cgo\""
-
-		if Linkrlookup(Ctxt, cgostrsym, 0) == nil {
-			s = Linklookup(Ctxt, cgostrsym, 0)
-			s.Type = SRODATA
-			s.Reachable = true
-			addstrdata(cgostrsym, "runtime/cgo")
-		}
 	}
 
 	if Linkmode == LinkInternal {
 		// Drop all the cgo_import_static declarations.
 		// Turns out we won't be needing them.
-		for s = Ctxt.Allsym; s != nil; s = s.Allsym {
+		for s := Ctxt.Allsym; s != nil; s = s.Allsym {
 			if s.Type == SHOSTOBJ {
 				// If a symbol was marked both
 				// cgo_import_static and cgo_import_dynamic,
@@ -474,7 +399,7 @@
 		}
 	}
 
-	tlsg = Linklookup(Ctxt, "runtime.tlsg", 0)
+	tlsg := Linklookup(Ctxt, "runtime.tlsg", 0)
 
 	// For most ports, runtime.tlsg is a placeholder symbol for TLS
 	// relocation. However, the Android and Darwin arm ports need it
@@ -487,18 +412,17 @@
 		tlsg.Type = STLSBSS
 	}
 	tlsg.Size = int64(Thearch.Ptrsize)
-	tlsg.Hide = 1
 	tlsg.Reachable = true
 	Ctxt.Tlsg = tlsg
 
 	// Now that we know the link mode, trim the dynexp list.
-	x = CgoExportDynamic
+	x := CgoExportDynamic
 
 	if Linkmode == LinkExternal {
 		x = CgoExportStatic
 	}
-	w = 0
-	for i = 0; i < len(dynexp); i++ {
+	w := 0
+	for i := 0; i < len(dynexp); i++ {
 		if int(dynexp[i].Cgoexport)&x != 0 {
 			dynexp[w] = dynexp[i]
 			w++
@@ -564,12 +488,6 @@
 }
 
 func objfile(file string, pkg string) {
-	var off int64
-	var l int64
-	var f *Biobuf
-	var pname string
-	var arhdr ArHdr
-
 	pkg = pathtoprefix(pkg)
 
 	if Debug['v'] > 1 {
@@ -577,6 +495,7 @@
 	}
 	Bflush(&Bso)
 	var err error
+	var f *Biobuf
 	f, err = Bopenr(file)
 	if err != nil {
 		Diag("cannot open file %s: %v", file, err)
@@ -586,7 +505,7 @@
 	magbuf := make([]byte, len(ARMAG))
 	if Bread(f, magbuf) != len(magbuf) || !strings.HasPrefix(string(magbuf), ARMAG) {
 		/* load it as a regular file */
-		l = Bseek(f, 0, 2)
+		l := Bseek(f, 0, 2)
 
 		Bseek(f, 0, 0)
 		ldobj(f, pkg, l, file, file, FileObj)
@@ -596,9 +515,11 @@
 	}
 
 	/* skip over optional __.GOSYMDEF and process __.PKGDEF */
-	off = Boffset(f)
+	off := Boffset(f)
 
-	l = nextar(f, off, &arhdr)
+	var arhdr ArHdr
+	l := nextar(f, off, &arhdr)
+	var pname string
 	if l <= 0 {
 		Diag("%s: short read on archive file symbol header", file)
 		goto out
@@ -669,10 +590,6 @@
 
 var hostobj []Hostobj
 
-var nhostobj int
-
-var mhostobj int
-
 // These packages can use internal linking mode.
 // Others trigger external mode.
 var internalpkg = []string{
@@ -684,14 +601,10 @@
 }
 
 func ldhostobj(ld func(*Biobuf, string, int64, string), f *Biobuf, pkg string, length int64, pn string, file string) {
-	var i int
-	var isinternal int
-	var h *Hostobj
-
-	isinternal = 0
-	for i = 0; i < len(internalpkg); i++ {
+	isinternal := false
+	for i := 0; i < len(internalpkg); i++ {
 		if pkg == internalpkg[i] {
-			isinternal = 1
+			isinternal = true
 			break
 		}
 	}
@@ -704,16 +617,16 @@
 	// these relocation types.
 	if HEADTYPE == Hdragonfly {
 		if pkg == "net" || pkg == "os/user" {
-			isinternal = 0
+			isinternal = false
 		}
 	}
 
-	if isinternal == 0 {
-		externalobj = 1
+	if !isinternal {
+		externalobj = true
 	}
 
 	hostobj = append(hostobj, Hostobj{})
-	h = &hostobj[len(hostobj)-1]
+	h := &hostobj[len(hostobj)-1]
 	h.ld = ld
 	h.pkg = pkg
 	h.pn = pn
@@ -723,11 +636,10 @@
 }
 
 func hostobjs() {
-	var i int
 	var f *Biobuf
 	var h *Hostobj
 
-	for i = 0; i < len(hostobj); i++ {
+	for i := 0; i < len(hostobj); i++ {
 		h = &hostobj[i]
 		var err error
 		f, err = Bopenr(h.file)
@@ -750,8 +662,6 @@
 }
 
 func hostlinksetup() {
-	var p string
-
 	if Linkmode != LinkExternal {
 		return
 	}
@@ -769,7 +679,7 @@
 	// change our output to temporary object file
 	cout.Close()
 
-	p = fmt.Sprintf("%s/go.o", tmpdir)
+	p := fmt.Sprintf("%s/go.o", tmpdir)
 	var err error
 	cout, err = os.OpenFile(p, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0775)
 	if err != nil {
@@ -783,14 +693,6 @@
 var hostlink_buf = make([]byte, 64*1024)
 
 func hostlink() {
-	var p string
-	var argv []string
-	var i int
-	var n int
-	var length int
-	var h *Hostobj
-	var f *Biobuf
-
 	if Linkmode != LinkExternal || nerrors > 0 {
 		return
 	}
@@ -798,13 +700,13 @@
 	if extld == "" {
 		extld = "gcc"
 	}
+	var argv []string
 	argv = append(argv, extld)
 	switch Thearch.Thechar {
 	case '8':
 		argv = append(argv, "-m32")
 
-	case '6',
-		'9':
+	case '6', '9':
 		argv = append(argv, "-m64")
 
 	case '5':
@@ -823,6 +725,13 @@
 	if HEADTYPE == Hopenbsd {
 		argv = append(argv, "-Wl,-nopie")
 	}
+	if HEADTYPE == Hwindows {
+		if headstring == "windowsgui" {
+			argv = append(argv, "-mwindows")
+		} else {
+			argv = append(argv, "-mconsole")
+		}
+	}
 
 	if Iself && AssumeGoldLinker != 0 /*TypeKind(100016)*/ {
 		argv = append(argv, "-Wl,--rosegment")
@@ -851,7 +760,12 @@
 
 	// already wrote main object file
 	// copy host objects to temporary directory
-	for i = 0; i < len(hostobj); i++ {
+	var f *Biobuf
+	var h *Hostobj
+	var length int
+	var n int
+	var p string
+	for i := 0; i < len(hostobj); i++ {
 		h = &hostobj[i]
 		var err error
 		f, err = Bopenr(h.file)
@@ -886,7 +800,7 @@
 			length -= n
 		}
 
-		if err = w.Close(); err != nil {
+		if err := w.Close(); err != nil {
 			Ctxt.Cursym = nil
 			Diag("cannot write %s: %v", p, err)
 			Errorexit()
@@ -896,6 +810,7 @@
 	}
 
 	argv = append(argv, fmt.Sprintf("%s/go.o", tmpdir))
+	var i int
 	for i = 0; i < len(ldflag); i++ {
 		argv = append(argv, ldflag[i])
 	}
@@ -917,6 +832,9 @@
 			}
 		}
 	}
+	if HEADTYPE == Hwindows {
+		argv = append(argv, peimporteddlls()...)
+	}
 
 	if Debug['v'] != 0 {
 		fmt.Fprintf(&Bso, "host link:")
@@ -935,30 +853,18 @@
 }
 
 func ldobj(f *Biobuf, pkg string, length int64, pn string, file string, whence int) {
-	var line string
-	var c1 int
-	var c2 int
-	var c3 int
-	var c4 int
-	var magic uint32
-	var import0 int64
-	var import1 int64
-	var eof int64
-	var start int64
-	var t string
-
-	eof = Boffset(f) + length
+	eof := Boffset(f) + length
 
 	pn = pn
 
-	start = Boffset(f)
-	c1 = Bgetc(f)
-	c2 = Bgetc(f)
-	c3 = Bgetc(f)
-	c4 = Bgetc(f)
+	start := Boffset(f)
+	c1 := Bgetc(f)
+	c2 := Bgetc(f)
+	c3 := Bgetc(f)
+	c4 := Bgetc(f)
 	Bseek(f, start, 0)
 
-	magic = uint32(c1)<<24 | uint32(c2)<<16 | uint32(c3)<<8 | uint32(c4)
+	magic := uint32(c1)<<24 | uint32(c2)<<16 | uint32(c3)<<8 | uint32(c4)
 	if magic == 0x7f454c46 { // \x7F E L F
 		ldhostobj(ldelf, f, pkg, length, pn, file)
 		return
@@ -975,8 +881,11 @@
 	}
 
 	/* check the header */
-	line = Brdline(f, '\n')
+	line := Brdline(f, '\n')
 
+	var import0 int64
+	var import1 int64
+	var t string
 	if line == "" {
 		if Blinelen(f) > 0 {
 			Diag("%s: not an object file", pn)
@@ -1054,13 +963,6 @@
 	Diag("truncated object file: %s", pn)
 }
 
-func zerosig(sp string) {
-	var s *LSym
-
-	s = Linklookup(Ctxt, sp, 0)
-	s.Sig = 0
-}
-
 func mywhatsys() {
 	goroot = obj.Getgoroot()
 	goos = obj.Getgoos()
@@ -1071,18 +973,6 @@
 	}
 }
 
-func pathchar() int {
-	return '/'
-}
-
-var hunk []byte
-
-var nhunk uint32
-
-const (
-	NHUNK = 10 << 20
-)
-
 // Copied from ../gc/subr.c:/^pathtoprefix; must stay in sync.
 /*
  * Convert raw string to the prefix that will be used in the symbol table.
@@ -1097,44 +987,27 @@
 	for i := 0; i < len(s); i++ {
 		c := s[i]
 		if c <= ' ' || i >= slash && c == '.' || c == '%' || c == '"' || c >= 0x7F {
-			goto escape
+			var buf bytes.Buffer
+			for i := 0; i < len(s); i++ {
+				c := s[i]
+				if c <= ' ' || i >= slash && c == '.' || c == '%' || c == '"' || c >= 0x7F {
+					fmt.Fprintf(&buf, "%%%02x", c)
+					continue
+				}
+				buf.WriteByte(c)
+			}
+			return buf.String()
 		}
 	}
 	return s
-
-escape:
-	var buf bytes.Buffer
-	for i := 0; i < len(s); i++ {
-		c := s[i]
-		if c <= ' ' || i >= slash && c == '.' || c == '%' || c == '"' || c >= 0x7F {
-			fmt.Fprintf(&buf, "%%%02x", c)
-			continue
-		}
-		buf.WriteByte(c)
-	}
-	return buf.String()
-}
-
-func iconv(p string) string {
-	var fp string
-
-	if p == "" {
-		fp += "<nil>"
-		return fp
-	}
-
-	p = pathtoprefix(p)
-	fp += p
-	return fp
 }
 
 func addsection(seg *Segment, name string, rwx int) *Section {
 	var l **Section
-	var sect *Section
 
 	for l = &seg.Sect; *l != nil; l = &(*l).Next {
 	}
-	sect = new(Section)
+	sect := new(Section)
 	sect.Rwx = uint8(rwx)
 	sect.Name = name
 	sect.Seg = seg
@@ -1167,25 +1040,22 @@
 	return uint64(Be32(b))<<32 | uint64(Be32(b[4:]))
 }
 
-var be = Endian{Be16, Be32, Be64}
-
-var le = Endian{Le16, Le32, Le64}
-
 type Chain struct {
 	sym   *LSym
 	up    *Chain
-	limit int
+	limit int // limit on entry to sym
 }
 
-var morestack *LSym
-
-var newstack *LSym
+var (
+	morestack *LSym
+	newstack  *LSym
+)
 
 // TODO: Record enough information in new object files to
 // allow stack checks here.
 
 func haslinkregister() bool {
-	return Thearch.Thechar == '5' || Thearch.Thechar == '9'
+	return Thearch.Thechar == '5' || Thearch.Thechar == '9' || Thearch.Thechar == '7'
 }
 
 func callsize() int {
@@ -1197,7 +1067,6 @@
 
 func dostkcheck() {
 	var ch Chain
-	var s *LSym
 
 	morestack = Linklookup(Ctxt, "runtime.morestack", 0)
 	newstack = Linklookup(Ctxt, "runtime.newstack", 0)
@@ -1215,7 +1084,7 @@
 
 	// Check every function, but do the nosplit functions in a first pass,
 	// to make the printed failure chains as short as possible.
-	for s = Ctxt.Textp; s != nil; s = s.Next {
+	for s := Ctxt.Textp; s != nil; s = s.Next {
 		// runtime.racesymbolizethunk is called from gcc-compiled C
 		// code running on the operating system thread stack.
 		// It uses more than the usual amount of stack but that's okay.
@@ -1230,7 +1099,7 @@
 		}
 	}
 
-	for s = Ctxt.Textp; s != nil; s = s.Next {
+	for s := Ctxt.Textp; s != nil; s = s.Next {
 		if s.Nosplit == 0 {
 			Ctxt.Cursym = s
 			ch.sym = s
@@ -1240,17 +1109,8 @@
 }
 
 func stkcheck(up *Chain, depth int) int {
-	var ch Chain
-	var ch1 Chain
-	var s *LSym
-	var limit int
-	var r *Reloc
-	var ri int
-	var endr int
-	var pcsp Pciter
-
-	limit = up.limit
-	s = up.sym
+	limit := up.limit
+	s := up.sym
 
 	// Don't duplicate work: only need to consider each
 	// function at top of safe zone once.
@@ -1288,12 +1148,16 @@
 		return 0
 	}
 
+	var ch Chain
 	ch.up = up
 
 	// Walk through sp adjustments in function, consuming relocs.
-	ri = 0
+	ri := 0
 
-	endr = len(s.R)
+	endr := len(s.R)
+	var ch1 Chain
+	var pcsp Pciter
+	var r *Reloc
 	for pciterinit(Ctxt, &pcsp, &s.Pcln.Pcsp); pcsp.done == 0; pciternext(&pcsp) {
 		// pcsp.value is in effect for [pcsp.pc, pcsp.nextpc).
 
@@ -1308,9 +1172,7 @@
 			r = &s.R[ri]
 			switch r.Type {
 			// Direct call.
-			case R_CALL,
-				R_CALLARM,
-				R_CALLPOWER:
+			case R_CALL, R_CALLARM, R_CALLARM64, R_CALLPOWER:
 				ch.limit = int(int32(limit) - pcsp.value - int32(callsize()))
 
 				ch.sym = r.Sym
@@ -1384,16 +1246,12 @@
 func Yconv(s *LSym) string {
 	var fp string
 
-	var fmt_ string
-	var i int
-	var str string
-
 	if s == nil {
 		fp += fmt.Sprintf("<nil>")
 	} else {
-		fmt_ = ""
+		fmt_ := ""
 		fmt_ += fmt.Sprintf("%s @0x%08x [%d]", s.Name, int64(s.Value), int64(s.Size))
-		for i = 0; int64(i) < s.Size; i++ {
+		for i := 0; int64(i) < s.Size; i++ {
 			if i%8 == 0 {
 				fmt_ += fmt.Sprintf("\n\t0x%04x ", i)
 			}
@@ -1401,11 +1259,11 @@
 		}
 
 		fmt_ += fmt.Sprintf("\n")
-		for i = 0; i < len(s.R); i++ {
+		for i := 0; i < len(s.R); i++ {
 			fmt_ += fmt.Sprintf("\t0x%04x[%x] %d %s[%x]\n", s.R[i].Off, s.R[i].Siz, s.R[i].Type, s.R[i].Sym.Name, int64(s.R[i].Add))
 		}
 
-		str = fmt_
+		str := fmt_
 		fp += str
 	}
 
@@ -1439,9 +1297,7 @@
 }
 
 func setheadtype(s string) {
-	var h int
-
-	h = headtype(s)
+	h := headtype(s)
 	if h < 0 {
 		fmt.Fprintf(os.Stderr, "unknown header type -H %s\n", s)
 		Errorexit()
@@ -1462,13 +1318,9 @@
 }
 
 func genasmsym(put func(*LSym, string, int, int64, int64, int, *LSym)) {
-	var a *Auto
-	var s *LSym
-	var off int32
-
 	// These symbols won't show up in the first loop below because we
 	// skip STEXT symbols. Normal STEXT symbols are emitted by walking textp.
-	s = Linklookup(Ctxt, "runtime.text", 0)
+	s := Linklookup(Ctxt, "runtime.text", 0)
 
 	if s.Type == STEXT {
 		put(s, s.Name, 'T', s.Value, s.Size, int(s.Version), nil)
@@ -1478,7 +1330,7 @@
 		put(s, s.Name, 'T', s.Value, s.Size, int(s.Version), nil)
 	}
 
-	for s = Ctxt.Allsym; s != nil; s = s.Allsym {
+	for s := Ctxt.Allsym; s != nil; s = s.Allsym {
 		if s.Hide != 0 || (s.Name[0] == '.' && s.Version == 0 && s.Name != ".rathole") {
 			continue
 		}
@@ -1487,6 +1339,7 @@
 			SRODATA,
 			SSYMTAB,
 			SPCLNTAB,
+			SINITARR,
 			SDATA,
 			SNOPTRDATA,
 			SELFROSECT,
@@ -1499,10 +1352,8 @@
 				continue
 			}
 			put(s, s.Name, 'D', Symaddr(s), s.Size, int(s.Version), s.Gotype)
-			continue
 
-		case SBSS,
-			SNOPTRBSS:
+		case SBSS, SNOPTRBSS:
 			if !s.Reachable {
 				continue
 			}
@@ -1510,15 +1361,37 @@
 				Diag("%s should not be bss (size=%d type=%d special=%d)", s.Name, int(len(s.P)), s.Type, s.Special)
 			}
 			put(s, s.Name, 'B', Symaddr(s), s.Size, int(s.Version), s.Gotype)
-			continue
 
 		case SFILE:
 			put(nil, s.Name, 'f', s.Value, 0, int(s.Version), nil)
-			continue
+
+		case SHOSTOBJ:
+			if HEADTYPE == Hwindows || Iself {
+				put(s, s.Name, 'U', s.Value, 0, int(s.Version), nil)
+			}
+
+		case SDYNIMPORT:
+			if !s.Reachable {
+				continue
+			}
+			put(s, s.Extname, 'U', 0, 0, int(s.Version), nil)
+
+		case STLSBSS:
+			if Linkmode == LinkExternal && HEADTYPE != Hopenbsd {
+				var type_ int
+				if goos == "android" {
+					type_ = 'B'
+				} else {
+					type_ = 't'
+				}
+				put(s, s.Name, type_, Symaddr(s), s.Size, int(s.Version), s.Gotype)
+			}
 		}
 	}
 
-	for s = Ctxt.Textp; s != nil; s = s.Next {
+	var a *Auto
+	var off int32
+	for s := Ctxt.Textp; s != nil; s = s.Next {
 		put(s, s.Name, 'T', s.Value, s.Size, int(s.Version), s.Gotype)
 
 		// NOTE(ality): acid can't produce a stack trace without .frame symbols
@@ -1568,9 +1441,7 @@
 }
 
 func xdefine(p string, t int, v int64) {
-	var s *LSym
-
-	s = Linklookup(Ctxt, p, 0)
+	s := Linklookup(Ctxt, p, 0)
 	s.Type = int16(t)
 	s.Value = v
 	s.Reachable = true
@@ -1589,14 +1460,11 @@
 }
 
 func Entryvalue() int64 {
-	var a string
-	var s *LSym
-
-	a = INITENTRY
+	a := INITENTRY
 	if a[0] >= '0' && a[0] <= '9' {
 		return atolwhex(a)
 	}
-	s = Linklookup(Ctxt, a, 0)
+	s := Linklookup(Ctxt, a, 0)
 	if s.Type == 0 {
 		return INITTEXT
 	}
@@ -1607,11 +1475,10 @@
 }
 
 func undefsym(s *LSym) {
-	var i int
 	var r *Reloc
 
 	Ctxt.Cursym = s
-	for i = 0; i < len(s.R); i++ {
+	for i := 0; i < len(s.R); i++ {
 		r = &s.R[i]
 		if r.Sym == nil { // happens for some external ARM relocs
 			continue
@@ -1626,12 +1493,10 @@
 }
 
 func undef() {
-	var s *LSym
-
-	for s = Ctxt.Textp; s != nil; s = s.Next {
+	for s := Ctxt.Textp; s != nil; s = s.Next {
 		undefsym(s)
 	}
-	for s = datap; s != nil; s = s.Next {
+	for s := datap; s != nil; s = s.Next {
 		undefsym(s)
 	}
 	if nerrors > 0 {
@@ -1640,15 +1505,13 @@
 }
 
 func callgraph() {
-	var s *LSym
-	var r *Reloc
-	var i int
-
 	if Debug['c'] == 0 {
 		return
 	}
 
-	for s = Ctxt.Textp; s != nil; s = s.Next {
+	var i int
+	var r *Reloc
+	for s := Ctxt.Textp; s != nil; s = s.Next {
 		for i = 0; i < len(s.R); i++ {
 			r = &s.R[i]
 			if r.Sym == nil {
@@ -1678,11 +1541,6 @@
 }
 
 func checkgo() {
-	var s *LSym
-	var r *Reloc
-	var i int
-	var changed int
-
 	if Debug['C'] == 0 {
 		return
 	}
@@ -1691,6 +1549,10 @@
 	// which would simplify this logic quite a bit.
 
 	// Mark every Go-called C function with cfunc=2, recursively.
+	var changed int
+	var i int
+	var r *Reloc
+	var s *LSym
 	for {
 		changed = 0
 		for s = Ctxt.Textp; s != nil; s = s.Next {
@@ -1716,7 +1578,7 @@
 
 	// Complain about Go-called C functions that can split the stack
 	// (that can be preempted for garbage collection or trigger a stack copy).
-	for s = Ctxt.Textp; s != nil; s = s.Next {
+	for s := Ctxt.Textp; s != nil; s = s.Next {
 		if s.Cfunc == 0 || (s.Cfunc == 2 && s.Nosplit != 0) {
 			for i = 0; i < len(s.R); i++ {
 				r = &s.R[i]
@@ -1736,13 +1598,11 @@
 }
 
 func Rnd(v int64, r int64) int64 {
-	var c int64
-
 	if r <= 0 {
 		return v
 	}
 	v += r - 1
-	c = v % r
+	c := v % r
 	if c < 0 {
 		c += r
 	}
diff --git a/src/cmd/internal/ld/link.go b/src/cmd/internal/ld/link.go
index 69702fb..a5624ed 100644
--- a/src/cmd/internal/ld/link.go
+++ b/src/cmd/internal/ld/link.go
@@ -50,7 +50,6 @@
 	Localentry  uint8
 	Onlist      uint8
 	Dynid       int32
-	Sig         int32
 	Plt         int32
 	Got         int32
 	Align       int32
@@ -128,7 +127,6 @@
 	ByteOrder binary.ByteOrder
 	Name      string
 	Thechar   int
-	Endian    int32
 	Minlc     int
 	Ptrsize   int
 	Regsize   int
@@ -221,6 +219,7 @@
 	R_SIZE
 	R_CALL
 	R_CALLARM
+	R_CALLARM64
 	R_CALLIND
 	R_CALLPOWER
 	R_CONST
@@ -269,11 +268,6 @@
 // Link holds the context for writing object code from a compiler
 // to be linker input or for reading that input into the linker.
 
-const (
-	LittleEndian = 0x04030201
-	BigEndian    = 0x01020304
-)
-
 // LinkArch is the definition of a single architecture.
 
 /* executable header types */
diff --git a/src/cmd/internal/ld/macho.go b/src/cmd/internal/ld/macho.go
index 6349642..bff73339 100644
--- a/src/cmd/internal/ld/macho.go
+++ b/src/cmd/internal/ld/macho.go
@@ -95,10 +95,6 @@
 
 var seg [16]MachoSeg
 
-var nload int
-
-var mload int
-
 var nseg int
 
 var ndebug int
@@ -129,8 +125,7 @@
 func Machoinit() {
 	switch Thearch.Thechar {
 	// 64-bit architectures
-	case '6',
-		'9':
+	case '6', '9':
 		macho64 = true
 
 		// 32-bit architectures
@@ -156,14 +151,12 @@
 }
 
 func newMachoSeg(name string, msect int) *MachoSeg {
-	var s *MachoSeg
-
 	if nseg >= len(seg) {
 		Diag("too many segs")
 		Errorexit()
 	}
 
-	s = &seg[nseg]
+	s := &seg[nseg]
 	nseg++
 	s.name = name
 	s.msect = uint32(msect)
@@ -172,14 +165,12 @@
 }
 
 func newMachoSect(seg *MachoSeg, name string, segname string) *MachoSect {
-	var s *MachoSect
-
 	if seg.nsect >= seg.msect {
 		Diag("too many sects in segment %s", seg.name)
 		Errorexit()
 	}
 
-	s = &seg.sect[seg.nsect]
+	s := &seg.sect[seg.nsect]
 	seg.nsect++
 	s.name = name
 	s.segname = segname
@@ -191,23 +182,13 @@
 
 var dylib []string
 
-var ndylib int
-
 var linkoff int64
 
 func machowrite() int {
-	var o1 int64
-	var loadsize int
-	var i int
-	var j int
-	var s *MachoSeg
-	var t *MachoSect
-	var l *MachoLoad
+	o1 := Cpos()
 
-	o1 = Cpos()
-
-	loadsize = 4 * 4 * ndebug
-	for i = 0; i < len(load); i++ {
+	loadsize := 4 * 4 * ndebug
+	for i := 0; i < len(load); i++ {
 		loadsize += 4 * (len(load[i].data) + 2)
 	}
 	if macho64 {
@@ -237,7 +218,10 @@
 		Thearch.Lput(0) /* reserved */
 	}
 
-	for i = 0; i < nseg; i++ {
+	var j int
+	var s *MachoSeg
+	var t *MachoSect
+	for i := 0; i < nseg; i++ {
 		s = &seg[i]
 		if macho64 {
 			Thearch.Lput(25) /* segment 64 */
@@ -296,7 +280,8 @@
 		}
 	}
 
-	for i = 0; i < len(load); i++ {
+	var l *MachoLoad
+	for i := 0; i < len(load); i++ {
 		l = &load[i]
 		Thearch.Lput(l.type_)
 		Thearch.Lput(4 * (uint32(len(l.data)) + 2))
@@ -309,14 +294,12 @@
 }
 
 func domacho() {
-	var s *LSym
-
 	if Debug['d'] != 0 {
 		return
 	}
 
 	// empirically, string table must begin with " \x00".
-	s = Linklookup(Ctxt, ".machosymstr", 0)
+	s := Linklookup(Ctxt, ".machosymstr", 0)
 
 	s.Type = SMACHOSYMSTR
 	s.Reachable = true
@@ -328,7 +311,7 @@
 	s.Reachable = true
 
 	if Linkmode != LinkExternal {
-		s = Linklookup(Ctxt, ".plt", 0) // will be __symbol_stub
+		s := Linklookup(Ctxt, ".plt", 0) // will be __symbol_stub
 		s.Type = SMACHOPLT
 		s.Reachable = true
 
@@ -364,12 +347,9 @@
 }
 
 func machoshbits(mseg *MachoSeg, sect *Section, segname string) {
-	var msect *MachoSect
-	var buf string
+	buf := "__" + strings.Replace(sect.Name[1:], ".", "_", -1)
 
-	buf = "__" + strings.Replace(sect.Name[1:], ".", "_", -1)
-
-	msect = newMachoSect(mseg, buf, segname)
+	msect := newMachoSect(mseg, buf, segname)
 	if sect.Rellen > 0 {
 		msect.reloc = uint32(sect.Reloff)
 		msect.nreloc = uint32(sect.Rellen / 8)
@@ -413,20 +393,10 @@
 }
 
 func Asmbmacho() {
-	var v int64
-	var w int64
-	var va int64
-	var a int
-	var i int
-	var mh *MachoHdr
-	var ms *MachoSeg
-	var ml *MachoLoad
-	var sect *Section
-
 	/* apple MACH */
-	va = INITTEXT - int64(HEADR)
+	va := INITTEXT - int64(HEADR)
 
-	mh = getMachoHdr()
+	mh := getMachoHdr()
 	switch Thearch.Thechar {
 	default:
 		Diag("unknown mach architecture")
@@ -446,7 +416,7 @@
 		mh.subcpu = MACHO_SUBCPU_X86
 	}
 
-	ms = nil
+	var ms *MachoSeg
 	if Linkmode == LinkExternal {
 		/* segment for entire file */
 		ms = newMachoSeg("", 40)
@@ -462,7 +432,7 @@
 	}
 
 	/* text */
-	v = Rnd(int64(uint64(HEADR)+Segtext.Length), int64(INITRND))
+	v := Rnd(int64(uint64(HEADR)+Segtext.Length), int64(INITRND))
 
 	if Linkmode != LinkExternal {
 		ms = newMachoSeg("__TEXT", 20)
@@ -474,13 +444,13 @@
 		ms.prot2 = 5
 	}
 
-	for sect = Segtext.Sect; sect != nil; sect = sect.Next {
+	for sect := Segtext.Sect; sect != nil; sect = sect.Next {
 		machoshbits(ms, sect, "__TEXT")
 	}
 
 	/* data */
 	if Linkmode != LinkExternal {
-		w = int64(Segdata.Length)
+		w := int64(Segdata.Length)
 		ms = newMachoSeg("__DATA", 20)
 		ms.vaddr = uint64(va) + uint64(v)
 		ms.vsize = uint64(w)
@@ -490,7 +460,7 @@
 		ms.prot2 = 3
 	}
 
-	for sect = Segdata.Sect; sect != nil; sect = sect.Next {
+	for sect := Segdata.Sect; sect != nil; sect = sect.Next {
 		machoshbits(ms, sect, "__DATA")
 	}
 
@@ -502,20 +472,20 @@
 			fallthrough
 
 		case '5':
-			ml = newMachoLoad(5, 17+2)           /* unix thread */
+			ml := newMachoLoad(5, 17+2)          /* unix thread */
 			ml.data[0] = 1                       /* thread type */
 			ml.data[1] = 17                      /* word count */
 			ml.data[2+15] = uint32(Entryvalue()) /* start pc */
 
 		case '6':
-			ml = newMachoLoad(5, 42+2)                         /* unix thread */
+			ml := newMachoLoad(5, 42+2)                        /* unix thread */
 			ml.data[0] = 4                                     /* thread type */
 			ml.data[1] = 42                                    /* word count */
 			ml.data[2+32] = uint32(Entryvalue())               /* start pc */
 			ml.data[2+32+1] = uint32(Entryvalue() >> 16 >> 16) // hide >>32 for 8l
 
 		case '8':
-			ml = newMachoLoad(5, 16+2)           /* unix thread */
+			ml := newMachoLoad(5, 16+2)          /* unix thread */
 			ml.data[0] = 1                       /* thread type */
 			ml.data[1] = 16                      /* word count */
 			ml.data[2+10] = uint32(Entryvalue()) /* start pc */
@@ -523,20 +493,15 @@
 	}
 
 	if Debug['d'] == 0 {
-		var s1 *LSym
-		var s2 *LSym
-		var s3 *LSym
-		var s4 *LSym
-
 		// must match domacholink below
-		s1 = Linklookup(Ctxt, ".machosymtab", 0)
+		s1 := Linklookup(Ctxt, ".machosymtab", 0)
 
-		s2 = Linklookup(Ctxt, ".linkedit.plt", 0)
-		s3 = Linklookup(Ctxt, ".linkedit.got", 0)
-		s4 = Linklookup(Ctxt, ".machosymstr", 0)
+		s2 := Linklookup(Ctxt, ".linkedit.plt", 0)
+		s3 := Linklookup(Ctxt, ".linkedit.got", 0)
+		s4 := Linklookup(Ctxt, ".machosymstr", 0)
 
 		if Linkmode != LinkExternal {
-			ms = newMachoSeg("__LINKEDIT", 0)
+			ms := newMachoSeg("__LINKEDIT", 0)
 			ms.vaddr = uint64(va) + uint64(v) + uint64(Rnd(int64(Segdata.Length), int64(INITRND)))
 			ms.vsize = uint64(s1.Size) + uint64(s2.Size) + uint64(s3.Size) + uint64(s4.Size)
 			ms.fileoffset = uint64(linkoff)
@@ -545,7 +510,7 @@
 			ms.prot2 = 3
 		}
 
-		ml = newMachoLoad(2, 4)                                    /* LC_SYMTAB */
+		ml := newMachoLoad(2, 4)                                   /* LC_SYMTAB */
 		ml.data[0] = uint32(linkoff)                               /* symoff */
 		ml.data[1] = uint32(nsortsym)                              /* nsyms */
 		ml.data[2] = uint32(linkoff + s1.Size + s2.Size + s3.Size) /* stroff */
@@ -554,11 +519,11 @@
 		machodysymtab()
 
 		if Linkmode != LinkExternal {
-			ml = newMachoLoad(14, 6) /* LC_LOAD_DYLINKER */
-			ml.data[0] = 12          /* offset to string */
+			ml := newMachoLoad(14, 6) /* LC_LOAD_DYLINKER */
+			ml.data[0] = 12           /* offset to string */
 			stringtouint32(ml.data[1:], "/usr/lib/dyld")
 
-			for i = 0; i < len(dylib); i++ {
+			for i := 0; i < len(dylib); i++ {
 				ml = newMachoLoad(12, 4+(uint32(len(dylib[i]))+1+7)/8*2) /* LC_LOAD_DYLIB */
 				ml.data[0] = 24                                          /* offset of string from beginning of load */
 				ml.data[1] = 0                                           /* time stamp */
@@ -574,7 +539,7 @@
 		dwarfaddmachoheaders()
 	}
 
-	a = machowrite()
+	a := machowrite()
 	if int32(a) > HEADR {
 		Diag("HEADR too small: %d > %d", a, HEADR)
 	}
@@ -599,9 +564,7 @@
 	default:
 		return
 
-	case 'D',
-		'B',
-		'T':
+	case 'D', 'B', 'T':
 		break
 	}
 
@@ -624,16 +587,11 @@
 }
 
 func (x machoscmp) Less(i, j int) bool {
-	var s1 *LSym
-	var s2 *LSym
-	var k1 int
-	var k2 int
+	s1 := x[i]
+	s2 := x[j]
 
-	s1 = x[i]
-	s2 = x[j]
-
-	k1 = symkind(s1)
-	k2 = symkind(s2)
+	k1 := symkind(s1)
+	k2 := symkind(s2)
 	if k1 != k2 {
 		return k1-k2 < 0
 	}
@@ -642,10 +600,8 @@
 }
 
 func machogenasmsym(put func(*LSym, string, int, int64, int64, int, *LSym)) {
-	var s *LSym
-
 	genasmsym(put)
-	for s = Ctxt.Allsym; s != nil; s = s.Allsym {
+	for s := Ctxt.Allsym; s != nil; s = s.Allsym {
 		if s.Type == SDYNIMPORT || s.Type == SHOSTOBJ {
 			if s.Reachable {
 				put(s, "", 'D', 0, 0, 0, nil)
@@ -655,12 +611,10 @@
 }
 
 func machosymorder() {
-	var i int
-
 	// On Mac OS X Mountain Lion, we must sort exported symbols
 	// So we sort them here and pre-allocate dynid for them
 	// See http://golang.org/issue/4029
-	for i = 0; i < len(dynexp); i++ {
+	for i := 0; i < len(dynexp); i++ {
 		dynexp[i].Reachable = true
 	}
 	machogenasmsym(addsym)
@@ -668,23 +622,20 @@
 	nsortsym = 0
 	machogenasmsym(addsym)
 	sort.Sort(machoscmp(sortsym[:nsortsym]))
-	for i = 0; i < nsortsym; i++ {
+	for i := 0; i < nsortsym; i++ {
 		sortsym[i].Dynid = int32(i)
 	}
 }
 
 func machosymtab() {
-	var i int
-	var symtab *LSym
-	var symstr *LSym
 	var s *LSym
 	var o *LSym
 	var p string
 
-	symtab = Linklookup(Ctxt, ".machosymtab", 0)
-	symstr = Linklookup(Ctxt, ".machosymstr", 0)
+	symtab := Linklookup(Ctxt, ".machosymtab", 0)
+	symstr := Linklookup(Ctxt, ".machosymstr", 0)
 
-	for i = 0; i < nsortsym; i++ {
+	for i := 0; i < nsortsym; i++ {
 		s = sortsym[i]
 		Adduint32(Ctxt, symtab, uint32(symstr.Size))
 
@@ -737,15 +688,9 @@
 }
 
 func machodysymtab() {
-	var n int
-	var ml *MachoLoad
-	var s1 *LSym
-	var s2 *LSym
-	var s3 *LSym
+	ml := newMachoLoad(11, 18) /* LC_DYSYMTAB */
 
-	ml = newMachoLoad(11, 18) /* LC_DYSYMTAB */
-
-	n = 0
+	n := 0
 	ml.data[0] = uint32(n)                   /* ilocalsym */
 	ml.data[1] = uint32(nkind[SymKindLocal]) /* nlocalsym */
 	n += nkind[SymKindLocal]
@@ -765,10 +710,10 @@
 	ml.data[11] = 0 /* nextrefsyms */
 
 	// must match domacholink below
-	s1 = Linklookup(Ctxt, ".machosymtab", 0)
+	s1 := Linklookup(Ctxt, ".machosymtab", 0)
 
-	s2 = Linklookup(Ctxt, ".linkedit.plt", 0)
-	s3 = Linklookup(Ctxt, ".linkedit.got", 0)
+	s2 := Linklookup(Ctxt, ".linkedit.plt", 0)
+	s3 := Linklookup(Ctxt, ".linkedit.got", 0)
 	ml.data[12] = uint32(linkoff + s1.Size)       /* indirectsymoff */
 	ml.data[13] = uint32((s2.Size + s3.Size) / 4) /* nindirectsyms */
 
@@ -779,20 +724,14 @@
 }
 
 func Domacholink() int64 {
-	var size int
-	var s1 *LSym
-	var s2 *LSym
-	var s3 *LSym
-	var s4 *LSym
-
 	machosymtab()
 
 	// write data that will be linkedit section
-	s1 = Linklookup(Ctxt, ".machosymtab", 0)
+	s1 := Linklookup(Ctxt, ".machosymtab", 0)
 
-	s2 = Linklookup(Ctxt, ".linkedit.plt", 0)
-	s3 = Linklookup(Ctxt, ".linkedit.got", 0)
-	s4 = Linklookup(Ctxt, ".machosymstr", 0)
+	s2 := Linklookup(Ctxt, ".linkedit.plt", 0)
+	s3 := Linklookup(Ctxt, ".linkedit.got", 0)
+	s4 := Linklookup(Ctxt, ".machosymstr", 0)
 
 	// Force the linkedit section to end on a 16-byte
 	// boundary.  This allows pure (non-cgo) Go binaries
@@ -815,7 +754,7 @@
 		Adduint8(Ctxt, s4, 0)
 	}
 
-	size = int(s1.Size + s2.Size + s3.Size + s4.Size)
+	size := int(s1.Size + s2.Size + s3.Size + s4.Size)
 
 	if size > 0 {
 		linkoff = Rnd(int64(uint64(HEADR)+Segtext.Length), int64(INITRND)) + Rnd(int64(Segdata.Filelen), int64(INITRND)) + Rnd(int64(Segdwarf.Filelen), int64(INITRND))
@@ -831,17 +770,13 @@
 }
 
 func machorelocsect(sect *Section, first *LSym) {
-	var sym *LSym
-	var eaddr int32
-	var ri int
-	var r *Reloc
-
 	// If main section has no bits, nothing to relocate.
 	if sect.Vaddr >= sect.Seg.Vaddr+sect.Seg.Filelen {
 		return
 	}
 
 	sect.Reloff = uint64(Cpos())
+	var sym *LSym
 	for sym = first; sym != nil; sym = sym.Next {
 		if !sym.Reachable {
 			continue
@@ -851,7 +786,9 @@
 		}
 	}
 
-	eaddr = int32(sect.Vaddr + sect.Length)
+	eaddr := int32(sect.Vaddr + sect.Length)
+	var r *Reloc
+	var ri int
 	for ; sym != nil; sym = sym.Next {
 		if !sym.Reachable {
 			continue
@@ -876,17 +813,15 @@
 }
 
 func Machoemitreloc() {
-	var sect *Section
-
 	for Cpos()&7 != 0 {
 		Cput(0)
 	}
 
 	machorelocsect(Segtext.Sect, Ctxt.Textp)
-	for sect = Segtext.Sect.Next; sect != nil; sect = sect.Next {
+	for sect := Segtext.Sect.Next; sect != nil; sect = sect.Next {
 		machorelocsect(sect, datap)
 	}
-	for sect = Segdata.Sect; sect != nil; sect = sect.Next {
+	for sect := Segdata.Sect; sect != nil; sect = sect.Next {
 		machorelocsect(sect, datap)
 	}
 }
diff --git a/src/cmd/internal/ld/objfile.go b/src/cmd/internal/ld/objfile.go
index 98b7ba6..34176be 100644
--- a/src/cmd/internal/ld/objfile.go
+++ b/src/cmd/internal/ld/objfile.go
@@ -12,28 +12,25 @@
 	"strings"
 )
 
-var startmagic string = "\x00\x00go13ld"
-
-var endmagic string = "\xff\xffgo13ld"
+const (
+	startmagic = "\x00\x00go13ld"
+	endmagic   = "\xff\xffgo13ld"
+)
 
 func ldobjfile(ctxt *Link, f *Biobuf, pkg string, length int64, pn string) {
-	var c int
-	var buf [8]uint8
-	var start int64
-	var lib string
-
-	start = Boffset(f)
+	start := Boffset(f)
 	ctxt.Version++
-	buf = [8]uint8{}
+	var buf [8]uint8
 	Bread(f, buf[:])
 	if string(buf[:]) != startmagic {
 		log.Fatalf("%s: invalid file start %x %x %x %x %x %x %x %x", pn, buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6], buf[7])
 	}
-	c = Bgetc(f)
+	c := Bgetc(f)
 	if c != 1 {
 		log.Fatalf("%s: invalid file version number %d", pn, c)
 	}
 
+	var lib string
 	for {
 		lib = rdstring(f)
 		if lib == "" {
@@ -65,45 +62,28 @@
 var readsym_ndup int
 
 func readsym(ctxt *Link, f *Biobuf, pkg string, pn string) {
-	var i int
-	var j int
-	var c int
-	var t int
-	var v int
-	var n int
-	var nreloc int
-	var size int
-	var dupok int
-	var name string
-	var data []byte
-	var r *Reloc
-	var s *LSym
-	var dup *LSym
-	var typ *LSym
-	var pc *Pcln
-	var a *Auto
-
 	if Bgetc(f) != 0xfe {
 		log.Fatalf("readsym out of sync")
 	}
-	t = int(rdint(f))
-	name = expandpkg(rdstring(f), pkg)
-	v = int(rdint(f))
+	t := int(rdint(f))
+	name := expandpkg(rdstring(f), pkg)
+	v := int(rdint(f))
 	if v != 0 && v != 1 {
 		log.Fatalf("invalid symbol version %d", v)
 	}
-	dupok = int(rdint(f))
+	dupok := int(rdint(f))
 	dupok &= 1
-	size = int(rdint(f))
-	typ = rdsym(ctxt, f, pkg)
+	size := int(rdint(f))
+	typ := rdsym(ctxt, f, pkg)
+	var data []byte
 	rddata(f, &data)
-	nreloc = int(rdint(f))
+	nreloc := int(rdint(f))
 
 	if v != 0 {
 		v = ctxt.Version
 	}
-	s = Linklookup(ctxt, name, v)
-	dup = nil
+	s := Linklookup(ctxt, name, v)
+	var dup *LSym
 	if s.Type != 0 && s.Type != SXREF {
 		if (t == SDATA || t == SBSS || t == SNOPTRBSS) && len(data) == 0 && nreloc == 0 {
 			if s.Size < int64(size) {
@@ -155,7 +135,8 @@
 	if nreloc > 0 {
 		s.R = make([]Reloc, nreloc)
 		s.R = s.R[:nreloc]
-		for i = 0; i < nreloc; i++ {
+		var r *Reloc
+		for i := 0; i < nreloc; i++ {
 			r = &s.R[i]
 			r.Off = int32(rdint(f))
 			r.Siz = uint8(rdint(f))
@@ -179,11 +160,12 @@
 		s.Args = int32(rdint(f))
 		s.Locals = int32(rdint(f))
 		s.Nosplit = uint8(rdint(f))
-		v = int(rdint(f))
+		v := int(rdint(f))
 		s.Leaf = uint8(v & 1)
 		s.Cfunc = uint8(v & 2)
-		n = int(rdint(f))
-		for i = 0; i < n; i++ {
+		n := int(rdint(f))
+		var a *Auto
+		for i := 0; i < n; i++ {
 			a = new(Auto)
 			a.Asym = rdsym(ctxt, f, pkg)
 			a.Aoffset = int32(rdint(f))
@@ -194,30 +176,30 @@
 		}
 
 		s.Pcln = new(Pcln)
-		pc = s.Pcln
+		pc := s.Pcln
 		rddata(f, &pc.Pcsp.P)
 		rddata(f, &pc.Pcfile.P)
 		rddata(f, &pc.Pcline.P)
 		n = int(rdint(f))
 		pc.Pcdata = make([]Pcdata, n)
 		pc.Npcdata = n
-		for i = 0; i < n; i++ {
+		for i := 0; i < n; i++ {
 			rddata(f, &pc.Pcdata[i].P)
 		}
 		n = int(rdint(f))
 		pc.Funcdata = make([]*LSym, n)
 		pc.Funcdataoff = make([]int64, n)
 		pc.Nfuncdata = n
-		for i = 0; i < n; i++ {
+		for i := 0; i < n; i++ {
 			pc.Funcdata[i] = rdsym(ctxt, f, pkg)
 		}
-		for i = 0; i < n; i++ {
+		for i := 0; i < n; i++ {
 			pc.Funcdataoff[i] = rdint(f)
 		}
 		n = int(rdint(f))
 		pc.File = make([]*LSym, n)
 		pc.Nfile = n
-		for i = 0; i < n; i++ {
+		for i := 0; i < n; i++ {
 			pc.File[i] = rdsym(ctxt, f, pkg)
 		}
 
@@ -257,7 +239,9 @@
 			fmt.Fprintf(ctxt.Bso, " args=%#x locals=%#x", uint64(s.Args), uint64(s.Locals))
 		}
 		fmt.Fprintf(ctxt.Bso, "\n")
-		for i = 0; i < len(s.P); {
+		var c int
+		var j int
+		for i := 0; i < len(s.P); {
 			fmt.Fprintf(ctxt.Bso, "\t%#04x", uint(i))
 			for j = i; j < i+16 && j < len(s.P); j++ {
 				fmt.Fprintf(ctxt.Bso, " %02x", s.P[j])
@@ -279,7 +263,8 @@
 			i += 16
 		}
 
-		for i = 0; i < len(s.R); i++ {
+		var r *Reloc
+		for i := 0; i < len(s.R); i++ {
 			r = &s.R[i]
 			fmt.Fprintf(ctxt.Bso, "\trel %d+%d t=%d %s+%d\n", int(r.Off), r.Siz, r.Type, r.Sym.Name, int64(r.Add))
 		}
@@ -288,11 +273,9 @@
 
 func rdint(f *Biobuf) int64 {
 	var c int
-	var uv uint64
-	var shift int
 
-	uv = 0
-	for shift = 0; ; shift += 7 {
+	uv := uint64(0)
+	for shift := 0; ; shift += 7 {
 		if shift >= 64 {
 			log.Fatalf("corrupt input")
 		}
@@ -322,12 +305,7 @@
 var symbuf []byte
 
 func rdsym(ctxt *Link, f *Biobuf, pkg string) *LSym {
-	var n int
-	var v int
-	var p string
-	var s *LSym
-
-	n = int(rdint(f))
+	n := int(rdint(f))
 	if n == 0 {
 		rdint(f)
 		return nil
@@ -337,25 +315,23 @@
 		symbuf = make([]byte, n)
 	}
 	Bread(f, symbuf[:n])
-	p = string(symbuf[:n])
-	v = int(rdint(f))
+	p := string(symbuf[:n])
+	v := int(rdint(f))
 	if v != 0 {
 		v = ctxt.Version
 	}
-	s = Linklookup(ctxt, expandpkg(p, pkg), v)
+	s := Linklookup(ctxt, expandpkg(p, pkg), v)
 
 	if v == 0 && s.Name[0] == '$' && s.Type == 0 {
 		if strings.HasPrefix(s.Name, "$f32.") {
-			var i32 int32
 			x, _ := strconv.ParseUint(s.Name[5:], 16, 32)
-			i32 = int32(x)
+			i32 := int32(x)
 			s.Type = SRODATA
 			Adduint32(ctxt, s, uint32(i32))
 			s.Reachable = false
 		} else if strings.HasPrefix(s.Name, "$f64.") || strings.HasPrefix(s.Name, "$i64.") {
-			var i64 int64
 			x, _ := strconv.ParseUint(s.Name[5:], 16, 64)
-			i64 = int64(x)
+			i64 := int64(x)
 			s.Type = SRODATA
 			Adduint64(ctxt, s, uint64(i64))
 			s.Reachable = false
diff --git a/src/cmd/internal/ld/pcln.go b/src/cmd/internal/ld/pcln.go
index 2900664..0250ca0 100644
--- a/src/cmd/internal/ld/pcln.go
+++ b/src/cmd/internal/ld/pcln.go
@@ -40,13 +40,9 @@
 // iteration over encoded pcdata tables.
 
 func getvarint(pp *[]byte) uint32 {
-	var p []byte
-	var shift int
-	var v uint32
-
-	v = 0
-	p = *pp
-	for shift = 0; ; shift += 7 {
+	v := uint32(0)
+	p := *pp
+	for shift := 0; ; shift += 7 {
 		v |= uint32(p[0]&0x7F) << uint(shift)
 		tmp4 := p
 		p = p[1:]
@@ -60,9 +56,6 @@
 }
 
 func pciternext(it *Pciter) {
-	var v uint32
-	var dv int32
-
 	it.pc = it.nextpc
 	if it.done != 0 {
 		return
@@ -73,7 +66,7 @@
 	}
 
 	// value delta
-	v = getvarint(&it.p)
+	v := getvarint(&it.p)
 
 	if v == 0 && it.start == 0 {
 		it.done = 1
@@ -81,7 +74,7 @@
 	}
 
 	it.start = 0
-	dv = int32(v>>1) ^ (int32(v<<31) >> 31)
+	dv := int32(v>>1) ^ (int32(v<<31) >> 31)
 	it.value += dv
 
 	// pc delta
@@ -107,12 +100,8 @@
 // license that can be found in the LICENSE file.
 
 func addvarint(d *Pcdata, val uint32) {
-	var n int32
-	var v uint32
-	var p []byte
-
-	n = 0
-	for v = val; v >= 0x80; v >>= 7 {
+	n := int32(0)
+	for v := val; v >= 0x80; v >>= 7 {
 		n++
 	}
 	n++
@@ -123,7 +112,8 @@
 	}
 	d.P = d.P[:old+int(n)]
 
-	p = d.P[old:]
+	p := d.P[old:]
+	var v uint32
 	for v = val; v >= 0x80; v >>= 7 {
 		p[0] = byte(v | 0x80)
 		p = p[1:]
@@ -132,9 +122,7 @@
 }
 
 func addpctab(ftab *LSym, off int32, d *Pcdata) int32 {
-	var start int32
-
-	start = int32(len(ftab.P))
+	start := int32(len(ftab.P))
 	Symgrow(Ctxt, ftab, int64(start)+int64(len(d.P)))
 	copy(ftab.P[start:], d.P)
 
@@ -142,29 +130,18 @@
 }
 
 func ftabaddstring(ftab *LSym, s string) int32 {
-	var n int32
-	var start int32
-
-	n = int32(len(s)) + 1
-	start = int32(len(ftab.P))
+	n := int32(len(s)) + 1
+	start := int32(len(ftab.P))
 	Symgrow(Ctxt, ftab, int64(start)+int64(n)+1)
 	copy(ftab.P[start:], s)
 	return start
 }
 
 func renumberfiles(ctxt *Link, files []*LSym, d *Pcdata) {
-	var i int
 	var f *LSym
-	var out Pcdata
-	var it Pciter
-	var v uint32
-	var oldval int32
-	var newval int32
-	var val int32
-	var dv int32
 
 	// Give files numbers.
-	for i = 0; i < len(files); i++ {
+	for i := 0; i < len(files); i++ {
 		f = files[i]
 		if f.Type != SFILEPATH {
 			ctxt.Nhistfile++
@@ -175,9 +152,14 @@
 		}
 	}
 
-	newval = -1
-	out = Pcdata{}
+	newval := int32(-1)
+	var out Pcdata
 
+	var dv int32
+	var it Pciter
+	var oldval int32
+	var v uint32
+	var val int32
 	for pciterinit(ctxt, &it, d); it.done == 0; pciternext(&it) {
 		// value delta
 		oldval = it.value
@@ -221,22 +203,8 @@
 var pclntab_zpcln Pcln
 
 func pclntab() {
-	var i int32
-	var nfunc int32
-	var start int32
-	var funcstart int32
-	var ftab *LSym
-	var s *LSym
-	var last *LSym
-	var off int32
-	var end int32
-	var frameptrsize int32
-	var funcdata_bytes int64
-	var pcln *Pcln
-	var it Pciter
-
-	funcdata_bytes = 0
-	ftab = Linklookup(Ctxt, "runtime.pclntab", 0)
+	funcdata_bytes := int64(0)
+	ftab := Linklookup(Ctxt, "runtime.pclntab", 0)
 	ftab.Type = SPCLNTAB
 	ftab.Reachable = true
 
@@ -246,7 +214,7 @@
 	//	function table, alternating PC and offset to func struct [each entry thearch.ptrsize bytes]
 	//	end PC [thearch.ptrsize bytes]
 	//	offset to file table [4 bytes]
-	nfunc = 0
+	nfunc := int32(0)
 
 	for Ctxt.Cursym = Ctxt.Textp; Ctxt.Cursym != nil; Ctxt.Cursym = Ctxt.Cursym.Next {
 		if container(Ctxt.Cursym) == 0 {
@@ -261,7 +229,13 @@
 	setuintxx(Ctxt, ftab, 8, uint64(nfunc), int64(Thearch.Ptrsize))
 
 	nfunc = 0
-	last = nil
+	var last *LSym
+	var end int32
+	var funcstart int32
+	var i int32
+	var it Pciter
+	var off int32
+	var pcln *Pcln
 	for Ctxt.Cursym = Ctxt.Textp; Ctxt.Cursym != nil; Ctxt.Cursym = Ctxt.Cursym.Next {
 		last = Ctxt.Cursym
 		if container(Ctxt.Cursym) != 0 {
@@ -298,17 +272,11 @@
 		off = int32(setuint32(Ctxt, ftab, int64(off), uint32(Ctxt.Cursym.Args)))
 
 		// frame int32
-		// TODO: Remove entirely. The pcsp table is more precise.
-		// This is only used by a fallback case during stack walking
-		// when a called function doesn't have argument information.
-		// We need to make sure everything has argument information
-		// and then remove this.
-		frameptrsize = int32(Thearch.Ptrsize)
-
-		if Ctxt.Cursym.Leaf != 0 {
-			frameptrsize = 0
-		}
-		off = int32(setuint32(Ctxt, ftab, int64(off), uint32(Ctxt.Cursym.Locals)+uint32(frameptrsize)))
+		// This has been removed (it was never set quite correctly anyway).
+		// Nothing should use it.
+		// Leave an obviously incorrect value.
+		// TODO: Remove entirely.
+		off = int32(setuint32(Ctxt, ftab, int64(off), 0x1234567))
 
 		if pcln != &pclntab_zpcln {
 			renumberfiles(Ctxt, pcln.File, &pcln.Pcfile)
@@ -366,14 +334,14 @@
 	setaddrplus(Ctxt, ftab, 8+int64(Thearch.Ptrsize)+int64(nfunc)*2*int64(Thearch.Ptrsize), last, last.Size)
 
 	// Start file table.
-	start = int32(len(ftab.P))
+	start := int32(len(ftab.P))
 
 	start += int32(-len(ftab.P)) & (int32(Thearch.Ptrsize) - 1)
 	setuint32(Ctxt, ftab, 8+int64(Thearch.Ptrsize)+int64(nfunc)*2*int64(Thearch.Ptrsize)+int64(Thearch.Ptrsize), uint32(start))
 
 	Symgrow(Ctxt, ftab, int64(start)+(int64(Ctxt.Nhistfile)+1)*4)
 	setuint32(Ctxt, ftab, int64(start), uint32(Ctxt.Nhistfile))
-	for s = Ctxt.Filesyms; s != nil; s = s.Next {
+	for s := Ctxt.Filesyms; s != nil; s = s.Next {
 		setuint32(Ctxt, ftab, int64(start)+s.Value*4, uint32(ftabaddstring(ftab, s.Name)))
 	}
 
@@ -394,43 +362,32 @@
 // findfunctab generates a lookup table to quickly find the containing
 // function for a pc.  See src/runtime/symtab.go:findfunc for details.
 func findfunctab() {
-	var t *LSym
-	var s *LSym
-	var e *LSym
-	var idx int32
-	var i int32
-	var j int32
-	var nbuckets int32
-	var n int32
-	var base int32
-	var min int64
-	var max int64
-	var p int64
-	var q int64
-	var indexes []int32
-
-	t = Linklookup(Ctxt, "runtime.findfunctab", 0)
+	t := Linklookup(Ctxt, "runtime.findfunctab", 0)
 	t.Type = SRODATA
 	t.Reachable = true
 
 	// find min and max address
-	min = Ctxt.Textp.Value
+	min := Ctxt.Textp.Value
 
-	max = 0
-	for s = Ctxt.Textp; s != nil; s = s.Next {
+	max := int64(0)
+	for s := Ctxt.Textp; s != nil; s = s.Next {
 		max = s.Value + s.Size
 	}
 
 	// for each subbucket, compute the minimum of all symbol indexes
 	// that map to that subbucket.
-	n = int32((max - min + SUBBUCKETSIZE - 1) / SUBBUCKETSIZE)
+	n := int32((max - min + SUBBUCKETSIZE - 1) / SUBBUCKETSIZE)
 
-	indexes = make([]int32, n)
-	for i = 0; i < n; i++ {
+	indexes := make([]int32, n)
+	for i := int32(0); i < n; i++ {
 		indexes[i] = NOIDX
 	}
-	idx = 0
-	for s = Ctxt.Textp; s != nil; s = s.Next {
+	idx := int32(0)
+	var e *LSym
+	var i int32
+	var p int64
+	var q int64
+	for s := Ctxt.Textp; s != nil; s = s.Next {
 		if container(s) != 0 {
 			continue
 		}
@@ -461,12 +418,14 @@
 	}
 
 	// allocate table
-	nbuckets = int32((max - min + BUCKETSIZE - 1) / BUCKETSIZE)
+	nbuckets := int32((max - min + BUCKETSIZE - 1) / BUCKETSIZE)
 
 	Symgrow(Ctxt, t, 4*int64(nbuckets)+int64(n))
 
 	// fill in table
-	for i = 0; i < nbuckets; i++ {
+	var base int32
+	var j int32
+	for i := int32(0); i < nbuckets; i++ {
 		base = indexes[i*SUBBUCKETS]
 		if base == NOIDX {
 			Diag("hole in findfunctab")
diff --git a/src/cmd/internal/ld/pe.go b/src/cmd/internal/ld/pe.go
index c2ef49f..53bf0af 100644
--- a/src/cmd/internal/ld/pe.go
+++ b/src/cmd/internal/ld/pe.go
@@ -8,6 +8,8 @@
 	"encoding/binary"
 	"fmt"
 	"sort"
+	"strconv"
+	"strings"
 )
 
 type IMAGE_FILE_HEADER struct {
@@ -95,8 +97,15 @@
 }
 
 const (
-	PEBASE      = 0x00400000
+	PEBASE = 0x00400000
+
+	// SectionAlignment must be greater than or equal to FileAlignment.
+	// The default is the page size for the architecture.
 	PESECTALIGN = 0x1000
+
+	// FileAlignment should be a power of 2 between 512 and 64 K, inclusive.
+	// The default is 512. If the SectionAlignment is less than
+	// the architecture's page size, then FileAlignment must match SectionAlignment.
 	PEFILEALIGN = 2 << 8
 )
 
@@ -105,6 +114,7 @@
 	IMAGE_FILE_MACHINE_AMD64             = 0x8664
 	IMAGE_FILE_RELOCS_STRIPPED           = 0x0001
 	IMAGE_FILE_EXECUTABLE_IMAGE          = 0x0002
+	IMAGE_FILE_LINE_NUMS_STRIPPED        = 0x0004
 	IMAGE_FILE_LARGE_ADDRESS_AWARE       = 0x0020
 	IMAGE_FILE_32BIT_MACHINE             = 0x0100
 	IMAGE_FILE_DEBUG_STRIPPED            = 0x0200
@@ -115,6 +125,8 @@
 	IMAGE_SCN_MEM_READ                   = 0x40000000
 	IMAGE_SCN_MEM_WRITE                  = 0x80000000
 	IMAGE_SCN_MEM_DISCARDABLE            = 0x2000000
+	IMAGE_SCN_LNK_NRELOC_OVFL            = 0x1000000
+	IMAGE_SCN_ALIGN_32BYTES              = 0x600000
 	IMAGE_DIRECTORY_ENTRY_EXPORT         = 0
 	IMAGE_DIRECTORY_ENTRY_IMPORT         = 1
 	IMAGE_DIRECTORY_ENTRY_RESOURCE       = 2
@@ -329,6 +341,8 @@
 
 var datasect int
 
+var bsssect int
+
 var fh IMAGE_FILE_HEADER
 
 var oh IMAGE_OPTIONAL_HEADER
@@ -340,9 +354,10 @@
 var dd []IMAGE_DATA_DIRECTORY
 
 type Imp struct {
-	s    *LSym
-	off  uint64
-	next *Imp
+	s       *LSym
+	off     uint64
+	next    *Imp
+	argsize int
 }
 
 type Dll struct {
@@ -364,6 +379,7 @@
 	strtbloff int
 	sect      int
 	value     int64
+	typ       uint16
 }
 
 var coffsym []COFFSym
@@ -371,14 +387,12 @@
 var ncoffsym int
 
 func addpesection(name string, sectsize int, filesize int) *IMAGE_SECTION_HEADER {
-	var h *IMAGE_SECTION_HEADER
-
 	if pensect == 16 {
 		Diag("too many sections")
 		Errorexit()
 	}
 
-	h = &sh[pensect]
+	h := &sh[pensect]
 	pensect++
 	copy(h.Name[:], name)
 	h.VirtualSize = uint32(sectsize)
@@ -423,7 +437,7 @@
 		l = binary.Size(&oh64)
 		dd = oh64.DataDirectory[:]
 
-		// 32-bit architectures
+	// 32-bit architectures
 	default:
 		l = binary.Size(&oh)
 
@@ -443,8 +457,10 @@
 
 func pewrite() {
 	Cseek(0)
-	Cwrite(dosstub)
-	strnput("PE", 4)
+	if Linkmode != LinkExternal {
+		Cwrite(dosstub)
+		strnput("PE", 4)
+	}
 
 	binary.Write(&coutbuf, binary.LittleEndian, &fh)
 
@@ -466,14 +482,11 @@
 }
 
 func initdynimport() *Dll {
-	var m *Imp
 	var d *Dll
-	var s *LSym
-	var dynamic *LSym
 
 	dr = nil
-	m = nil
-	for s = Ctxt.Allsym; s != nil; s = s.Allsym {
+	var m *Imp
+	for s := Ctxt.Allsym; s != nil; s = s.Allsym {
 		if !s.Reachable || s.Type != SDYNIMPORT {
 			continue
 		}
@@ -492,59 +505,104 @@
 			m = new(Imp)
 		}
 
+		// Because external link requires properly stdcall decorated name,
+		// all external symbols in runtime use %n to denote that the number
+		// of uinptrs this function consumes. Store the argsize and discard
+		// the %n suffix if any.
+		m.argsize = -1
+		if i := strings.IndexByte(s.Extname, '%'); i >= 0 {
+			var err error
+			m.argsize, err = strconv.Atoi(s.Extname[i+1:])
+			if err != nil {
+				Diag("failed to parse stdcall decoration: %v", err)
+			}
+			m.argsize *= Thearch.Ptrsize
+			s.Extname = s.Extname[:i]
+		}
+
 		m.s = s
 		m.next = d.ms
 		d.ms = m
 	}
 
-	dynamic = Linklookup(Ctxt, ".windynamic", 0)
-	dynamic.Reachable = true
-	dynamic.Type = SWINDOWS
-	for d = dr; d != nil; d = d.next {
-		for m = d.ms; m != nil; m = m.next {
-			m.s.Type = SWINDOWS | SSUB
-			m.s.Sub = dynamic.Sub
-			dynamic.Sub = m.s
-			m.s.Value = dynamic.Size
+	if Linkmode == LinkExternal {
+		// Add real symbol name
+		for d := dr; d != nil; d = d.next {
+			for m = d.ms; m != nil; m = m.next {
+				m.s.Type = SDATA
+				Symgrow(Ctxt, m.s, int64(Thearch.Ptrsize))
+				dynName := m.s.Extname
+				// only windows/386 requires stdcall decoration
+				if Thearch.Thechar == '8' && m.argsize >= 0 {
+					dynName += fmt.Sprintf("@%d", m.argsize)
+				}
+				dynSym := Linklookup(Ctxt, dynName, 0)
+				dynSym.Reachable = true
+				dynSym.Type = SHOSTOBJ
+				r := Addrel(m.s)
+				r.Sym = dynSym
+				r.Off = 0
+				r.Siz = uint8(Thearch.Ptrsize)
+				r.Type = R_ADDR
+
+				// pre-allocate symtab entries for those symbols
+				dynSym.Dynid = int32(ncoffsym)
+				ncoffsym++
+			}
+		}
+	} else {
+		dynamic := Linklookup(Ctxt, ".windynamic", 0)
+		dynamic.Reachable = true
+		dynamic.Type = SWINDOWS
+		for d := dr; d != nil; d = d.next {
+			for m = d.ms; m != nil; m = m.next {
+				m.s.Type = SWINDOWS | SSUB
+				m.s.Sub = dynamic.Sub
+				dynamic.Sub = m.s
+				m.s.Value = dynamic.Size
+				dynamic.Size += int64(Thearch.Ptrsize)
+			}
+
 			dynamic.Size += int64(Thearch.Ptrsize)
 		}
-
-		dynamic.Size += int64(Thearch.Ptrsize)
 	}
 
 	return dr
 }
 
-func addimports(datsect *IMAGE_SECTION_HEADER) {
-	var isect *IMAGE_SECTION_HEADER
-	var n uint64
-	var oftbase uint64
-	var ftbase uint64
-	var startoff int64
-	var endoff int64
-	var m *Imp
-	var d *Dll
-	var dynamic *LSym
+// peimporteddlls returns the gcc command line argument to link all imported
+// DLLs.
+func peimporteddlls() []string {
+	var dlls []string
 
-	startoff = Cpos()
-	dynamic = Linklookup(Ctxt, ".windynamic", 0)
+	for d := dr; d != nil; d = d.next {
+		dlls = append(dlls, "-l"+strings.TrimSuffix(d.name, ".dll"))
+	}
+
+	return dlls
+}
+
+func addimports(datsect *IMAGE_SECTION_HEADER) {
+	startoff := Cpos()
+	dynamic := Linklookup(Ctxt, ".windynamic", 0)
 
 	// skip import descriptor table (will write it later)
-	n = 0
+	n := uint64(0)
 
-	for d = dr; d != nil; d = d.next {
+	for d := dr; d != nil; d = d.next {
 		n++
 	}
 	Cseek(startoff + int64(binary.Size(&IMAGE_IMPORT_DESCRIPTOR{}))*int64(n+1))
 
 	// write dll names
-	for d = dr; d != nil; d = d.next {
+	for d := dr; d != nil; d = d.next {
 		d.nameoff = uint64(Cpos()) - uint64(startoff)
 		strput(d.name)
 	}
 
 	// write function names
-	for d = dr; d != nil; d = d.next {
+	var m *Imp
+	for d := dr; d != nil; d = d.next {
 		for m = d.ms; m != nil; m = m.next {
 			m.off = uint64(nextsectoff) + uint64(Cpos()) - uint64(startoff)
 			Wputl(0) // hint
@@ -553,10 +611,10 @@
 	}
 
 	// write OriginalFirstThunks
-	oftbase = uint64(Cpos()) - uint64(startoff)
+	oftbase := uint64(Cpos()) - uint64(startoff)
 
 	n = uint64(Cpos())
-	for d = dr; d != nil; d = d.next {
+	for d := dr; d != nil; d = d.next {
 		d.thunkoff = uint64(Cpos()) - n
 		for m = d.ms; m != nil; m = m.next {
 			if pe64 != 0 {
@@ -576,17 +634,17 @@
 	// add pe section and pad it at the end
 	n = uint64(Cpos()) - uint64(startoff)
 
-	isect = addpesection(".idata", int(n), int(n))
+	isect := addpesection(".idata", int(n), int(n))
 	isect.Characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE
 	chksectoff(isect, startoff)
 	strnput("", int(uint64(isect.SizeOfRawData)-n))
-	endoff = Cpos()
+	endoff := Cpos()
 
 	// write FirstThunks (allocated in .data section)
-	ftbase = uint64(dynamic.Value) - uint64(datsect.VirtualAddress) - PEBASE
+	ftbase := uint64(dynamic.Value) - uint64(datsect.VirtualAddress) - PEBASE
 
 	Cseek(int64(uint64(datsect.PointerToRawData) + ftbase))
-	for d = dr; d != nil; d = d.next {
+	for d := dr; d != nil; d = d.next {
 		for m = d.ms; m != nil; m = m.next {
 			if pe64 != 0 {
 				Vputl(m.off)
@@ -605,7 +663,7 @@
 	// finally write import descriptor table
 	Cseek(startoff)
 
-	for d = dr; d != nil; d = d.next {
+	for d := dr; d != nil; d = d.next {
 		Lputl(uint32(uint64(isect.VirtualAddress) + oftbase + d.thunkoff))
 		Lputl(0)
 		Lputl(0)
@@ -640,19 +698,14 @@
 }
 
 func (x pescmp) Less(i, j int) bool {
-	var s1 *LSym
-	var s2 *LSym
-
-	s1 = x[i]
-	s2 = x[j]
+	s1 := x[i]
+	s2 := x[j]
 	return stringsCompare(s1.Extname, s2.Extname) < 0
 }
 
 func initdynexport() {
-	var s *LSym
-
 	nexport = 0
-	for s = Ctxt.Allsym; s != nil; s = s.Allsym {
+	for s := Ctxt.Allsym; s != nil; s = s.Allsym {
 		if !s.Reachable || s.Cgoexport&CgoExportDynamic == 0 {
 			continue
 		}
@@ -669,18 +722,10 @@
 }
 
 func addexports() {
-	var sect *IMAGE_SECTION_HEADER
 	var e IMAGE_EXPORT_DIRECTORY
-	var size int
-	var i int
-	var va int
-	var va_name int
-	var va_addr int
-	var va_na int
-	var v int
 
-	size = binary.Size(&e) + 10*nexport + len(outfile) + 1
-	for i = 0; i < nexport; i++ {
+	size := binary.Size(&e) + 10*nexport + len(outfile) + 1
+	for i := 0; i < nexport; i++ {
 		size += len(dexport[i].Extname) + 1
 	}
 
@@ -688,16 +733,16 @@
 		return
 	}
 
-	sect = addpesection(".edata", size, size)
+	sect := addpesection(".edata", size, size)
 	sect.Characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ
 	chksectoff(sect, Cpos())
-	va = int(sect.VirtualAddress)
+	va := int(sect.VirtualAddress)
 	dd[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress = uint32(va)
 	dd[IMAGE_DIRECTORY_ENTRY_EXPORT].Size = sect.VirtualSize
 
-	va_name = va + binary.Size(&e) + nexport*4
-	va_addr = va + binary.Size(&e)
-	va_na = va + binary.Size(&e) + nexport*8
+	va_name := va + binary.Size(&e) + nexport*4
+	va_addr := va + binary.Size(&e)
+	va_na := va + binary.Size(&e) + nexport*8
 
 	e.Characteristics = 0
 	e.MajorVersion = 0
@@ -714,37 +759,147 @@
 	binary.Write(&coutbuf, binary.LittleEndian, &e)
 
 	// put EXPORT Address Table
-	for i = 0; i < nexport; i++ {
+	for i := 0; i < nexport; i++ {
 		Lputl(uint32(dexport[i].Value - PEBASE))
 	}
 
 	// put EXPORT Name Pointer Table
-	v = int(e.Name + uint32(len(outfile)) + 1)
+	v := int(e.Name + uint32(len(outfile)) + 1)
 
-	for i = 0; i < nexport; i++ {
+	for i := 0; i < nexport; i++ {
 		Lputl(uint32(v))
 		v += len(dexport[i].Extname) + 1
 	}
 
 	// put EXPORT Ordinal Table
-	for i = 0; i < nexport; i++ {
+	for i := 0; i < nexport; i++ {
 		Wputl(uint16(i))
 	}
 
 	// put Names
 	strnput(outfile, len(outfile)+1)
 
-	for i = 0; i < nexport; i++ {
+	for i := 0; i < nexport; i++ {
 		strnput(dexport[i].Extname, len(dexport[i].Extname)+1)
 	}
 	strnput("", int(sect.SizeOfRawData-uint32(size)))
 }
 
-func dope() {
-	var rel *LSym
+// perelocsect relocates symbols from first in section sect, and returns
+// the total number of relocations emitted.
+func perelocsect(sect *Section, first *LSym) int {
+	// If main section has no bits, nothing to relocate.
+	if sect.Vaddr >= sect.Seg.Vaddr+sect.Seg.Filelen {
+		return 0
+	}
 
+	relocs := 0
+
+	sect.Reloff = uint64(Cpos())
+	var sym *LSym
+	for sym = first; sym != nil; sym = sym.Next {
+		if !sym.Reachable {
+			continue
+		}
+		if uint64(sym.Value) >= sect.Vaddr {
+			break
+		}
+	}
+
+	eaddr := int32(sect.Vaddr + sect.Length)
+	var r *Reloc
+	var ri int
+	for ; sym != nil; sym = sym.Next {
+		if !sym.Reachable {
+			continue
+		}
+		if sym.Value >= int64(eaddr) {
+			break
+		}
+		Ctxt.Cursym = sym
+
+		for ri = 0; ri < len(sym.R); ri++ {
+			r = &sym.R[ri]
+			if r.Done != 0 {
+				continue
+			}
+			if r.Xsym == nil {
+				Diag("missing xsym in relocation")
+				continue
+			}
+
+			if r.Xsym.Dynid < 0 {
+				Diag("reloc %d to non-coff symbol %s (outer=%s) %d", r.Type, r.Sym.Name, r.Xsym.Name, r.Sym.Type)
+			}
+			if !Thearch.PEreloc1(r, int64(uint64(sym.Value+int64(r.Off))-PEBASE)) {
+				Diag("unsupported obj reloc %d/%d to %s", r.Type, r.Siz, r.Sym.Name)
+			}
+
+			relocs++
+		}
+	}
+
+	sect.Rellen = uint64(Cpos()) - sect.Reloff
+
+	return relocs
+}
+
+// peemitreloc emits relocation entries for go.o in external linking.
+func peemitreloc(text, data *IMAGE_SECTION_HEADER) {
+	for Cpos()&7 != 0 {
+		Cput(0)
+	}
+
+	text.PointerToRelocations = uint32(Cpos())
+	// first entry: extended relocs
+	Lputl(0) // placeholder for number of relocation + 1
+	Lputl(0)
+	Wputl(0)
+
+	n := perelocsect(Segtext.Sect, Ctxt.Textp) + 1
+	for sect := Segtext.Sect.Next; sect != nil; sect = sect.Next {
+		n += perelocsect(sect, datap)
+	}
+
+	cpos := Cpos()
+	Cseek(int64(text.PointerToRelocations))
+	Lputl(uint32(n))
+	Cseek(cpos)
+	if n > 0x10000 {
+		n = 0x10000
+		text.Characteristics |= IMAGE_SCN_LNK_NRELOC_OVFL
+	} else {
+		text.PointerToRelocations += 10 // skip the extend reloc entry
+	}
+	text.NumberOfRelocations = uint16(n - 1)
+
+	data.PointerToRelocations = uint32(cpos)
+	// first entry: extended relocs
+	Lputl(0) // placeholder for number of relocation + 1
+	Lputl(0)
+	Wputl(0)
+
+	n = 1
+	for sect := Segdata.Sect; sect != nil; sect = sect.Next {
+		n += perelocsect(sect, datap)
+	}
+
+	cpos = Cpos()
+	Cseek(int64(data.PointerToRelocations))
+	Lputl(uint32(n))
+	Cseek(cpos)
+	if n > 0x10000 {
+		n = 0x10000
+		data.Characteristics |= IMAGE_SCN_LNK_NRELOC_OVFL
+	} else {
+		data.PointerToRelocations += 10 // skip the extend reloc entry
+	}
+	data.NumberOfRelocations = uint16(n - 1)
+}
+
+func dope() {
 	/* relocation table */
-	rel = Linklookup(Ctxt, ".rel", 0)
+	rel := Linklookup(Ctxt, ".rel", 0)
 
 	rel.Reachable = true
 	rel.Type = SELFROSECT
@@ -768,30 +923,24 @@
  * <http://www.microsoft.com/whdc/system/platform/firmware/PECOFFdwn.mspx>
  */
 func newPEDWARFSection(name string, size int64) *IMAGE_SECTION_HEADER {
-	var h *IMAGE_SECTION_HEADER
-	var s string
-	var off int
-
 	if size == 0 {
 		return nil
 	}
 
-	off = strtbladd(name)
-	s = fmt.Sprintf("/%d", off)
-	h = addpesection(s, int(size), int(size))
+	off := strtbladd(name)
+	s := fmt.Sprintf("/%d", off)
+	h := addpesection(s, int(size), int(size))
 	h.Characteristics = IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_DISCARDABLE
 
 	return h
 }
 
 func addpesym(s *LSym, name string, type_ int, addr int64, size int64, ver int, gotype *LSym) {
-	var cs *COFFSym
-
 	if s == nil {
 		return
 	}
 
-	if s.Sect == nil {
+	if s.Sect == nil && type_ != 'U' {
 		return
 	}
 
@@ -799,24 +948,34 @@
 	default:
 		return
 
-	case 'D',
-		'B',
-		'T':
+	case 'D', 'B', 'T', 'U':
 		break
 	}
 
 	if coffsym != nil {
-		cs = &coffsym[ncoffsym]
+		// only windows/386 requires underscore prefix on external symbols
+		if Thearch.Thechar == '8' && Linkmode == LinkExternal && (s.Type == SHOSTOBJ || s.Cgoexport != 0) && s.Name == s.Extname {
+			s.Name = "_" + s.Name
+		}
+		cs := &coffsym[ncoffsym]
 		cs.sym = s
 		if len(s.Name) > 8 {
 			cs.strtbloff = strtbladd(s.Name)
 		}
-		if uint64(s.Value) >= Segdata.Vaddr {
+		// Note: although address of runtime.edata (type SDATA) is at the start of .bss section
+		// it still belongs to the .data section, not the .bss section.
+		if uint64(s.Value) >= Segdata.Vaddr+Segdata.Filelen && s.Type != SDATA && Linkmode == LinkExternal {
+			cs.value = int64(uint64(s.Value) - Segdata.Vaddr - Segdata.Filelen)
+			cs.sect = bsssect
+		} else if uint64(s.Value) >= Segdata.Vaddr {
 			cs.value = int64(uint64(s.Value) - Segdata.Vaddr)
 			cs.sect = datasect
 		} else if uint64(s.Value) >= Segtext.Vaddr {
 			cs.value = int64(uint64(s.Value) - Segtext.Vaddr)
 			cs.sect = textsect
+		} else if type_ == 'U' {
+			cs.value = 0
+			cs.typ = IMAGE_SYM_DTYPE_FUNCTION
 		} else {
 			cs.value = 0
 			cs.sect = 0
@@ -824,31 +983,41 @@
 		}
 	}
 
+	s.Dynid = int32(ncoffsym)
 	ncoffsym++
 }
 
 func addpesymtable() {
-	var h *IMAGE_SECTION_HEADER
-	var i int
-	var size int
-	var s *COFFSym
-
 	if Debug['s'] == 0 {
 		genasmsym(addpesym)
 		coffsym = make([]COFFSym, ncoffsym)
 		ncoffsym = 0
+		if Linkmode == LinkExternal {
+			for d := dr; d != nil; d = d.next {
+				for m := d.ms; m != nil; m = m.next {
+					s := m.s.R[0].Xsym
+					addpesym(s, s.Name, 'U', 0, int64(Thearch.Ptrsize), 0, nil)
+				}
+			}
+		}
 		genasmsym(addpesym)
 	}
+	size := len(strtbl) + 4 + 18*ncoffsym
 
-	size = len(strtbl) + 4 + 18*ncoffsym
-	h = addpesection(".symtab", size, size)
-	h.Characteristics = IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_DISCARDABLE
-	chksectoff(h, Cpos())
+	var h *IMAGE_SECTION_HEADER
+	if Linkmode != LinkExternal {
+		// We do not really need .symtab for go.o, and if we have one, ld
+		// will also include it in the exe, and that will confuse windows.
+		h = addpesection(".symtab", size, size)
+		h.Characteristics = IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_DISCARDABLE
+		chksectoff(h, Cpos())
+	}
 	fh.PointerToSymbolTable = uint32(Cpos())
 	fh.NumberOfSymbols = uint32(ncoffsym)
 
 	// put COFF symbol table
-	for i = 0; i < ncoffsym; i++ {
+	var s *COFFSym
+	for i := 0; i < ncoffsym; i++ {
 		s = &coffsym[i]
 		if s.strtbloff == 0 {
 			strnput(s.sym.Name, 8)
@@ -859,18 +1028,26 @@
 
 		Lputl(uint32(s.value))
 		Wputl(uint16(s.sect))
-		Wputl(0x0308) // "array of structs"
-		Cput(2)       // storage class: external
-		Cput(0)       // no aux entries
+		if s.typ != 0 {
+			Wputl(s.typ)
+		} else if Linkmode == LinkExternal {
+			Wputl(0)
+		} else {
+			Wputl(0x0308) // "array of structs"
+		}
+		Cput(2) // storage class: external
+		Cput(0) // no aux entries
 	}
 
 	// put COFF string table
 	Lputl(uint32(len(strtbl)) + 4)
 
-	for i = 0; i < len(strtbl); i++ {
+	for i := 0; i < len(strtbl); i++ {
 		Cput(uint8(strtbl[i]))
 	}
-	strnput("", int(h.SizeOfRawData-uint32(size)))
+	if Linkmode != LinkExternal {
+		strnput("", int(h.SizeOfRawData-uint32(size)))
+	}
 }
 
 func setpersrc(sym *LSym) {
@@ -882,22 +1059,19 @@
 }
 
 func addpersrc() {
-	var h *IMAGE_SECTION_HEADER
-	var p []byte
-	var val uint32
-	var r *Reloc
-	var ri int
-
 	if rsrcsym == nil {
 		return
 	}
 
-	h = addpesection(".rsrc", int(rsrcsym.Size), int(rsrcsym.Size))
+	h := addpesection(".rsrc", int(rsrcsym.Size), int(rsrcsym.Size))
 	h.Characteristics = IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE | IMAGE_SCN_CNT_INITIALIZED_DATA
 	chksectoff(h, Cpos())
 
 	// relocation
-	for ri = 0; ri < len(rsrcsym.R); ri++ {
+	var p []byte
+	var r *Reloc
+	var val uint32
+	for ri := 0; ri < len(rsrcsym.R); ri++ {
 		r = &rsrcsym.R[ri]
 		p = rsrcsym.P[r.Off:]
 		val = uint32(int64(h.VirtualAddress) + r.Add)
@@ -920,9 +1094,6 @@
 }
 
 func Asmbpe() {
-	var t *IMAGE_SECTION_HEADER
-	var d *IMAGE_SECTION_HEADER
-
 	switch Thearch.Thechar {
 	default:
 		Diag("unknown PE architecture")
@@ -936,25 +1107,43 @@
 		fh.Machine = IMAGE_FILE_MACHINE_I386
 	}
 
-	t = addpesection(".text", int(Segtext.Length), int(Segtext.Length))
+	t := addpesection(".text", int(Segtext.Length), int(Segtext.Length))
 	t.Characteristics = IMAGE_SCN_CNT_CODE | IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_READ
 	chksectseg(t, &Segtext)
 	textsect = pensect
 
-	d = addpesection(".data", int(Segdata.Length), int(Segdata.Filelen))
-	d.Characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE
-	chksectseg(d, &Segdata)
-	datasect = pensect
+	var d *IMAGE_SECTION_HEADER
+	if Linkmode != LinkExternal {
+		d = addpesection(".data", int(Segdata.Length), int(Segdata.Filelen))
+		d.Characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE
+		chksectseg(d, &Segdata)
+		datasect = pensect
+	} else {
+		d = addpesection(".data", int(Segdata.Filelen), int(Segdata.Filelen))
+		d.Characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE | IMAGE_SCN_ALIGN_32BYTES
+		chksectseg(d, &Segdata)
+		datasect = pensect
+
+		b := addpesection(".bss", int(Segdata.Length-Segdata.Filelen), 0)
+		b.Characteristics = IMAGE_SCN_CNT_UNINITIALIZED_DATA | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE | IMAGE_SCN_ALIGN_32BYTES
+		b.PointerToRawData = 0
+		bsssect = pensect
+	}
 
 	if Debug['s'] == 0 {
 		dwarfaddpeheaders()
 	}
 
 	Cseek(int64(nextfileoff))
-	addimports(d)
-	addexports()
+	if Linkmode != LinkExternal {
+		addimports(d)
+		addexports()
+	}
 	addpesymtable()
 	addpersrc()
+	if Linkmode == LinkExternal {
+		peemitreloc(t, d)
+	}
 
 	fh.NumberOfSections = uint16(pensect)
 
@@ -962,11 +1151,15 @@
 	// much more beneficial than having build timestamp in the header.
 	fh.TimeDateStamp = 0
 
-	fh.Characteristics = IMAGE_FILE_RELOCS_STRIPPED | IMAGE_FILE_EXECUTABLE_IMAGE | IMAGE_FILE_DEBUG_STRIPPED
+	if Linkmode == LinkExternal {
+		fh.Characteristics = IMAGE_FILE_LINE_NUMS_STRIPPED
+	} else {
+		fh.Characteristics = IMAGE_FILE_RELOCS_STRIPPED | IMAGE_FILE_EXECUTABLE_IMAGE | IMAGE_FILE_DEBUG_STRIPPED
+	}
 	if pe64 != 0 {
 		fh.SizeOfOptionalHeader = uint16(binary.Size(&oh64))
 		fh.Characteristics |= IMAGE_FILE_LARGE_ADDRESS_AWARE
-		oh64.Magic = 0x20b
+		oh64.Magic = 0x20b // PE32+
 	} else {
 		fh.SizeOfOptionalHeader = uint16(binary.Size(&oh))
 		fh.Characteristics |= IMAGE_FILE_32BIT_MACHINE
@@ -986,8 +1179,10 @@
 	oh.SizeOfInitializedData = d.SizeOfRawData
 	oh64.SizeOfUninitializedData = 0
 	oh.SizeOfUninitializedData = 0
-	oh64.AddressOfEntryPoint = uint32(Entryvalue() - PEBASE)
-	oh.AddressOfEntryPoint = uint32(Entryvalue() - PEBASE)
+	if Linkmode != LinkExternal {
+		oh64.AddressOfEntryPoint = uint32(Entryvalue() - PEBASE)
+		oh.AddressOfEntryPoint = uint32(Entryvalue() - PEBASE)
+	}
 	oh64.BaseOfCode = t.VirtualAddress
 	oh.BaseOfCode = t.VirtualAddress
 	oh64.ImageBase = PEBASE
diff --git a/src/cmd/internal/ld/pobj.go b/src/cmd/internal/ld/pobj.go
index 226ccf1..221f2b0 100644
--- a/src/cmd/internal/ld/pobj.go
+++ b/src/cmd/internal/ld/pobj.go
@@ -40,10 +40,6 @@
 
 // Reading object files.
 
-var noname string = "<none>"
-
-var paramspace string = "FP"
-
 func Ldmain() {
 	Ctxt = linknew(Thelinkarch)
 	Ctxt.Thechar = int32(Thearch.Thechar)
@@ -189,7 +185,6 @@
 	checkgo()
 	deadcode()
 	callgraph()
-	paramspace = "SP" /* (FP) now (SP) on output */
 
 	doelf()
 	if HEADTYPE == Hdarwin {
diff --git a/src/cmd/internal/ld/sym.go b/src/cmd/internal/ld/sym.go
index 7e275a6..d0a80e6 100644
--- a/src/cmd/internal/ld/sym.go
+++ b/src/cmd/internal/ld/sym.go
@@ -63,21 +63,18 @@
 }
 
 func linknew(arch *LinkArch) *Link {
-	var ctxt *Link
-	var p string
-	var buf string
-
-	ctxt = new(Link)
+	ctxt := new(Link)
 	ctxt.Hash = make(map[symVer]*LSym)
 	ctxt.Arch = arch
 	ctxt.Version = HistVersion
 	ctxt.Goroot = obj.Getgoroot()
 
-	p = obj.Getgoarch()
+	p := obj.Getgoarch()
 	if p != arch.Name {
 		log.Fatalf("invalid goarch %s (want %s)", p, arch.Name)
 	}
 
+	var buf string
 	buf, _ = os.Getwd()
 	if buf == "" {
 		buf = "/???"
@@ -95,8 +92,7 @@
 	default:
 		log.Fatalf("unknown thread-local storage offset for %s", Headstr(ctxt.Headtype))
 
-	case Hplan9,
-		Hwindows:
+	case Hplan9, Hwindows:
 		break
 
 		/*
@@ -110,7 +106,7 @@
 		Hopenbsd,
 		Hdragonfly,
 		Hsolaris:
-		ctxt.Tlsoffset = -2 * ctxt.Arch.Ptrsize
+		ctxt.Tlsoffset = -1 * ctxt.Arch.Ptrsize
 
 	case Hnacl:
 		switch ctxt.Arch.Thechar {
@@ -149,7 +145,7 @@
 
 	// On arm, record goarm.
 	if ctxt.Arch.Thechar == '5' {
-		p = obj.Getgoarm()
+		p := obj.Getgoarm()
 		if p != "" {
 			ctxt.Goarm = int32(obj.Atoi(p))
 		} else {
@@ -161,9 +157,7 @@
 }
 
 func linknewsym(ctxt *Link, symb string, v int) *LSym {
-	var s *LSym
-
-	s = new(LSym)
+	s := new(LSym)
 	*s = LSym{}
 
 	s.Dynid = -1
@@ -173,7 +167,6 @@
 	s.Type = 0
 	s.Version = int16(v)
 	s.Value = 0
-	s.Sig = 0
 	s.Size = 0
 	ctxt.Nsymbol++
 
@@ -215,9 +208,7 @@
 var headstr_buf string
 
 func Headstr(v int) string {
-	var i int
-
-	for i = 0; i < len(headers); i++ {
+	for i := 0; i < len(headers); i++ {
 		if v == headers[i].val {
 			return headers[i].name
 		}
@@ -227,9 +218,7 @@
 }
 
 func headtype(name string) int {
-	var i int
-
-	for i = 0; i < len(headers); i++ {
+	for i := 0; i < len(headers); i++ {
 		if name == headers[i].name {
 			return headers[i].val
 		}
diff --git a/src/cmd/internal/ld/symtab.go b/src/cmd/internal/ld/symtab.go
index 997300c..d667d1c 100644
--- a/src/cmd/internal/ld/symtab.go
+++ b/src/cmd/internal/ld/symtab.go
@@ -34,12 +34,7 @@
 
 // Symbol table.
 
-var maxelfstr int
-
 func putelfstr(s string) int {
-	var off int
-	var n int
-
 	if len(Elfstrdat) == 0 && s != "" {
 		// first entry must be empty string
 		putelfstr("")
@@ -48,12 +43,12 @@
 	// Rewrite · to . for ASCII-only tools like DTrace (sigh)
 	s = strings.Replace(s, "·", ".", -1)
 
-	n = len(s) + 1
+	n := len(s) + 1
 	for len(Elfstrdat)+n > cap(Elfstrdat) {
 		Elfstrdat = append(Elfstrdat[:cap(Elfstrdat)], 0)[:len(Elfstrdat)]
 	}
 
-	off = len(Elfstrdat)
+	off := len(Elfstrdat)
 	Elfstrdat = Elfstrdat[:off+n]
 	copy(Elfstrdat[off:], s)
 
@@ -62,8 +57,7 @@
 
 func putelfsyment(off int, addr int64, size int64, info int, shndx int, other int) {
 	switch Thearch.Thechar {
-	case '6',
-		'9':
+	case '6', '7', '9':
 		Thearch.Lput(uint32(off))
 		Cput(uint8(info))
 		Cput(uint8(other))
@@ -88,11 +82,7 @@
 var elfbind int
 
 func putelfsym(x *LSym, s string, t int, addr int64, size int64, ver int, go_ *LSym) {
-	var bind int
 	var type_ int
-	var off int
-	var other int
-	var xo *LSym
 
 	switch t {
 	default:
@@ -106,27 +96,39 @@
 
 	case 'B':
 		type_ = STT_OBJECT
+
+	case 'U':
+		type_ = STT_NOTYPE
+
+	case 't':
+		type_ = STT_TLS
 	}
 
-	xo = x
+	xo := x
 	for xo.Outer != nil {
 		xo = xo.Outer
 	}
-	if xo.Sect == nil {
-		Ctxt.Cursym = x
-		Diag("missing section in putelfsym")
-		return
-	}
 
-	if (xo.Sect.(*Section)).Elfsect == nil {
-		Ctxt.Cursym = x
-		Diag("missing ELF section in putelfsym")
-		return
+	var elfshnum int
+	if xo.Type == SDYNIMPORT || xo.Type == SHOSTOBJ {
+		elfshnum = SHN_UNDEF
+	} else {
+		if xo.Sect == nil {
+			Ctxt.Cursym = x
+			Diag("missing section in putelfsym")
+			return
+		}
+		if (xo.Sect.(*Section)).Elfsect == nil {
+			Ctxt.Cursym = x
+			Diag("missing ELF section in putelfsym")
+			return
+		}
+		elfshnum = ((xo.Sect.(*Section)).Elfsect.(*ElfShdr)).shnum
 	}
 
 	// One pass for each binding: STB_LOCAL, STB_GLOBAL,
 	// maybe one day STB_WEAK.
-	bind = STB_GLOBAL
+	bind := STB_GLOBAL
 
 	if ver != 0 || (x.Type&SHIDDEN != 0) {
 		bind = STB_LOCAL
@@ -136,7 +138,7 @@
 	// to get the exported symbols put into the dynamic symbol table.
 	// To avoid filling the dynamic table with lots of unnecessary symbols,
 	// mark all Go symbols local (not global) in the final executable.
-	if Linkmode == LinkExternal && x.Cgoexport&CgoExportStatic == 0 {
+	if Linkmode == LinkExternal && x.Cgoexport&CgoExportStatic == 0 && elfshnum != SHN_UNDEF {
 		bind = STB_LOCAL
 	}
 
@@ -144,15 +146,15 @@
 		return
 	}
 
-	off = putelfstr(s)
-	if Linkmode == LinkExternal {
+	off := putelfstr(s)
+	if Linkmode == LinkExternal && elfshnum != SHN_UNDEF {
 		addr -= int64((xo.Sect.(*Section)).Vaddr)
 	}
-	other = 2
+	other := STV_DEFAULT
 	if x.Type&SHIDDEN != 0 {
-		other = 0
+		other = STV_HIDDEN
 	}
-	putelfsyment(off, addr, size, bind<<4|type_&0xf, ((xo.Sect.(*Section)).Elfsect.(*ElfShdr)).shnum, other)
+	putelfsyment(off, addr, size, bind<<4|type_&0xf, elfshnum, other)
 	x.Elfsym = int32(numelfsym)
 	numelfsym++
 }
@@ -164,9 +166,7 @@
 }
 
 func putelfsymshndx(sympos int64, shndx int) {
-	var here int64
-
-	here = Cpos()
+	here := Cpos()
 	switch Thearch.Thechar {
 	case '6':
 		Cseek(sympos + 6)
@@ -180,9 +180,6 @@
 }
 
 func Asmelfsym() {
-	var s *LSym
-	var name string
-
 	// the first symbol entry is reserved
 	putelfsyment(0, 0, 0, STB_LOCAL<<4|STT_NOTYPE, 0, 0)
 
@@ -191,53 +188,14 @@
 	elfbind = STB_LOCAL
 	genasmsym(putelfsym)
 
-	if Linkmode == LinkExternal && HEADTYPE != Hopenbsd {
-		s = Linklookup(Ctxt, "runtime.tlsg", 0)
-		if s.Sect == nil {
-			Ctxt.Cursym = nil
-			Diag("missing section for %s", s.Name)
-			Errorexit()
-		}
-
-		if goos == "android" {
-			// Android emulates runtime.tlsg as a regular variable.
-			putelfsyment(putelfstr(s.Name), 0, s.Size, STB_LOCAL<<4|STT_OBJECT, ((s.Sect.(*Section)).Elfsect.(*ElfShdr)).shnum, 0)
-		} else {
-			putelfsyment(putelfstr(s.Name), 0, s.Size, STB_LOCAL<<4|STT_TLS, ((s.Sect.(*Section)).Elfsect.(*ElfShdr)).shnum, 0)
-		}
-
-		s.Elfsym = int32(numelfsym)
-		numelfsym++
-	}
-
 	elfbind = STB_GLOBAL
 	elfglobalsymndx = numelfsym
 	genasmsym(putelfsym)
-
-	for s = Ctxt.Allsym; s != nil; s = s.Allsym {
-		if s.Type != SHOSTOBJ && (s.Type != SDYNIMPORT || !s.Reachable) {
-			continue
-		}
-		if s.Type == SDYNIMPORT {
-			name = s.Extname
-		} else {
-			name = s.Name
-		}
-		putelfsyment(putelfstr(name), 0, 0, STB_GLOBAL<<4|STT_NOTYPE, 0, 0)
-		s.Elfsym = int32(numelfsym)
-		numelfsym++
-	}
 }
 
 func putplan9sym(x *LSym, s string, t int, addr int64, size int64, ver int, go_ *LSym) {
-	var i int
-	var l int
-
 	switch t {
-	case 'T',
-		'L',
-		'D',
-		'B':
+	case 'T', 'L', 'D', 'B':
 		if ver != 0 {
 			t += 'a' - 'A'
 		}
@@ -249,7 +207,7 @@
 		'z',
 		'Z',
 		'm':
-		l = 4
+		l := 4
 		if HEADTYPE == Hplan9 && Thearch.Thechar == '6' && Debug['8'] == 0 {
 			Lputb(uint32(addr >> 32))
 			l = 8
@@ -258,6 +216,7 @@
 		Lputb(uint32(addr))
 		Cput(uint8(t + 0x80)) /* 0x80 is variable length */
 
+		var i int
 		if t == 'z' || t == 'Z' {
 			Cput(uint8(s[0]))
 			for i = 1; s[i] != 0 || s[i+1] != 0; i += 2 {
@@ -327,12 +286,6 @@
 }
 
 func symtab() {
-	var s *LSym
-	var symtype *LSym
-	var symtypelink *LSym
-	var symgostring *LSym
-	var symgofunc *LSym
-
 	dosymtype()
 
 	// Define these so that they'll get put into the symbol table.
@@ -357,7 +310,7 @@
 	xdefine("runtime.esymtab", SRODATA, 0)
 
 	// garbage collection symbols
-	s = Linklookup(Ctxt, "runtime.gcdata", 0)
+	s := Linklookup(Ctxt, "runtime.gcdata", 0)
 
 	s.Type = SRODATA
 	s.Size = 0
@@ -376,21 +329,21 @@
 	s.Type = STYPE
 	s.Size = 0
 	s.Reachable = true
-	symtype = s
+	symtype := s
 
 	s = Linklookup(Ctxt, "go.string.*", 0)
 	s.Type = SGOSTRING
 	s.Size = 0
 	s.Reachable = true
-	symgostring = s
+	symgostring := s
 
 	s = Linklookup(Ctxt, "go.func.*", 0)
 	s.Type = SGOFUNC
 	s.Size = 0
 	s.Reachable = true
-	symgofunc = s
+	symgofunc := s
 
-	symtypelink = Linklookup(Ctxt, "runtime.typelink", 0)
+	symtypelink := Linklookup(Ctxt, "runtime.typelink", 0)
 
 	symt = Linklookup(Ctxt, "runtime.symtab", 0)
 	symt.Type = SSYMTAB
@@ -401,7 +354,7 @@
 	// within a type they sort by size, so the .* symbols
 	// just defined above will be first.
 	// hide the specific symbols.
-	for s = Ctxt.Allsym; s != nil; s = s.Allsym {
+	for s := Ctxt.Allsym; s != nil; s = s.Allsym {
 		if !s.Reachable || s.Special != 0 || s.Type != SRODATA {
 			continue
 		}
@@ -437,4 +390,38 @@
 			liveness += (s.Size + int64(s.Align) - 1) &^ (int64(s.Align) - 1)
 		}
 	}
+
+	// Information about the layout of the executable image for the
+	// runtime to use. Any changes here must be matched by changes to
+	// the definition of moduledata in runtime/symtab.go.
+	moduledata := Linklookup(Ctxt, "runtime.themoduledata", 0)
+	moduledata.Type = SNOPTRDATA
+	moduledata.Size = 0 // truncate symbol back to 0 bytes to reinitialize
+	moduledata.Reachable = true
+	// Three slices (pclntable, ftab, filetab), uninitalized
+	moduledata.Size += int64((3 * 3 * Thearch.Ptrsize))
+	Symgrow(Ctxt, moduledata, moduledata.Size)
+	// Three uintptrs, initialized
+	Addaddr(Ctxt, moduledata, Linklookup(Ctxt, "runtime.pclntab", 0))
+	Addaddr(Ctxt, moduledata, Linklookup(Ctxt, "runtime.epclntab", 0))
+	Addaddr(Ctxt, moduledata, Linklookup(Ctxt, "runtime.findfunctab", 0))
+	// 2 more uintptrs (minpc, maxpc), uninitalized
+	moduledata.Size += int64(2 * Thearch.Ptrsize)
+	Symgrow(Ctxt, moduledata, moduledata.Size)
+	// more initialized uintptrs
+	Addaddr(Ctxt, moduledata, Linklookup(Ctxt, "runtime.text", 0))
+	Addaddr(Ctxt, moduledata, Linklookup(Ctxt, "runtime.etext", 0))
+	Addaddr(Ctxt, moduledata, Linklookup(Ctxt, "runtime.noptrdata", 0))
+	Addaddr(Ctxt, moduledata, Linklookup(Ctxt, "runtime.enoptrdata", 0))
+	Addaddr(Ctxt, moduledata, Linklookup(Ctxt, "runtime.data", 0))
+	Addaddr(Ctxt, moduledata, Linklookup(Ctxt, "runtime.edata", 0))
+	Addaddr(Ctxt, moduledata, Linklookup(Ctxt, "runtime.bss", 0))
+	Addaddr(Ctxt, moduledata, Linklookup(Ctxt, "runtime.ebss", 0))
+	Addaddr(Ctxt, moduledata, Linklookup(Ctxt, "runtime.noptrbss", 0))
+	Addaddr(Ctxt, moduledata, Linklookup(Ctxt, "runtime.enoptrbss", 0))
+	Addaddr(Ctxt, moduledata, Linklookup(Ctxt, "runtime.end", 0))
+	Addaddr(Ctxt, moduledata, Linklookup(Ctxt, "runtime.gcdata", 0))
+	Addaddr(Ctxt, moduledata, Linklookup(Ctxt, "runtime.gcbss", 0))
+	Addaddr(Ctxt, moduledata, Linklookup(Ctxt, "runtime.typelink", 0))
+	Addaddr(Ctxt, moduledata, Linklookup(Ctxt, "runtime.etypelink", 0))
 }
diff --git a/src/cmd/internal/ld/util.go b/src/cmd/internal/ld/util.go
index 9a56f09..8c37cab 100644
--- a/src/cmd/internal/ld/util.go
+++ b/src/cmd/internal/ld/util.go
@@ -26,17 +26,14 @@
 
 func plan9quote(s string) string {
 	if s == "" {
-		goto needquote
+		return "'" + strings.Replace(s, "'", "''", -1) + "'"
 	}
 	for i := 0; i < len(s); i++ {
 		if s[i] <= ' ' || s[i] == '\'' {
-			goto needquote
+			return "'" + strings.Replace(s, "'", "''", -1) + "'"
 		}
 	}
 	return s
-
-needquote:
-	return "'" + strings.Replace(s, "'", "''", -1) + "'"
 }
 
 func tokenize(s string) []string {
diff --git a/src/cmd/internal/ld/z.go b/src/cmd/internal/ld/z.go
deleted file mode 100644
index 7330ae2..0000000
--- a/src/cmd/internal/ld/z.go
+++ /dev/null
@@ -1 +0,0 @@
-package ld
diff --git a/src/cmd/internal/obj/arm/5.out.go b/src/cmd/internal/obj/arm/5.out.go
index d4b0170..1cb561d 100644
--- a/src/cmd/internal/obj/arm/5.out.go
+++ b/src/cmd/internal/obj/arm/5.out.go
@@ -32,8 +32,7 @@
 
 import "cmd/internal/obj"
 
-// TODO(ality): remove this workaround.
-//   It's here because Pconv in liblink/list?.c references %L.
+//go:generate go run ../stringer.go -i $GOFILE -o anames.go -p arm
 
 const (
 	NSNAME = 8
@@ -47,7 +46,7 @@
 )
 
 const (
-	REG_R0 = obj.RBaseARM + iota
+	REG_R0 = obj.RBaseARM + iota // must be 16-aligned
 	REG_R1
 	REG_R2
 	REG_R3
@@ -63,7 +62,8 @@
 	REG_R13
 	REG_R14
 	REG_R15
-	REG_F0
+
+	REG_F0 // must be 16-aligned
 	REG_F1
 	REG_F2
 	REG_F3
@@ -79,28 +79,37 @@
 	REG_F13
 	REG_F14
 	REG_F15
-	REG_FPSR
+
+	REG_FPSR // must be 2-aligned
 	REG_FPCR
-	REG_CPSR
+
+	REG_CPSR // must be 2-aligned
 	REG_SPSR
+
 	MAXREG
-	REGRET  = REG_R0
-	REGEXT  = REG_R10
-	REGG    = REGEXT - 0
-	REGM    = REGEXT - 1
+	REGRET = REG_R0
+	/* compiler allocates R1 up as temps */
+	/* compiler allocates register variables R3 up */
+	/* compiler allocates external registers R10 down */
+	REGEXT = REG_R10
+	/* these two registers are declared in runtime.h */
+	REGG = REGEXT - 0
+	REGM = REGEXT - 1
+
 	REGCTXT = REG_R7
 	REGTMP  = REG_R11
 	REGSP   = REG_R13
 	REGLINK = REG_R14
 	REGPC   = REG_R15
-	NFREG   = 16
+
+	NFREG = 16
+	/* compiler allocates register variables F0 up */
+	/* compiler allocates external registers F7 down */
 	FREGRET = REG_F0
 	FREGEXT = REG_F7
 	FREGTMP = REG_F15
 )
 
-/* compiler allocates register variables F0 up */
-/* compiler allocates external registers F7 down */
 const (
 	C_NONE = iota
 	C_REG
@@ -111,41 +120,50 @@
 	C_FREG
 	C_PSR
 	C_FCR
-	C_RCON
-	C_NCON
-	C_SCON
+
+	C_RCON /* 0xff rotated */
+	C_NCON /* ~RCON */
+	C_SCON /* 0xffff */
 	C_LCON
 	C_LCONADDR
 	C_ZFCON
 	C_SFCON
 	C_LFCON
+
 	C_RACON
 	C_LACON
+
 	C_SBRA
 	C_LBRA
-	C_HAUTO
-	C_FAUTO
-	C_HFAUTO
-	C_SAUTO
+
+	C_HAUTO  /* halfword insn offset (-0xff to 0xff) */
+	C_FAUTO  /* float insn offset (0 to 0x3fc, word aligned) */
+	C_HFAUTO /* both H and F */
+	C_SAUTO  /* -0xfff to 0xfff */
 	C_LAUTO
+
 	C_HOREG
 	C_FOREG
 	C_HFOREG
 	C_SOREG
 	C_ROREG
-	C_SROREG
+	C_SROREG /* both nil and R */
 	C_LOREG
+
 	C_PC
 	C_SP
 	C_HREG
-	C_ADDR
+
+	C_ADDR /* reference to relocatable address */
 	C_TEXTSIZE
+
 	C_GOK
-	C_NCLASS
+
+	C_NCLASS /* must be the last */
 )
 
 const (
-	AAND = obj.A_ARCHSPECIFIC + iota
+	AAND = obj.ABaseARM + obj.A_ARCHSPECIFIC + iota
 	AEOR
 	ASUB
 	ARSB
@@ -159,7 +177,13 @@
 	ACMN
 	AORR
 	ABIC
+
 	AMVN
+
+	/*
+	 * Do not reorder or fragment the conditional branch
+	 * opcodes, or the predication code will break
+	 */
 	ABEQ
 	ABNE
 	ABCS
@@ -176,6 +200,7 @@
 	ABLT
 	ABGT
 	ABLE
+
 	AMOVWD
 	AMOVWF
 	AMOVDW
@@ -184,6 +209,7 @@
 	AMOVDF
 	AMOVF
 	AMOVD
+
 	ACMPF
 	ACMPD
 	AADDF
@@ -198,6 +224,7 @@
 	ASQRTD
 	AABSF
 	AABSD
+
 	ASRL
 	ASRA
 	ASLL
@@ -207,6 +234,7 @@
 	ADIV
 	AMOD
 	AMODU
+
 	AMOVB
 	AMOVBS
 	AMOVBU
@@ -217,46 +245,64 @@
 	AMOVM
 	ASWPBU
 	ASWPW
+
 	ARFE
 	ASWI
 	AMULA
+
 	AWORD
 	ABCASE
 	ACASE
+
 	AMULL
 	AMULAL
 	AMULLU
 	AMULALU
+
 	ABX
 	ABXRET
 	ADWORD
+
 	ALDREX
 	ASTREX
 	ALDREXD
 	ASTREXD
+
 	APLD
+
 	ACLZ
+
 	AMULWT
 	AMULWB
 	AMULAWT
 	AMULAWB
+
 	ADATABUNDLE
 	ADATABUNDLEEND
-	AMRC
+
+	AMRC // MRC/MCR
+
 	ALAST
+
+	// aliases
 	AB  = obj.AJMP
 	ABL = obj.ACALL
 )
 
 /* scond byte */
 const (
-	C_SCOND      = (1 << 4) - 1
-	C_SBIT       = 1 << 4
-	C_PBIT       = 1 << 5
-	C_WBIT       = 1 << 6
-	C_FBIT       = 1 << 7
-	C_UBIT       = 1 << 7
-	C_SCOND_XOR  = 14
+	C_SCOND = (1 << 4) - 1
+	C_SBIT  = 1 << 4
+	C_PBIT  = 1 << 5
+	C_WBIT  = 1 << 6
+	C_FBIT  = 1 << 7 /* psr flags-only */
+	C_UBIT  = 1 << 7 /* up bit, unsigned bit */
+
+	// These constants are the ARM condition codes encodings,
+	// XORed with 14 so that C_SCOND_NONE has value 0,
+	// so that a zeroed Prog.scond means "always execute".
+	C_SCOND_XOR = 14
+
 	C_SCOND_EQ   = 0 ^ C_SCOND_XOR
 	C_SCOND_NE   = 1 ^ C_SCOND_XOR
 	C_SCOND_HS   = 2 ^ C_SCOND_XOR
@@ -273,13 +319,10 @@
 	C_SCOND_LE   = 13 ^ C_SCOND_XOR
 	C_SCOND_NONE = 14 ^ C_SCOND_XOR
 	C_SCOND_NV   = 15 ^ C_SCOND_XOR
-	SHIFT_LL     = 0 << 5
-	SHIFT_LR     = 1 << 5
-	SHIFT_AR     = 2 << 5
-	SHIFT_RR     = 3 << 5
-)
 
-/*
- * this is the ranlib header
- */
-var SYMDEF string
+	/* D_SHIFT type */
+	SHIFT_LL = 0 << 5
+	SHIFT_LR = 1 << 5
+	SHIFT_AR = 2 << 5
+	SHIFT_RR = 3 << 5
+)
diff --git a/src/cmd/internal/obj/arm/anames.go b/src/cmd/internal/obj/arm/anames.go
new file mode 100644
index 0000000..0a028c0
--- /dev/null
+++ b/src/cmd/internal/obj/arm/anames.go
@@ -0,0 +1,108 @@
+// Generated by stringer -i 5.out.go -o anames.go -p arm
+// Do not edit.
+
+package arm
+
+import "cmd/internal/obj"
+
+var Anames = []string{
+	obj.A_ARCHSPECIFIC: "AND",
+	"EOR",
+	"SUB",
+	"RSB",
+	"ADD",
+	"ADC",
+	"SBC",
+	"RSC",
+	"TST",
+	"TEQ",
+	"CMP",
+	"CMN",
+	"ORR",
+	"BIC",
+	"MVN",
+	"BEQ",
+	"BNE",
+	"BCS",
+	"BHS",
+	"BCC",
+	"BLO",
+	"BMI",
+	"BPL",
+	"BVS",
+	"BVC",
+	"BHI",
+	"BLS",
+	"BGE",
+	"BLT",
+	"BGT",
+	"BLE",
+	"MOVWD",
+	"MOVWF",
+	"MOVDW",
+	"MOVFW",
+	"MOVFD",
+	"MOVDF",
+	"MOVF",
+	"MOVD",
+	"CMPF",
+	"CMPD",
+	"ADDF",
+	"ADDD",
+	"SUBF",
+	"SUBD",
+	"MULF",
+	"MULD",
+	"DIVF",
+	"DIVD",
+	"SQRTF",
+	"SQRTD",
+	"ABSF",
+	"ABSD",
+	"SRL",
+	"SRA",
+	"SLL",
+	"MULU",
+	"DIVU",
+	"MUL",
+	"DIV",
+	"MOD",
+	"MODU",
+	"MOVB",
+	"MOVBS",
+	"MOVBU",
+	"MOVH",
+	"MOVHS",
+	"MOVHU",
+	"MOVW",
+	"MOVM",
+	"SWPBU",
+	"SWPW",
+	"RFE",
+	"SWI",
+	"MULA",
+	"WORD",
+	"BCASE",
+	"CASE",
+	"MULL",
+	"MULAL",
+	"MULLU",
+	"MULALU",
+	"BX",
+	"BXRET",
+	"DWORD",
+	"LDREX",
+	"STREX",
+	"LDREXD",
+	"STREXD",
+	"PLD",
+	"CLZ",
+	"MULWT",
+	"MULWB",
+	"MULAWT",
+	"MULAWB",
+	"DATABUNDLE",
+	"DATABUNDLEEND",
+	"MRC",
+	"LAST",
+}
diff --git a/src/cmd/internal/obj/arm/anames5.go b/src/cmd/internal/obj/arm/anames5.go
index f00cf17..2e3a1f9 100644
--- a/src/cmd/internal/obj/arm/anames5.go
+++ b/src/cmd/internal/obj/arm/anames5.go
@@ -1,125 +1,8 @@
-package arm
+// Copyright 2015 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 Anames = []string{
-	"XXX",
-	"CALL",
-	"CHECKNIL",
-	"DATA",
-	"DUFFCOPY",
-	"DUFFZERO",
-	"END",
-	"FUNCDATA",
-	"GLOBL",
-	"JMP",
-	"NOP",
-	"PCDATA",
-	"RET",
-	"TEXT",
-	"TYPE",
-	"UNDEF",
-	"USEFIELD",
-	"VARDEF",
-	"VARKILL",
-	"AND",
-	"EOR",
-	"SUB",
-	"RSB",
-	"ADD",
-	"ADC",
-	"SBC",
-	"RSC",
-	"TST",
-	"TEQ",
-	"CMP",
-	"CMN",
-	"ORR",
-	"BIC",
-	"MVN",
-	"BEQ",
-	"BNE",
-	"BCS",
-	"BHS",
-	"BCC",
-	"BLO",
-	"BMI",
-	"BPL",
-	"BVS",
-	"BVC",
-	"BHI",
-	"BLS",
-	"BGE",
-	"BLT",
-	"BGT",
-	"BLE",
-	"MOVWD",
-	"MOVWF",
-	"MOVDW",
-	"MOVFW",
-	"MOVFD",
-	"MOVDF",
-	"MOVF",
-	"MOVD",
-	"CMPF",
-	"CMPD",
-	"ADDF",
-	"ADDD",
-	"SUBF",
-	"SUBD",
-	"MULF",
-	"MULD",
-	"DIVF",
-	"DIVD",
-	"SQRTF",
-	"SQRTD",
-	"ABSF",
-	"ABSD",
-	"SRL",
-	"SRA",
-	"SLL",
-	"MULU",
-	"DIVU",
-	"MUL",
-	"DIV",
-	"MOD",
-	"MODU",
-	"MOVB",
-	"MOVBS",
-	"MOVBU",
-	"MOVH",
-	"MOVHS",
-	"MOVHU",
-	"MOVW",
-	"MOVM",
-	"SWPBU",
-	"SWPW",
-	"RFE",
-	"SWI",
-	"MULA",
-	"WORD",
-	"BCASE",
-	"CASE",
-	"MULL",
-	"MULAL",
-	"MULLU",
-	"MULALU",
-	"BX",
-	"BXRET",
-	"DWORD",
-	"LDREX",
-	"STREX",
-	"LDREXD",
-	"STREXD",
-	"PLD",
-	"CLZ",
-	"MULWT",
-	"MULWB",
-	"MULAWT",
-	"MULAWB",
-	"DATABUNDLE",
-	"DATABUNDLEEND",
-	"MRC",
-	"LAST",
-}
+package arm
 
 var cnames5 = []string{
 	"NONE",
diff --git a/src/cmd/internal/obj/arm/asm5.go b/src/cmd/internal/obj/arm/asm5.go
index f82b737..527474f 100644
--- a/src/cmd/internal/obj/arm/asm5.go
+++ b/src/cmd/internal/obj/arm/asm5.go
@@ -39,7 +39,7 @@
 )
 
 type Optab struct {
-	as       uint8
+	as       uint16
 	a1       uint8
 	a2       int8
 	a3       uint8
@@ -268,7 +268,7 @@
 	extra uint32
 }
 
-var oprange [ALAST]Oprang
+var oprange [ALAST & obj.AMask]Oprang
 
 var xcmp [C_GOK + 1][C_GOK + 1]uint8
 
@@ -304,13 +304,7 @@
 // In rare cases, asmoutnacl might split p into two instructions.
 // origPC is the PC for this Prog (no padding is taken into account).
 func asmoutnacl(ctxt *obj.Link, origPC int32, p *obj.Prog, o *Optab, out []uint32) int {
-	var size int
-	var reg int
-	var q *obj.Prog
-	var a *obj.Addr
-	var a2 *obj.Addr
-
-	size = int(o.size)
+	size := int(o.size)
 
 	// instruction specific
 	switch p.As {
@@ -340,8 +334,7 @@
 			}
 		}
 
-	case AB,
-		ABL:
+	case AB, ABL:
 		if p.To.Type != obj.TYPE_MEM {
 			if out != nil {
 				asmout(ctxt, p, o, out)
@@ -356,8 +349,8 @@
 			if out != nil {
 				out[0] = ((uint32(p.Scond)&C_SCOND)^C_SCOND_XOR)<<28 | 0x03c0013f | (uint32(p.To.Reg)&15)<<12 | (uint32(p.To.Reg)&15)<<16 // BIC $0xc000000f, Rx
 				if p.As == AB {
-					out[1] = ((uint32(p.Scond)&C_SCOND)^C_SCOND_XOR)<<28 | 0x012fff10 | (uint32(p.To.Reg)&15)<<0 // BX Rx // ABL
-				} else {
+					out[1] = ((uint32(p.Scond)&C_SCOND)^C_SCOND_XOR)<<28 | 0x012fff10 | (uint32(p.To.Reg)&15)<<0 // BX Rx
+				} else { // ABL
 					out[1] = ((uint32(p.Scond)&C_SCOND)^C_SCOND_XOR)<<28 | 0x012fff30 | (uint32(p.To.Reg)&15)<<0 // BLX Rx
 				}
 			}
@@ -437,11 +430,12 @@
 			// split it into two instructions:
 			// 	ADD $-100004, R13
 			// 	MOVW R14, 0(R13)
-			q = ctxt.NewProg()
+			q := ctxt.NewProg()
 
 			p.Scond &^= C_WBIT
 			*q = *p
-			a = &p.To
+			a := &p.To
+			var a2 *obj.Addr
 			if p.To.Type == obj.TYPE_MEM {
 				a2 = &q.To
 			} else {
@@ -478,13 +472,15 @@
 			break
 		}
 
-		if (p.To.Type == obj.TYPE_MEM && p.To.Reg != REG_R13 && p.To.Reg != REG_R9) || (p.From.Type == obj.TYPE_MEM && p.From.Reg != REG_R13 && p.From.Reg != REG_R9) { // MOVW Rx, X(Ry), y != 13 && y != 9 // MOVW X(Rx), Ry, x != 13 && x != 9
+		if (p.To.Type == obj.TYPE_MEM && p.To.Reg != REG_R13 && p.To.Reg != REG_R9) || // MOVW Rx, X(Ry), y != 13 && y != 9
+			(p.From.Type == obj.TYPE_MEM && p.From.Reg != REG_R13 && p.From.Reg != REG_R9) { // MOVW X(Rx), Ry, x != 13 && x != 9
+			var a *obj.Addr
 			if p.To.Type == obj.TYPE_MEM {
 				a = &p.To
 			} else {
 				a = &p.From
 			}
-			reg = int(a.Reg)
+			reg := int(a.Reg)
 			if size == 4 {
 				// if addr.reg == 0, then it is probably load from x(FP) with small x, no need to modify.
 				if reg == 0 {
@@ -514,8 +510,9 @@
 				if p.Scond&(C_PBIT|C_WBIT) != 0 {
 					ctxt.Diag("unsupported instruction (.P/.W): %v", p)
 				}
-				q = ctxt.NewProg()
+				q := ctxt.NewProg()
 				*q = *p
+				var a2 *obj.Addr
 				if p.To.Type == obj.TYPE_MEM {
 					a2 = &q.To
 				} else {
@@ -577,34 +574,27 @@
 func span5(ctxt *obj.Link, cursym *obj.LSym) {
 	var p *obj.Prog
 	var op *obj.Prog
-	var o *Optab
-	var m int
-	var bflag int
-	var i int
-	var v int
-	var times int
-	var c int32
-	var opc int32
-	var out [6 + 3]uint32
-	var bp []byte
 
 	p = cursym.Text
 	if p == nil || p.Link == nil { // handle external functions and ELF section symbols
 		return
 	}
 
-	if oprange[AAND].start == nil {
+	if oprange[AAND&obj.AMask].start == nil {
 		buildop(ctxt)
 	}
 
 	ctxt.Cursym = cursym
 
 	ctxt.Autosize = int32(p.To.Offset + 4)
-	c = 0
+	c := int32(0)
 
 	op = p
 	p = p.Link
-	for ; p != nil || ctxt.Blitrl != nil; (func() { op = p; p = p.Link })() {
+	var i int
+	var m int
+	var o *Optab
+	for ; p != nil || ctxt.Blitrl != nil; op, p = p, p.Link {
 		if p == nil {
 			if checkpool(ctxt, op, 0) {
 				p = op
@@ -676,8 +666,11 @@
 	 * generate extra passes putting branches
 	 * around jmps to fix. this is rare.
 	 */
-	times = 0
+	times := 0
 
+	var bflag int
+	var opc int32
+	var out [6 + 3]uint32
 	for {
 		if ctxt.Debugvlog != 0 {
 			fmt.Fprintf(ctxt.Bso, "%5.2f span1\n", obj.Cputime())
@@ -774,8 +767,9 @@
 	ctxt.Autosize = int32(p.To.Offset + 4)
 	obj.Symgrow(ctxt, cursym, cursym.Size)
 
-	bp = cursym.P
+	bp := cursym.P
 	c = int32(p.Pc) // even p->link might need extra padding
+	var v int
 	for p = p.Link; p != nil; p = p.Link {
 		ctxt.Pc = p.Pc
 		ctxt.Curp = p
@@ -844,14 +838,12 @@
 }
 
 func flushpool(ctxt *obj.Link, p *obj.Prog, skip int, force int) bool {
-	var q *obj.Prog
-
 	if ctxt.Blitrl != nil {
 		if skip != 0 {
 			if false && skip == 1 {
 				fmt.Printf("note: flush literal pool at %x: len=%d ref=%x\n", uint64(p.Pc+4), pool.size, pool.start)
 			}
-			q = ctxt.NewProg()
+			q := ctxt.NewProg()
 			q.As = AB
 			q.To.Type = obj.TYPE_BRANCH
 			q.Pcond = p.Link
@@ -863,7 +855,7 @@
 		}
 		if ctxt.Headtype == obj.Hnacl && pool.size%16 != 0 {
 			// if pool is not multiple of 16 bytes, add an alignment marker
-			q = ctxt.NewProg()
+			q := ctxt.NewProg()
 
 			q.As = ADATABUNDLEEND
 			ctxt.Elitrl.Link = q
@@ -893,11 +885,9 @@
 }
 
 func addpool(ctxt *obj.Link, p *obj.Prog, a *obj.Addr) {
-	var q *obj.Prog
 	var t obj.Prog
-	var c int
 
-	c = aclass(ctxt, a)
+	c := aclass(ctxt, a)
 
 	t.Ctxt = ctxt
 	t.As = AWORD
@@ -928,7 +918,7 @@
 	}
 
 	if t.Pcrel == nil {
-		for q = ctxt.Blitrl; q != nil; q = q.Link { /* could hash on t.t0.offset */
+		for q := ctxt.Blitrl; q != nil; q = q.Link { /* could hash on t.t0.offset */
 			if q.Pcrel == nil && q.To == t.To {
 				p.Pcond = q
 				return
@@ -938,7 +928,7 @@
 
 	if ctxt.Headtype == obj.Hnacl && pool.size%16 == 0 {
 		// start a new data bundle
-		q = ctxt.NewProg()
+		q := ctxt.NewProg()
 		q.As = ADATABUNDLE
 		q.Pc = int64(pool.size)
 		pool.size += 4
@@ -952,7 +942,7 @@
 		ctxt.Elitrl = q
 	}
 
-	q = ctxt.NewProg()
+	q := ctxt.NewProg()
 	*q = t
 	q.Pc = int64(pool.size)
 
@@ -975,9 +965,7 @@
 }
 
 func immrot(v uint32) int32 {
-	var i int
-
-	for i = 0; i < 16; i++ {
+	for i := 0; i < 16; i++ {
 		if v&^0xff == 0 {
 			return int32(uint32(int32(i)<<8) | v | 1<<25)
 		}
@@ -1012,9 +1000,6 @@
 }
 
 func aclass(ctxt *obj.Link, a *obj.Addr) int {
-	var s *obj.LSym
-	var t int
-
 	switch a.Type {
 	case obj.TYPE_NONE:
 		return C_NONE
@@ -1060,7 +1045,7 @@
 
 		case obj.NAME_AUTO:
 			ctxt.Instoffset = int64(ctxt.Autosize) + a.Offset
-			t = int(immaddr(int32(ctxt.Instoffset)))
+			t := int(immaddr(int32(ctxt.Instoffset)))
 			if t != 0 {
 				if immhalf(int32(ctxt.Instoffset)) {
 					if immfloat(int32(t)) {
@@ -1079,7 +1064,7 @@
 
 		case obj.NAME_PARAM:
 			ctxt.Instoffset = int64(ctxt.Autosize) + a.Offset + 4
-			t = int(immaddr(int32(ctxt.Instoffset)))
+			t := int(immaddr(int32(ctxt.Instoffset)))
 			if t != 0 {
 				if immhalf(int32(ctxt.Instoffset)) {
 					if immfloat(int32(t)) {
@@ -1098,7 +1083,7 @@
 
 		case obj.TYPE_NONE:
 			ctxt.Instoffset = a.Offset
-			t = int(immaddr(int32(ctxt.Instoffset)))
+			t := int(immaddr(int32(ctxt.Instoffset)))
 			if t != 0 {
 				if immhalf(int32(ctxt.Instoffset)) { /* n.b. that it will also satisfy immrot */
 					if immfloat(int32(t)) {
@@ -1110,7 +1095,7 @@
 				if immfloat(int32(t)) {
 					return C_FOREG /* n.b. that it will also satisfy immrot */
 				}
-				t = int(immrot(uint32(ctxt.Instoffset)))
+				t := int(immrot(uint32(ctxt.Instoffset)))
 				if t != 0 {
 					return C_SROREG
 				}
@@ -1130,10 +1115,10 @@
 		return C_GOK
 
 	case obj.TYPE_FCONST:
-		if chipzero5(ctxt, a.U.Dval) >= 0 {
+		if chipzero5(ctxt, a.Val.(float64)) >= 0 {
 			return C_ZFCON
 		}
-		if chipfloat5(ctxt, a.U.Dval) >= 0 {
+		if chipfloat5(ctxt, a.Val.(float64)) >= 0 {
 			return C_SFCON
 		}
 		return C_LFCON
@@ -1150,7 +1135,7 @@
 				return aconsize(ctxt)
 			}
 
-			t = int(immrot(uint32(ctxt.Instoffset)))
+			t := int(immrot(uint32(ctxt.Instoffset)))
 			if t != 0 {
 				return C_RCON
 			}
@@ -1162,7 +1147,7 @@
 
 		case obj.NAME_EXTERN,
 			obj.NAME_STATIC:
-			s = a.Sym
+			s := a.Sym
 			if s == nil {
 				break
 			}
@@ -1188,9 +1173,7 @@
 }
 
 func aconsize(ctxt *obj.Link) int {
-	var t int
-
-	t = int(immrot(uint32(ctxt.Instoffset)))
+	t := int(immrot(uint32(ctxt.Instoffset)))
 	if t != 0 {
 		return C_RACON
 	}
@@ -1202,16 +1185,7 @@
 }
 
 func oplook(ctxt *obj.Link, p *obj.Prog) *Optab {
-	var a1 int
-	var a2 int
-	var a3 int
-	var r int
-	var c1 []byte
-	var c3 []byte
-	var o []Optab
-	var e []Optab
-
-	a1 = int(p.Optab)
+	a1 := int(p.Optab)
 	if a1 != 0 {
 		return &optab[a1-1:][0]
 	}
@@ -1222,31 +1196,31 @@
 	}
 
 	a1--
-	a3 = int(p.To.Class)
+	a3 := int(p.To.Class)
 	if a3 == 0 {
 		a3 = aclass(ctxt, &p.To) + 1
 		p.To.Class = int8(a3)
 	}
 
 	a3--
-	a2 = C_NONE
+	a2 := C_NONE
 	if p.Reg != 0 {
 		a2 = C_REG
 	}
-	r = int(p.As)
-	o = oprange[r].start
+	r := p.As & obj.AMask
+	o := oprange[r].start
 	if o == nil {
 		o = oprange[r].stop /* just generate an error */
 	}
 
 	if false { /*debug['O']*/
-		fmt.Printf("oplook %v %v %v %v\n", Aconv(int(p.As)), DRconv(a1), DRconv(a2), DRconv(a3))
+		fmt.Printf("oplook %v %v %v %v\n", obj.Aconv(int(p.As)), DRconv(a1), DRconv(a2), DRconv(a3))
 		fmt.Printf("\t\t%d %d\n", p.From.Type, p.To.Type)
 	}
 
-	e = oprange[r].stop
-	c1 = xcmp[a1][:]
-	c3 = xcmp[a3][:]
+	e := oprange[r].stop
+	c1 := xcmp[a1][:]
+	c3 := xcmp[a3][:]
 	for ; -cap(o) < -cap(e); o = o[1:] {
 		if int(o[0].a2) == a2 {
 			if c1[o[0].a1] != 0 {
@@ -1290,8 +1264,7 @@
 	case C_HFAUTO:
 		return b == C_HAUTO || b == C_FAUTO
 
-	case C_FAUTO,
-		C_HAUTO:
+	case C_FAUTO, C_HAUTO:
 		return b == C_HFAUTO
 
 	case C_SAUTO:
@@ -1303,15 +1276,13 @@
 	case C_HFOREG:
 		return b == C_HOREG || b == C_FOREG
 
-	case C_FOREG,
-		C_HOREG:
+	case C_FOREG, C_HOREG:
 		return b == C_HFOREG
 
 	case C_SROREG:
 		return cmp(C_SOREG, b) || cmp(C_ROREG, b)
 
-	case C_SOREG,
-		C_ROREG:
+	case C_SOREG, C_ROREG:
 		return b == C_SROREG || cmp(C_HFOREG, b)
 
 	case C_LOREG:
@@ -1340,13 +1311,9 @@
 }
 
 func (x ocmp) Less(i, j int) bool {
-	var p1 *Optab
-	var p2 *Optab
-	var n int
-
-	p1 = &x[i]
-	p2 = &x[j]
-	n = int(p1.as) - int(p2.as)
+	p1 := &x[i]
+	p2 := &x[j]
+	n := int(p1.as) - int(p2.as)
 	if n != 0 {
 		return n < 0
 	}
@@ -1365,12 +1332,14 @@
 	return false
 }
 
-func buildop(ctxt *obj.Link) {
-	var i int
-	var n int
-	var r int
+func opset(a, b0 uint16) {
+	oprange[a&obj.AMask] = oprange[b0]
+}
 
-	for i = 0; i < C_GOK; i++ {
+func buildop(ctxt *obj.Link) {
+	var n int
+
+	for i := 0; i < C_GOK; i++ {
 		for n = 0; n < C_GOK; n++ {
 			if cmp(n, i) {
 				xcmp[i][n] = 1
@@ -1388,66 +1357,67 @@
 	}
 
 	sort.Sort(ocmp(optab[:n]))
-	for i = 0; i < n; i++ {
-		r = int(optab[i].as)
-		oprange[r].start = optab[i:]
-		for int(optab[i].as) == r {
+	for i := 0; i < n; i++ {
+		r := optab[i].as
+		r0 := r & obj.AMask
+		oprange[r0].start = optab[i:]
+		for optab[i].as == r {
 			i++
 		}
-		oprange[r].stop = optab[i:]
+		oprange[r0].stop = optab[i:]
 		i--
 
 		switch r {
 		default:
-			ctxt.Diag("unknown op in build: %v", Aconv(r))
+			ctxt.Diag("unknown op in build: %v", obj.Aconv(int(r)))
 			log.Fatalf("bad code")
 
 		case AADD:
-			oprange[AAND] = oprange[r]
-			oprange[AEOR] = oprange[r]
-			oprange[ASUB] = oprange[r]
-			oprange[ARSB] = oprange[r]
-			oprange[AADC] = oprange[r]
-			oprange[ASBC] = oprange[r]
-			oprange[ARSC] = oprange[r]
-			oprange[AORR] = oprange[r]
-			oprange[ABIC] = oprange[r]
+			opset(AAND, r0)
+			opset(AEOR, r0)
+			opset(ASUB, r0)
+			opset(ARSB, r0)
+			opset(AADC, r0)
+			opset(ASBC, r0)
+			opset(ARSC, r0)
+			opset(AORR, r0)
+			opset(ABIC, r0)
 
 		case ACMP:
-			oprange[ATEQ] = oprange[r]
-			oprange[ACMN] = oprange[r]
+			opset(ATEQ, r0)
+			opset(ACMN, r0)
 
 		case AMVN:
 			break
 
 		case ABEQ:
-			oprange[ABNE] = oprange[r]
-			oprange[ABCS] = oprange[r]
-			oprange[ABHS] = oprange[r]
-			oprange[ABCC] = oprange[r]
-			oprange[ABLO] = oprange[r]
-			oprange[ABMI] = oprange[r]
-			oprange[ABPL] = oprange[r]
-			oprange[ABVS] = oprange[r]
-			oprange[ABVC] = oprange[r]
-			oprange[ABHI] = oprange[r]
-			oprange[ABLS] = oprange[r]
-			oprange[ABGE] = oprange[r]
-			oprange[ABLT] = oprange[r]
-			oprange[ABGT] = oprange[r]
-			oprange[ABLE] = oprange[r]
+			opset(ABNE, r0)
+			opset(ABCS, r0)
+			opset(ABHS, r0)
+			opset(ABCC, r0)
+			opset(ABLO, r0)
+			opset(ABMI, r0)
+			opset(ABPL, r0)
+			opset(ABVS, r0)
+			opset(ABVC, r0)
+			opset(ABHI, r0)
+			opset(ABLS, r0)
+			opset(ABGE, r0)
+			opset(ABLT, r0)
+			opset(ABGT, r0)
+			opset(ABLE, r0)
 
 		case ASLL:
-			oprange[ASRL] = oprange[r]
-			oprange[ASRA] = oprange[r]
+			opset(ASRL, r0)
+			opset(ASRA, r0)
 
 		case AMUL:
-			oprange[AMULU] = oprange[r]
+			opset(AMULU, r0)
 
 		case ADIV:
-			oprange[AMOD] = oprange[r]
-			oprange[AMODU] = oprange[r]
-			oprange[ADIVU] = oprange[r]
+			opset(AMOD, r0)
+			opset(AMODU, r0)
+			opset(ADIVU, r0)
 
 		case AMOVW,
 			AMOVB,
@@ -1459,7 +1429,7 @@
 			break
 
 		case ASWPW:
-			oprange[ASWPBU] = oprange[r]
+			opset(ASWPBU, r0)
 
 		case AB,
 			ABL,
@@ -1479,42 +1449,42 @@
 			break
 
 		case AADDF:
-			oprange[AADDD] = oprange[r]
-			oprange[ASUBF] = oprange[r]
-			oprange[ASUBD] = oprange[r]
-			oprange[AMULF] = oprange[r]
-			oprange[AMULD] = oprange[r]
-			oprange[ADIVF] = oprange[r]
-			oprange[ADIVD] = oprange[r]
-			oprange[ASQRTF] = oprange[r]
-			oprange[ASQRTD] = oprange[r]
-			oprange[AMOVFD] = oprange[r]
-			oprange[AMOVDF] = oprange[r]
-			oprange[AABSF] = oprange[r]
-			oprange[AABSD] = oprange[r]
+			opset(AADDD, r0)
+			opset(ASUBF, r0)
+			opset(ASUBD, r0)
+			opset(AMULF, r0)
+			opset(AMULD, r0)
+			opset(ADIVF, r0)
+			opset(ADIVD, r0)
+			opset(ASQRTF, r0)
+			opset(ASQRTD, r0)
+			opset(AMOVFD, r0)
+			opset(AMOVDF, r0)
+			opset(AABSF, r0)
+			opset(AABSD, r0)
 
 		case ACMPF:
-			oprange[ACMPD] = oprange[r]
+			opset(ACMPD, r0)
 
 		case AMOVF:
-			oprange[AMOVD] = oprange[r]
+			opset(AMOVD, r0)
 
 		case AMOVFW:
-			oprange[AMOVDW] = oprange[r]
+			opset(AMOVDW, r0)
 
 		case AMOVWF:
-			oprange[AMOVWD] = oprange[r]
+			opset(AMOVWD, r0)
 
 		case AMULL:
-			oprange[AMULAL] = oprange[r]
-			oprange[AMULLU] = oprange[r]
-			oprange[AMULALU] = oprange[r]
+			opset(AMULAL, r0)
+			opset(AMULLU, r0)
+			opset(AMULALU, r0)
 
 		case AMULWT:
-			oprange[AMULWB] = oprange[r]
+			opset(AMULWB, r0)
 
 		case AMULAWT:
-			oprange[AMULAWB] = oprange[r]
+			opset(AMULAWB, r0)
 
 		case AMULA,
 			ALDREX,
@@ -1536,26 +1506,13 @@
 }
 
 func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) {
-	var o1 uint32
-	var o2 uint32
-	var o3 uint32
-	var o4 uint32
-	var o5 uint32
-	var o6 uint32
-	var v int32
-	var r int
-	var rf int
-	var rt int
-	var rt2 int
-	var rel *obj.Reloc
-
 	ctxt.Printp = p
-	o1 = 0
-	o2 = 0
-	o3 = 0
-	o4 = 0
-	o5 = 0
-	o6 = 0
+	o1 := uint32(0)
+	o2 := uint32(0)
+	o3 := uint32(0)
+	o4 := uint32(0)
+	o5 := uint32(0)
+	o6 := uint32(0)
 	ctxt.Armsize += int32(o.size)
 	if false { /*debug['P']*/
 		fmt.Printf("%x: %v\ttype %d\n", uint32(p.Pc), p, o.type_)
@@ -1573,9 +1530,9 @@
 	case 1: /* op R,[R],R */
 		o1 = oprrr(ctxt, int(p.As), int(p.Scond))
 
-		rf = int(p.From.Reg)
-		rt = int(p.To.Reg)
-		r = int(p.Reg)
+		rf := int(p.From.Reg)
+		rt := int(p.To.Reg)
+		r := int(p.Reg)
 		if p.To.Type == obj.TYPE_NONE {
 			rt = 0
 		}
@@ -1591,8 +1548,8 @@
 
 		o1 = oprrr(ctxt, int(p.As), int(p.Scond))
 		o1 |= uint32(immrot(uint32(ctxt.Instoffset)))
-		rt = int(p.To.Reg)
-		r = int(p.Reg)
+		rt := int(p.To.Reg)
+		r := int(p.Reg)
 		if p.To.Type == obj.TYPE_NONE {
 			rt = 0
 		}
@@ -1611,7 +1568,7 @@
 
 		o1 = oprrr(ctxt, AADD, int(p.Scond))
 		o1 |= uint32(immrot(uint32(ctxt.Instoffset)))
-		r = int(p.From.Reg)
+		r := int(p.From.Reg)
 		if r == 0 {
 			r = int(o.param)
 		}
@@ -1621,9 +1578,9 @@
 	case 5: /* bra s */
 		o1 = opbra(ctxt, int(p.As), int(p.Scond))
 
-		v = -8
+		v := int32(-8)
 		if p.To.Sym != nil {
-			rel = obj.Addrel(ctxt.Cursym)
+			rel := obj.Addrel(ctxt.Cursym)
 			rel.Off = int32(ctxt.Pc)
 			rel.Siz = 4
 			rel.Sym = p.To.Sym
@@ -1654,7 +1611,7 @@
 		}
 		o1 = oprrr(ctxt, ABL, int(p.Scond))
 		o1 |= (uint32(p.To.Reg) & 15) << 0
-		rel = obj.Addrel(ctxt.Cursym)
+		rel := obj.Addrel(ctxt.Cursym)
 		rel.Off = int32(ctxt.Pc)
 		rel.Siz = 0
 		rel.Type = obj.R_CALLIND
@@ -1663,7 +1620,7 @@
 		aclass(ctxt, &p.From)
 
 		o1 = oprrr(ctxt, int(p.As), int(p.Scond))
-		r = int(p.Reg)
+		r := int(p.Reg)
 		if r == 0 {
 			r = int(p.To.Reg)
 		}
@@ -1674,7 +1631,7 @@
 	case 9: /* sll R,[R],R -> mov (R<<R),R */
 		o1 = oprrr(ctxt, int(p.As), int(p.Scond))
 
-		r = int(p.Reg)
+		r := int(p.Reg)
 		if r == 0 {
 			r = int(p.To.Reg)
 		}
@@ -1697,7 +1654,7 @@
 		if p.To.Sym != nil {
 			// This case happens with words generated
 			// in the PC stream as part of the literal pool.
-			rel = obj.Addrel(ctxt.Cursym)
+			rel := obj.Addrel(ctxt.Cursym)
 
 			rel.Off = int32(ctxt.Pc)
 			rel.Siz = 4
@@ -1742,7 +1699,7 @@
 		}
 		o2 = oprrr(ctxt, int(p.As), int(p.Scond))
 		o2 |= REGTMP & 15
-		r = int(p.Reg)
+		r := int(p.Reg)
 		if p.As == AMOVW || p.As == AMVN {
 			r = 0
 		} else if r == 0 {
@@ -1762,7 +1719,7 @@
 			o2 = oprrr(ctxt, ASRA, int(p.Scond))
 		}
 
-		r = int(p.To.Reg)
+		r := int(p.To.Reg)
 		o1 |= (uint32(p.From.Reg)&15)<<0 | (uint32(r)&15)<<12
 		o2 |= uint32(r)&15 | (uint32(r)&15)<<12
 		if p.As == AMOVB || p.As == AMOVBS || p.As == AMOVBU {
@@ -1776,9 +1733,9 @@
 	case 15: /* mul r,[r,]r */
 		o1 = oprrr(ctxt, int(p.As), int(p.Scond))
 
-		rf = int(p.From.Reg)
-		rt = int(p.To.Reg)
-		r = int(p.Reg)
+		rf := int(p.From.Reg)
+		rt := int(p.To.Reg)
+		r := int(p.Reg)
 		if r == 0 {
 			r = rt
 		}
@@ -1803,16 +1760,16 @@
 
 	case 17:
 		o1 = oprrr(ctxt, int(p.As), int(p.Scond))
-		rf = int(p.From.Reg)
-		rt = int(p.To.Reg)
-		rt2 = int(p.To.Offset)
-		r = int(p.Reg)
+		rf := int(p.From.Reg)
+		rt := int(p.To.Reg)
+		rt2 := int(p.To.Offset)
+		r := int(p.Reg)
 		o1 |= (uint32(rf)&15)<<8 | (uint32(r)&15)<<0 | (uint32(rt)&15)<<16 | (uint32(rt2)&15)<<12
 
 	case 20: /* mov/movb/movbu R,O(R) */
 		aclass(ctxt, &p.To)
 
-		r = int(p.To.Reg)
+		r := int(p.To.Reg)
 		if r == 0 {
 			r = int(o.param)
 		}
@@ -1821,7 +1778,7 @@
 	case 21: /* mov/movbu O(R),R -> lr */
 		aclass(ctxt, &p.From)
 
-		r = int(p.From.Reg)
+		r := int(p.From.Reg)
 		if r == 0 {
 			r = int(o.param)
 		}
@@ -1836,7 +1793,7 @@
 		if o1 == 0 {
 			break
 		}
-		r = int(p.To.Reg)
+		r := int(p.To.Reg)
 		if r == 0 {
 			r = int(o.param)
 		}
@@ -1851,7 +1808,7 @@
 		if o1 == 0 {
 			break
 		}
-		r = int(p.From.Reg)
+		r := int(p.From.Reg)
 		if r == 0 {
 			r = int(o.param)
 		}
@@ -1869,7 +1826,7 @@
 
 		o2 = oprrr(ctxt, AADD, int(p.Scond))
 		o2 |= REGTMP & 15
-		r = int(p.From.Reg)
+		r := int(p.From.Reg)
 		if r == 0 {
 			r = int(o.param)
 		}
@@ -1907,8 +1864,7 @@
 		o1 |= (uint32(p.To.Reg) & 1) << 22
 		o1 |= (uint32(p.From.Reg) & 15) << 0
 
-	case 38,
-		39:
+	case 38, 39:
 		switch o.type_ {
 		case 38: /* movm $con,oreg -> stm */
 			o1 = 0x4 << 25
@@ -1961,18 +1917,18 @@
 		o1 = 0xe8fd8000
 
 	case 50: /* floating point store */
-		v = regoff(ctxt, &p.To)
+		v := regoff(ctxt, &p.To)
 
-		r = int(p.To.Reg)
+		r := int(p.To.Reg)
 		if r == 0 {
 			r = int(o.param)
 		}
 		o1 = ofsr(ctxt, int(p.As), int(p.From.Reg), v, r, int(p.Scond), p)
 
 	case 51: /* floating point load */
-		v = regoff(ctxt, &p.From)
+		v := regoff(ctxt, &p.From)
 
-		r = int(p.From.Reg)
+		r := int(p.From.Reg)
 		if r == 0 {
 			r = int(o.param)
 		}
@@ -1984,7 +1940,7 @@
 		if o1 == 0 {
 			break
 		}
-		r = int(p.To.Reg)
+		r := int(p.To.Reg)
 		if r == 0 {
 			r = int(o.param)
 		}
@@ -1997,7 +1953,7 @@
 		if o1 == 0 {
 			break
 		}
-		r = int(p.From.Reg)
+		r := int(p.From.Reg)
 		if r == 0 {
 			r = int(o.param)
 		}
@@ -2007,9 +1963,9 @@
 	case 54: /* floating point arith */
 		o1 = oprrr(ctxt, int(p.As), int(p.Scond))
 
-		rf = int(p.From.Reg)
-		rt = int(p.To.Reg)
-		r = int(p.Reg)
+		rf := int(p.From.Reg)
+		rt := int(p.To.Reg)
+		r := int(p.Reg)
 		if r == 0 {
 			r = rt
 			if p.As == AMOVF || p.As == AMOVD || p.As == AMOVFD || p.As == AMOVDF || p.As == ASQRTF || p.As == ASQRTD || p.As == AABSF || p.As == AABSD {
@@ -2033,8 +1989,8 @@
 		o1 = oprrr(ctxt, AAND, int(p.Scond))
 
 		o1 |= uint32(immrot(0xff))
-		rt = int(p.To.Reg)
-		r = int(p.From.Reg)
+		rt := int(p.To.Reg)
+		r := int(p.From.Reg)
 		if p.To.Type == obj.TYPE_NONE {
 			rt = 0
 		}
@@ -2095,7 +2051,7 @@
 
 	case 63: /* bcase */
 		if p.Pcond != nil {
-			rel = obj.Addrel(ctxt.Cursym)
+			rel := obj.Addrel(ctxt.Cursym)
 			rel.Off = int32(ctxt.Pc)
 			rel.Siz = 4
 			if p.To.Sym != nil && p.To.Sym.Type != 0 {
@@ -2171,7 +2127,7 @@
 	case 70: /* movh/movhu R,O(R) -> strh */
 		aclass(ctxt, &p.To)
 
-		r = int(p.To.Reg)
+		r := int(p.To.Reg)
 		if r == 0 {
 			r = int(o.param)
 		}
@@ -2180,7 +2136,7 @@
 	case 71: /* movb/movh/movhu O(R),R -> ldrsb/ldrsh/ldrh */
 		aclass(ctxt, &p.From)
 
-		r = int(p.From.Reg)
+		r := int(p.From.Reg)
 		if r == 0 {
 			r = int(o.param)
 		}
@@ -2197,7 +2153,7 @@
 		if o1 == 0 {
 			break
 		}
-		r = int(p.To.Reg)
+		r := int(p.To.Reg)
 		if r == 0 {
 			r = int(o.param)
 		}
@@ -2209,7 +2165,7 @@
 		if o1 == 0 {
 			break
 		}
-		r = int(p.From.Reg)
+		r := int(p.From.Reg)
 		if r == 0 {
 			r = int(o.param)
 		}
@@ -2278,8 +2234,8 @@
 			o2 = oprrr(ctxt, ASUBF, int(p.Scond))
 		}
 
-		v = 0x70 // 1.0
-		r = (int(p.To.Reg) & 15) << 0
+		v := int32(0x70) // 1.0
+		r := (int(p.To.Reg) & 15) << 0
 
 		// movf $1.0, r
 		o1 |= ((uint32(p.Scond) & C_SCOND) ^ C_SCOND_XOR) << 28
@@ -2298,7 +2254,7 @@
 		}
 		o1 |= ((uint32(p.Scond) & C_SCOND) ^ C_SCOND_XOR) << 28
 		o1 |= (uint32(p.To.Reg) & 15) << 12
-		v = int32(chipfloat5(ctxt, p.From.U.Dval))
+		v := int32(chipfloat5(ctxt, p.From.Val.(float64)))
 		o1 |= (uint32(v) & 0xf) << 0
 		o1 |= (uint32(v) & 0xf0) << 12
 
@@ -2475,18 +2431,14 @@
 }
 
 func mov(ctxt *obj.Link, p *obj.Prog) uint32 {
-	var o1 uint32
-	var rt int
-	var r int
-
 	aclass(ctxt, &p.From)
-	o1 = oprrr(ctxt, int(p.As), int(p.Scond))
+	o1 := oprrr(ctxt, int(p.As), int(p.Scond))
 	o1 |= uint32(p.From.Offset)
-	rt = int(p.To.Reg)
+	rt := int(p.To.Reg)
 	if p.To.Type == obj.TYPE_NONE {
 		rt = 0
 	}
-	r = int(p.Reg)
+	r := int(p.Reg)
 	if p.As == AMOVW || p.As == AMVN {
 		r = 0
 	} else if r == 0 {
@@ -2497,9 +2449,7 @@
 }
 
 func oprrr(ctxt *obj.Link, a int, sc int) uint32 {
-	var o uint32
-
-	o = ((uint32(sc) & C_SCOND) ^ C_SCOND_XOR) << 28
+	o := ((uint32(sc) & C_SCOND) ^ C_SCOND_XOR) << 28
 	if sc&C_SBIT != 0 {
 		o |= 1 << 20
 	}
@@ -2507,8 +2457,7 @@
 		ctxt.Diag(".nil/.W on dp instruction")
 	}
 	switch a {
-	case AMULU,
-		AMUL:
+	case AMULU, AMUL:
 		return o | 0x0<<21 | 0x9<<4
 	case AMULA:
 		return o | 0x1<<21 | 0x9<<4
@@ -2547,9 +2496,7 @@
 	case AORR:
 		return o | 0xc<<21
 
-	case AMOVB,
-		AMOVH,
-		AMOVW:
+	case AMOVB, AMOVH, AMOVW:
 		return o | 0xd<<21
 	case ABIC:
 		return o | 0xe<<21
@@ -2710,18 +2657,16 @@
 		return 0xe<<28 | 0x5<<25
 	}
 
-	ctxt.Diag("bad bra %v", Aconv(a))
+	ctxt.Diag("bad bra %v", obj.Aconv(a))
 	prasm(ctxt.Curp)
 	return 0
 }
 
 func olr(ctxt *obj.Link, v int32, b int, r int, sc int) uint32 {
-	var o uint32
-
 	if sc&C_SBIT != 0 {
 		ctxt.Diag(".nil on LDR/STR instruction")
 	}
-	o = ((uint32(sc) & C_SCOND) ^ C_SCOND_XOR) << 28
+	o := ((uint32(sc) & C_SCOND) ^ C_SCOND_XOR) << 28
 	if sc&C_PBIT == 0 {
 		o |= 1 << 24
 	}
@@ -2750,12 +2695,10 @@
 }
 
 func olhr(ctxt *obj.Link, v int32, b int, r int, sc int) uint32 {
-	var o uint32
-
 	if sc&C_SBIT != 0 {
 		ctxt.Diag(".nil on LDRH/STRH instruction")
 	}
-	o = ((uint32(sc) & C_SCOND) ^ C_SCOND_XOR) << 28
+	o := ((uint32(sc) & C_SCOND) ^ C_SCOND_XOR) << 28
 	if sc&C_PBIT == 0 {
 		o |= 1 << 24
 	}
@@ -2778,9 +2721,7 @@
 }
 
 func osr(ctxt *obj.Link, a int, r int, v int32, b int, sc int) uint32 {
-	var o uint32
-
-	o = olr(ctxt, v, b, r, sc) ^ (1 << 20)
+	o := olr(ctxt, v, b, r, sc) ^ (1 << 20)
 	if a != AMOVW {
 		o |= 1 << 22
 	}
@@ -2788,9 +2729,7 @@
 }
 
 func oshr(ctxt *obj.Link, r int, v int32, b int, sc int) uint32 {
-	var o uint32
-
-	o = olhr(ctxt, v, b, r, sc) ^ (1 << 20)
+	o := olhr(ctxt, v, b, r, sc) ^ (1 << 20)
 	return o
 }
 
@@ -2811,12 +2750,10 @@
 }
 
 func ofsr(ctxt *obj.Link, a int, r int, v int32, b int, sc int, p *obj.Prog) uint32 {
-	var o uint32
-
 	if sc&C_SBIT != 0 {
 		ctxt.Diag(".nil on FLDR/FSTR instruction")
 	}
-	o = ((uint32(sc) & C_SCOND) ^ C_SCOND_XOR) << 28
+	o := ((uint32(sc) & C_SCOND) ^ C_SCOND_XOR) << 28
 	if sc&C_PBIT == 0 {
 		o |= 1 << 24
 	}
@@ -2840,7 +2777,7 @@
 
 	switch a {
 	default:
-		ctxt.Diag("bad fst %v", Aconv(a))
+		ctxt.Diag("bad fst %v", obj.Aconv(a))
 		fallthrough
 
 	case AMOVD:
@@ -2855,11 +2792,10 @@
 }
 
 func omvl(ctxt *obj.Link, p *obj.Prog, a *obj.Addr, dr int) uint32 {
-	var v int32
 	var o1 uint32
 	if p.Pcond == nil {
 		aclass(ctxt, a)
-		v = immrot(^uint32(ctxt.Instoffset))
+		v := immrot(^uint32(ctxt.Instoffset))
 		if v == 0 {
 			ctxt.Diag("missing literal")
 			prasm(p)
@@ -2870,7 +2806,7 @@
 		o1 |= uint32(v)
 		o1 |= (uint32(dr) & 15) << 12
 	} else {
-		v = int32(p.Pcond.Pc - p.Pc - 8)
+		v := int32(p.Pcond.Pc - p.Pc - 8)
 		o1 = olr(ctxt, v, REGPC, dr, int(p.Scond)&C_SCOND)
 	}
 
@@ -2886,29 +2822,23 @@
 }
 
 func chipfloat5(ctxt *obj.Link, e float64) int {
-	var n int
-	var h1 uint32
-	var l uint32
-	var h uint32
-	var ei uint64
-
 	// We use GOARM=7 to gate the use of VFPv3 vmov (imm) instructions.
 	if ctxt.Goarm < 7 {
-		goto no
+		return -1
 	}
 
-	ei = math.Float64bits(e)
-	l = uint32(ei)
-	h = uint32(ei >> 32)
+	ei := math.Float64bits(e)
+	l := uint32(ei)
+	h := uint32(ei >> 32)
 
 	if l != 0 || h&0xffff != 0 {
-		goto no
+		return -1
 	}
-	h1 = h & 0x7fc00000
+	h1 := h & 0x7fc00000
 	if h1 != 0x40000000 && h1 != 0x3fc00000 {
-		goto no
+		return -1
 	}
-	n = 0
+	n := 0
 
 	// sign bit (a)
 	if h&0x80000000 != 0 {
@@ -2925,7 +2855,4 @@
 
 	//print("match %.8lux %.8lux %d\n", l, h, n);
 	return n
-
-no:
-	return -1
 }
diff --git a/src/cmd/internal/obj/arm/list5.go b/src/cmd/internal/obj/arm/list5.go
index 70280f3..bb2ac20 100644
--- a/src/cmd/internal/obj/arm/list5.go
+++ b/src/cmd/internal/obj/arm/list5.go
@@ -35,128 +35,19 @@
 	"fmt"
 )
 
-const (
-	STRINGSZ = 1000
-)
-
-var extra = []string{
-	".EQ",
-	".NE",
-	".CS",
-	".CC",
-	".MI",
-	".PL",
-	".VS",
-	".VC",
-	".HI",
-	".LS",
-	".GE",
-	".LT",
-	".GT",
-	".LE",
-	"",
-	".NV",
-}
-
-var bigP *obj.Prog
-
-func Pconv(p *obj.Prog) string {
-	var str string
-	var sc string
-	var fp string
-
-	var a int
-	var s int
-
-	a = int(p.As)
-	s = int(p.Scond)
-	sc = extra[(s&C_SCOND)^C_SCOND_XOR]
-	if s&C_SBIT != 0 {
-		sc += ".S"
-	}
-	if s&C_PBIT != 0 {
-		sc += ".P"
-	}
-	if s&C_WBIT != 0 {
-		sc += ".W"
-	}
-	if s&C_UBIT != 0 { /* ambiguous with FBIT */
-		sc += ".U"
-	}
-	if a == obj.ADATA {
-		str = fmt.Sprintf("%.5d (%v)\t%v\t%v/%d,%v",
-			p.Pc, p.Line(), Aconv(a), obj.Dconv(p, &p.From), p.From3.Offset, obj.Dconv(p, &p.To))
-	} else if p.As == obj.ATEXT {
-		str = fmt.Sprintf("%.5d (%v)\t%v\t%v,%d,%v",
-			p.Pc, p.Line(), Aconv(a), obj.Dconv(p, &p.From), p.From3.Offset, obj.Dconv(p, &p.To))
-	} else if p.Reg == 0 {
-		str = fmt.Sprintf("%.5d (%v)\t%v%s\t%v,%v",
-			p.Pc, p.Line(), Aconv(a), sc, obj.Dconv(p, &p.From), obj.Dconv(p, &p.To))
-	} else {
-		str = fmt.Sprintf("%.5d (%v)\t%v%s\t%v,%v,%v",
-			p.Pc, p.Line(), Aconv(a), sc, obj.Dconv(p, &p.From), Rconv(int(p.Reg)), obj.Dconv(p, &p.To))
-	}
-
-	fp += str
-	return fp
-}
-
-func Aconv(a int) string {
-	var s string
-	var fp string
-
-	s = "???"
-	if a >= obj.AXXX && a < ALAST {
-		s = Anames[a]
-	}
-	fp += s
-	return fp
-}
-
-func RAconv(a *obj.Addr) string {
-	var str string
-	var fp string
-
-	var i int
-	var v int
-
-	str = fmt.Sprintf("GOK-reglist")
-	switch a.Type {
-	case obj.TYPE_CONST:
-		if a.Reg != 0 {
-			break
-		}
-		if a.Sym != nil {
-			break
-		}
-		v = int(a.Offset)
-		str = ""
-		for i = 0; i < NREG; i++ {
-			if v&(1<<uint(i)) != 0 {
-				if str == "" {
-					str += "[R"
-				} else {
-					str += ",R"
-				}
-				str += fmt.Sprintf("%d", i)
-			}
-		}
-
-		str += "]"
-	}
-
-	fp += str
-	return fp
-}
-
 func init() {
 	obj.RegisterRegister(obj.RBaseARM, MAXREG, Rconv)
+	obj.RegisterOpcode(obj.ABaseARM, Anames)
 }
 
 func Rconv(r int) string {
 	if r == 0 {
 		return "NONE"
 	}
+	if r == REGG {
+		// Special case.
+		return "g"
+	}
 	if REG_R0 <= r && r <= REG_R15 {
 		return fmt.Sprintf("R%d", r-REG_R0)
 	}
@@ -182,13 +73,11 @@
 }
 
 func DRconv(a int) string {
-	var s string
-	var fp string
-
-	s = "C_??"
+	s := "C_??"
 	if a >= C_NONE && a <= C_NCLASS {
 		s = cnames5[a]
 	}
+	var fp string
 	fp += s
 	return fp
 }
diff --git a/src/cmd/internal/obj/arm/obj5.go b/src/cmd/internal/obj/arm/obj5.go
index 67042c0..793a2b6 100644
--- a/src/cmd/internal/obj/arm/obj5.go
+++ b/src/cmd/internal/obj/arm/obj5.go
@@ -41,9 +41,6 @@
 var progedit_tlsfallback *obj.LSym
 
 func progedit(ctxt *obj.Link, p *obj.Prog) {
-	var literal string
-	var s *obj.LSym
-
 	p.From.Class = 0
 	p.To.Class = 0
 
@@ -110,13 +107,11 @@
 	// Rewrite float constants to values stored in memory.
 	switch p.As {
 	case AMOVF:
-		if p.From.Type == obj.TYPE_FCONST && chipfloat5(ctxt, p.From.U.Dval) < 0 && (chipzero5(ctxt, p.From.U.Dval) < 0 || p.Scond&C_SCOND != C_SCOND_NONE) {
-			var i32 uint32
-			var f32 float32
-			f32 = float32(p.From.U.Dval)
-			i32 = math.Float32bits(f32)
-			literal = fmt.Sprintf("$f32.%08x", i32)
-			s = obj.Linklookup(ctxt, literal, 0)
+		if p.From.Type == obj.TYPE_FCONST && chipfloat5(ctxt, p.From.Val.(float64)) < 0 && (chipzero5(ctxt, p.From.Val.(float64)) < 0 || p.Scond&C_SCOND != C_SCOND_NONE) {
+			f32 := float32(p.From.Val.(float64))
+			i32 := math.Float32bits(f32)
+			literal := fmt.Sprintf("$f32.%08x", i32)
+			s := obj.Linklookup(ctxt, literal, 0)
 			if s.Type == 0 {
 				s.Type = obj.SRODATA
 				obj.Adduint32(ctxt, s, i32)
@@ -130,11 +125,10 @@
 		}
 
 	case AMOVD:
-		if p.From.Type == obj.TYPE_FCONST && chipfloat5(ctxt, p.From.U.Dval) < 0 && (chipzero5(ctxt, p.From.U.Dval) < 0 || p.Scond&C_SCOND != C_SCOND_NONE) {
-			var i64 uint64
-			i64 = math.Float64bits(p.From.U.Dval)
-			literal = fmt.Sprintf("$f64.%016x", i64)
-			s = obj.Linklookup(ctxt, literal, 0)
+		if p.From.Type == obj.TYPE_FCONST && chipfloat5(ctxt, p.From.Val.(float64)) < 0 && (chipzero5(ctxt, p.From.Val.(float64)) < 0 || p.Scond&C_SCOND != C_SCOND_NONE) {
+			i64 := math.Float64bits(p.From.Val.(float64))
+			literal := fmt.Sprintf("$f64.%016x", i64)
+			s := obj.Linklookup(ctxt, literal, 0)
 			if s.Type == 0 {
 				s.Type = obj.SRODATA
 				obj.Adduint64(ctxt, s, i64)
@@ -175,9 +169,7 @@
 )
 
 func linkcase(casep *obj.Prog) {
-	var p *obj.Prog
-
-	for p = casep; p != nil; p = p.Link {
+	for p := casep; p != nil; p = p.Link {
 		if p.As == ABCASE {
 			for ; p != nil && p.As == ABCASE; p = p.Link {
 				p.Pcrel = casep
@@ -188,26 +180,13 @@
 }
 
 func preprocess(ctxt *obj.Link, cursym *obj.LSym) {
-	var p *obj.Prog
-	var pl *obj.Prog
-	var p1 *obj.Prog
-	var p2 *obj.Prog
-	var q *obj.Prog
-	var q1 *obj.Prog
-	var q2 *obj.Prog
-	var o int
-	var autosize int32
-	var autoffset int32
-
-	autosize = 0
+	autosize := int32(0)
 
 	if ctxt.Symmorestack[0] == nil {
 		ctxt.Symmorestack[0] = obj.Linklookup(ctxt, "runtime.morestack", 0)
 		ctxt.Symmorestack[1] = obj.Linklookup(ctxt, "runtime.morestack_noctxt", 0)
 	}
 
-	q = nil
-
 	ctxt.Cursym = cursym
 
 	if cursym.Text == nil || cursym.Text.Link == nil {
@@ -216,13 +195,13 @@
 
 	softfloat(ctxt, cursym)
 
-	p = cursym.Text
-	autoffset = int32(p.To.Offset)
+	p := cursym.Text
+	autoffset := int32(p.To.Offset)
 	if autoffset < 0 {
 		autoffset = 0
 	}
 	cursym.Locals = autoffset
-	cursym.Args = p.To.U.Argsize
+	cursym.Args = p.To.Val.(int32)
 
 	if ctxt.Debugzerostack != 0 {
 		if autoffset != 0 && p.From3.Offset&obj.NOSPLIT == 0 {
@@ -259,8 +238,8 @@
 			//	MOVW.nil R3, 0(R1) +4
 			//	CMP R1, R2
 			//	BNE L
-			pl = obj.Appendp(ctxt, p)
-			p = pl
+			pl := obj.Appendp(ctxt, p)
+			p := pl
 
 			p.As = AMOVW
 			p.From.Type = obj.TYPE_REG
@@ -289,7 +268,9 @@
 	 * expand RET
 	 * expand BECOME pseudo
 	 */
-	for p = cursym.Text; p != nil; p = p.Link {
+	var q1 *obj.Prog
+	var q *obj.Prog
+	for p := cursym.Text; p != nil; p = p.Link {
 		switch p.As {
 		case ACASE:
 			if ctxt.Flag_shared != 0 {
@@ -302,10 +283,7 @@
 		case obj.ARET:
 			break
 
-		case ADIV,
-			ADIVU,
-			AMOD,
-			AMODU:
+		case ADIV, ADIVU, AMOD, AMODU:
 			q = p
 			if ctxt.Sym_div == nil {
 				initdiv(ctxt)
@@ -358,7 +336,11 @@
 		q = p
 	}
 
-	for p = cursym.Text; p != nil; p = p.Link {
+	var o int
+	var p1 *obj.Prog
+	var p2 *obj.Prog
+	var q2 *obj.Prog
+	for p := cursym.Text; p != nil; p = p.Link {
 		o = int(p.As)
 		switch o {
 		case obj.ATEXT:
@@ -539,10 +521,7 @@
 				p.Spadj = int32(p.From.Offset)
 			}
 
-		case ADIV,
-			ADIVU,
-			AMOD,
-			AMODU:
+		case ADIV, ADIVU, AMOD, AMODU:
 			if ctxt.Debugdivmod != 0 {
 				break
 			}
@@ -667,24 +646,20 @@
 }
 
 func softfloat(ctxt *obj.Link, cursym *obj.LSym) {
-	var p *obj.Prog
-	var next *obj.Prog
-	var symsfloat *obj.LSym
-	var wasfloat int
-
 	if ctxt.Goarm > 5 {
 		return
 	}
 
-	symsfloat = obj.Linklookup(ctxt, "_sfloat", 0)
+	symsfloat := obj.Linklookup(ctxt, "_sfloat", 0)
 
-	wasfloat = 0
-	for p = cursym.Text; p != nil; p = p.Link {
+	wasfloat := 0
+	for p := cursym.Text; p != nil; p = p.Link {
 		if p.Pcond != nil {
 			p.Pcond.Mark |= LABEL
 		}
 	}
-	for p = cursym.Text; p != nil; p = p.Link {
+	var next *obj.Prog
+	for p := cursym.Text; p != nil; p = p.Link {
 		switch p.As {
 		case AMOVW:
 			if isfloatreg(&p.To) || isfloatreg(&p.From) {
@@ -880,13 +855,10 @@
 }
 
 func follow(ctxt *obj.Link, s *obj.LSym) {
-	var firstp *obj.Prog
-	var lastp *obj.Prog
-
 	ctxt.Cursym = s
 
-	firstp = ctxt.NewProg()
-	lastp = firstp
+	firstp := ctxt.NewProg()
+	lastp := firstp
 	xfol(ctxt, s.Text, &lastp)
 	lastp.Link = nil
 	s.Text = firstp.Link
@@ -957,7 +929,7 @@
 	if p.Mark&FOLL != 0 {
 		i = 0
 		q = p
-		for ; i < 4; (func() { i++; q = q.Link })() {
+		for ; i < 4; i, q = i+1, q.Link {
 			if q == *last || q == nil {
 				break
 			}
@@ -1060,17 +1032,20 @@
 	goto loop
 }
 
+var unaryDst = map[int]bool{
+	ASWI:  true,
+	AWORD: true,
+}
+
 var Linkarm = obj.LinkArch{
-	Rconv:      Rconv,
 	ByteOrder:  binary.LittleEndian,
-	Pconv:      Pconv,
 	Name:       "arm",
 	Thechar:    '5',
-	Endian:     obj.LittleEndian,
 	Preprocess: preprocess,
 	Assemble:   span5,
 	Follow:     follow,
 	Progedit:   progedit,
+	UnaryDst:   unaryDst,
 	Minlc:      4,
 	Ptrsize:    4,
 	Regsize:    4,
diff --git a/src/cmd/internal/obj/arm64/7.out.go b/src/cmd/internal/obj/arm64/7.out.go
new file mode 100644
index 0000000..67b37aa
--- /dev/null
+++ b/src/cmd/internal/obj/arm64/7.out.go
@@ -0,0 +1,711 @@
+// cmd/7c/7.out.h  from Vita Nuova.
+// https://code.google.com/p/ken-cc/source/browse/src/cmd/7c/7.out.h
+//
+// 	Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
+// 	Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
+// 	Portions Copyright © 1997-1999 Vita Nuova Limited
+// 	Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
+// 	Portions Copyright © 2004,2006 Bruce Ellis
+// 	Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
+// 	Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
+// 	Portions Copyright © 2009 The Go Authors.  All rights reserved.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+package arm64
+
+import "cmd/internal/obj"
+
+const (
+	NSNAME = 8
+	NSYM   = 50
+	NREG   = 32 /* number of general registers */
+	NFREG  = 32 /* number of floating point registers */
+)
+
+// General purpose registers, kept in the low bits of Prog.Reg.
+const (
+	// integer
+	REG_R0 = obj.RBaseARM64 + iota
+	REG_R1
+	REG_R2
+	REG_R3
+	REG_R4
+	REG_R5
+	REG_R6
+	REG_R7
+	REG_R8
+	REG_R9
+	REG_R10
+	REG_R11
+	REG_R12
+	REG_R13
+	REG_R14
+	REG_R15
+	REG_R16
+	REG_R17
+	REG_R18
+	REG_R19
+	REG_R20
+	REG_R21
+	REG_R22
+	REG_R23
+	REG_R24
+	REG_R25
+	REG_R26
+	REG_R27
+	REG_R28
+	REG_R29
+	REG_R30
+	REG_R31
+
+	// scalar floating point
+	REG_F0
+	REG_F1
+	REG_F2
+	REG_F3
+	REG_F4
+	REG_F5
+	REG_F6
+	REG_F7
+	REG_F8
+	REG_F9
+	REG_F10
+	REG_F11
+	REG_F12
+	REG_F13
+	REG_F14
+	REG_F15
+	REG_F16
+	REG_F17
+	REG_F18
+	REG_F19
+	REG_F20
+	REG_F21
+	REG_F22
+	REG_F23
+	REG_F24
+	REG_F25
+	REG_F26
+	REG_F27
+	REG_F28
+	REG_F29
+	REG_F30
+	REG_F31
+
+	// SIMD
+	REG_V0
+	REG_V1
+	REG_V2
+	REG_V3
+	REG_V4
+	REG_V5
+	REG_V6
+	REG_V7
+	REG_V8
+	REG_V9
+	REG_V10
+	REG_V11
+	REG_V12
+	REG_V13
+	REG_V14
+	REG_V15
+	REG_V16
+	REG_V17
+	REG_V18
+	REG_V19
+	REG_V20
+	REG_V21
+	REG_V22
+	REG_V23
+	REG_V24
+	REG_V25
+	REG_V26
+	REG_V27
+	REG_V28
+	REG_V29
+	REG_V30
+	REG_V31
+
+	// The EQ in
+	// 	CSET	EQ, R0
+	// is encoded as TYPE_REG, even though it's not really a register.
+	COND_EQ
+	COND_NE
+	COND_HS
+	COND_LO
+	COND_MI
+	COND_PL
+	COND_VS
+	COND_VC
+	COND_HI
+	COND_LS
+	COND_GE
+	COND_LT
+	COND_GT
+	COND_LE
+	COND_AL
+	COND_NV
+
+	REG_RSP = REG_V31 + 32 // to differentiate ZR/SP, REG_RSP&0x1f = 31
+)
+
+// Not registers, but flags that can be combined with regular register
+// constants to indicate extended register conversion.  When checking,
+// you should subtract obj.RBaseARM64 first. From this difference, bit 11
+// indicates extended register, bits 8-10 select the conversion mode.
+const REG_EXT = obj.RBaseARM64 + 1<<11
+
+const (
+	REG_UXTB = REG_EXT + iota<<8
+	REG_UXTH
+	REG_UXTW
+	REG_UXTX
+	REG_SXTB
+	REG_SXTH
+	REG_SXTW
+	REG_SXTX
+)
+
+// Special registers, after subtracting obj.RBaseARM64, bit 12 indicates
+// a special register and the low bits select the register.
+const (
+	REG_SPECIAL = obj.RBaseARM64 + 1<<12 + iota
+	REG_DAIF
+	REG_NZCV
+	REG_FPSR
+	REG_FPCR
+	REG_SPSR_EL1
+	REG_ELR_EL1
+	REG_SPSR_EL2
+	REG_ELR_EL2
+	REG_CurrentEL
+	REG_SP_EL0
+	REG_SPSel
+	REG_DAIFSet
+	REG_DAIFClr
+)
+
+// Register assignments:
+//
+// compiler allocates R0 up as temps
+// compiler allocates register variables R7-R25
+// compiler allocates external registers R26 down
+//
+// compiler allocates register variables F7-F26
+// compiler allocates external registers F26 down
+const (
+	REGMIN = REG_R7  // register variables allocated from here to REGMAX
+	REGRT1 = REG_R16 // ARM64 IP0, for external linker, runtime, duffzero and duffcopy
+	REGRT2 = REG_R17 // ARM64 IP1, for external linker, runtime, duffcopy
+	REGPR  = REG_R18 // ARM64 platform register, unused in the Go toolchain
+	REGMAX = REG_R25
+
+	REGCTXT = REG_R26 // environment for closures
+	REGTMP  = REG_R27 // reserved for liblink
+	REGG    = REG_R28 // G
+	REGFP   = REG_R29 // frame pointer, unused in the Go toolchain
+	REGLINK = REG_R30
+
+	// ARM64 uses R31 as both stack pointer and zero register,
+	// depending on the instruction. To differentiate RSP from ZR,
+	// we use a different numeric value for REGZERO and REGSP.
+	REGZERO = REG_R31
+	REGSP   = REG_RSP
+
+	FREGRET  = REG_F0
+	FREGMIN  = REG_F7  // first register variable
+	FREGMAX  = REG_F26 // last register variable for 7g only
+	FREGEXT  = REG_F26 // first external register
+	FREGZERO = REG_F28 // both float and double
+	FREGHALF = REG_F29 // double
+	FREGONE  = REG_F30 // double
+	FREGTWO  = REG_F31 // double
+)
+
+const (
+	BIG = 2048 - 8
+)
+
+const (
+	/* mark flags */
+	LABEL = 1 << iota
+	LEAF
+	FLOAT
+	BRANCH
+	LOAD
+	FCMP
+	SYNC
+	LIST
+	FOLL
+	NOSCHED
+)
+
+const (
+	C_NONE   = iota
+	C_REG    // R0..R30
+	C_RSP    // R0..R30, RSP
+	C_FREG   // F0..F31
+	C_VREG   // V0..V31
+	C_PAIR   // (Rn, Rm)
+	C_SHIFT  // Rn<<2
+	C_EXTREG // Rn.UXTB<<3
+	C_SPR    // REG_NZCV
+	C_COND   // EQ, NE, etc
+
+	C_ZCON     // $0 or ZR
+	C_ADDCON0  // 12-bit unsigned, unshifted
+	C_ADDCON   // 12-bit unsigned, shifted left by 0 or 12
+	C_MOVCON   // generated by a 16-bit constant, optionally inverted and/or shifted by multiple of 16
+	C_BITCON   // bitfield and logical immediate masks
+	C_ABCON    // could be C_ADDCON or C_BITCON
+	C_MBCON    // could be C_MOVCON or C_BITCON
+	C_LCON     // 32-bit constant
+	C_VCON     // 64-bit constant
+	C_FCON     // floating-point constant
+	C_VCONADDR // 64-bit memory address
+
+	C_AACON // ADDCON offset in auto constant $a(FP)
+	C_LACON // 32-bit offset in auto constant $a(FP)
+	C_AECON // ADDCON offset in extern constant $e(SB)
+
+	// TODO(aram): only one branch class should be enough
+	C_SBRA // for TYPE_BRANCH
+	C_LBRA
+
+	C_NPAUTO   // -512 <= x < 0, 0 mod 8
+	C_NSAUTO   // -256 <= x < 0
+	C_PSAUTO   // 0 to 255
+	C_PPAUTO   // 0 to 504, 0 mod 8
+	C_UAUTO4K  // 0 to 4095
+	C_UAUTO8K  // 0 to 8190, 0 mod 2
+	C_UAUTO16K // 0 to 16380, 0 mod 4
+	C_UAUTO32K // 0 to 32760, 0 mod 8
+	C_UAUTO64K // 0 to 65520, 0 mod 16
+	C_LAUTO    // any other 32-bit constant
+
+	C_SEXT1  // 0 to 4095, direct
+	C_SEXT2  // 0 to 8190
+	C_SEXT4  // 0 to 16380
+	C_SEXT8  // 0 to 32760
+	C_SEXT16 // 0 to 65520
+	C_LEXT
+
+	// TODO(aram): s/AUTO/INDIR/
+	C_ZOREG  // 0(R)
+	C_NPOREG // mirror NPAUTO, etc
+	C_NSOREG
+	C_PSOREG
+	C_PPOREG
+	C_UOREG4K
+	C_UOREG8K
+	C_UOREG16K
+	C_UOREG32K
+	C_UOREG64K
+	C_LOREG
+
+	C_ADDR // TODO(aram): explain difference from C_VCONADDR
+	C_ROFF // register offset (including register extended)
+
+	C_GOK
+	C_TEXTSIZE
+	C_NCLASS // must be last
+)
+
+const (
+	C_XPRE  = 1 << 6 // match arm.C_WBIT, so Prog.String know how to print it
+	C_XPOST = 1 << 5 // match arm.C_PBIT, so Prog.String know how to print it
+)
+
+//go:generate go run ../stringer.go -i $GOFILE -o anames.go -p arm64
+
+const (
+	AADC = obj.ABaseARM64 + obj.A_ARCHSPECIFIC + iota
+	AADCS
+	AADCSW
+	AADCW
+	AADD
+	AADDS
+	AADDSW
+	AADDW
+	AADR
+	AADRP
+	AAND
+	AANDS
+	AANDSW
+	AANDW
+	AASR
+	AASRW
+	AAT
+	ABFI
+	ABFIW
+	ABFM
+	ABFMW
+	ABFXIL
+	ABFXILW
+	ABIC
+	ABICS
+	ABICSW
+	ABICW
+	ABRK
+	ACBNZ
+	ACBNZW
+	ACBZ
+	ACBZW
+	ACCMN
+	ACCMNW
+	ACCMP
+	ACCMPW
+	ACINC
+	ACINCW
+	ACINV
+	ACINVW
+	ACLREX
+	ACLS
+	ACLSW
+	ACLZ
+	ACLZW
+	ACMN
+	ACMNW
+	ACMP
+	ACMPW
+	ACNEG
+	ACNEGW
+	ACRC32B
+	ACRC32CB
+	ACRC32CH
+	ACRC32CW
+	ACRC32CX
+	ACRC32H
+	ACRC32W
+	ACRC32X
+	ACSEL
+	ACSELW
+	ACSET
+	ACSETM
+	ACSETMW
+	ACSETW
+	ACSINC
+	ACSINCW
+	ACSINV
+	ACSINVW
+	ACSNEG
+	ACSNEGW
+	ADC
+	ADCPS1
+	ADCPS2
+	ADCPS3
+	ADMB
+	ADRPS
+	ADSB
+	AEON
+	AEONW
+	AEOR
+	AEORW
+	AERET
+	AEXTR
+	AEXTRW
+	AHINT
+	AHLT
+	AHVC
+	AIC
+	AISB
+	ALDAR
+	ALDARB
+	ALDARH
+	ALDARW
+	ALDAXP
+	ALDAXPW
+	ALDAXR
+	ALDAXRB
+	ALDAXRH
+	ALDAXRW
+	ALDP
+	ALDXR
+	ALDXRB
+	ALDXRH
+	ALDXRW
+	ALDXP
+	ALDXPW
+	ALSL
+	ALSLW
+	ALSR
+	ALSRW
+	AMADD
+	AMADDW
+	AMNEG
+	AMNEGW
+	AMOVK
+	AMOVKW
+	AMOVN
+	AMOVNW
+	AMOVZ
+	AMOVZW
+	AMRS
+	AMSR
+	AMSUB
+	AMSUBW
+	AMUL
+	AMULW
+	AMVN
+	AMVNW
+	ANEG
+	ANEGS
+	ANEGSW
+	ANEGW
+	ANGC
+	ANGCS
+	ANGCSW
+	ANGCW
+	AORN
+	AORNW
+	AORR
+	AORRW
+	APRFM
+	APRFUM
+	ARBIT
+	ARBITW
+	AREM
+	AREMW
+	AREV
+	AREV16
+	AREV16W
+	AREV32
+	AREVW
+	AROR
+	ARORW
+	ASBC
+	ASBCS
+	ASBCSW
+	ASBCW
+	ASBFIZ
+	ASBFIZW
+	ASBFM
+	ASBFMW
+	ASBFX
+	ASBFXW
+	ASDIV
+	ASDIVW
+	ASEV
+	ASEVL
+	ASMADDL
+	ASMC
+	ASMNEGL
+	ASMSUBL
+	ASMULH
+	ASMULL
+	ASTXR
+	ASTXRB
+	ASTXRH
+	ASTXP
+	ASTXPW
+	ASTXRW
+	ASTLP
+	ASTLPW
+	ASTLR
+	ASTLRB
+	ASTLRH
+	ASTLRW
+	ASTLXP
+	ASTLXPW
+	ASTLXR
+	ASTLXRB
+	ASTLXRH
+	ASTLXRW
+	ASTP
+	ASUB
+	ASUBS
+	ASUBSW
+	ASUBW
+	ASVC
+	ASXTB
+	ASXTBW
+	ASXTH
+	ASXTHW
+	ASXTW
+	ASYS
+	ASYSL
+	ATBNZ
+	ATBZ
+	ATLBI
+	ATST
+	ATSTW
+	AUBFIZ
+	AUBFIZW
+	AUBFM
+	AUBFMW
+	AUBFX
+	AUBFXW
+	AUDIV
+	AUDIVW
+	AUMADDL
+	AUMNEGL
+	AUMSUBL
+	AUMULH
+	AUMULL
+	AUREM
+	AUREMW
+	AUXTB
+	AUXTH
+	AUXTW
+	AUXTBW
+	AUXTHW
+	AWFE
+	AWFI
+	AYIELD
+	AMOVB
+	AMOVBU
+	AMOVH
+	AMOVHU
+	AMOVW
+	AMOVWU
+	AMOVD
+	AMOVNP
+	AMOVNPW
+	AMOVP
+	AMOVPD
+	AMOVPQ
+	AMOVPS
+	AMOVPSW
+	AMOVPW
+	ABEQ
+	ABNE
+	ABCS
+	ABHS
+	ABCC
+	ABLO
+	ABMI
+	ABPL
+	ABVS
+	ABVC
+	ABHI
+	ABLS
+	ABGE
+	ABLT
+	ABGT
+	ABLE
+	AFABSD
+	AFABSS
+	AFADDD
+	AFADDS
+	AFCCMPD
+	AFCCMPED
+	AFCCMPS
+	AFCCMPES
+	AFCMPD
+	AFCMPED
+	AFCMPES
+	AFCMPS
+	AFCVTSD
+	AFCVTDS
+	AFCVTZSD
+	AFCVTZSDW
+	AFCVTZSS
+	AFCVTZSSW
+	AFCVTZUD
+	AFCVTZUDW
+	AFCVTZUS
+	AFCVTZUSW
+	AFDIVD
+	AFDIVS
+	AFMOVD
+	AFMOVS
+	AFMULD
+	AFMULS
+	AFNEGD
+	AFNEGS
+	AFSQRTD
+	AFSQRTS
+	AFSUBD
+	AFSUBS
+	ASCVTFD
+	ASCVTFS
+	ASCVTFWD
+	ASCVTFWS
+	AUCVTFD
+	AUCVTFS
+	AUCVTFWD
+	AUCVTFWS
+	AHISTORY
+	ANAME
+	AWORD
+	ADYNT
+	AINIT
+	ABCASE
+	ACASE
+	ADWORD
+	ASIGNAME
+	AGOK
+	AEND
+	AFCSELS
+	AFCSELD
+	AFMAXS
+	AFMINS
+	AFMAXD
+	AFMIND
+	AFMAXNMS
+	AFMAXNMD
+	AFNMULS
+	AFNMULD
+	AFRINTNS
+	AFRINTND
+	AFRINTPS
+	AFRINTPD
+	AFRINTMS
+	AFRINTMD
+	AFRINTZS
+	AFRINTZD
+	AFRINTAS
+	AFRINTAD
+	AFRINTXS
+	AFRINTXD
+	AFRINTIS
+	AFRINTID
+	AFMADDS
+	AFMADDD
+	AFMSUBS
+	AFMSUBD
+	AFNMADDS
+	AFNMADDD
+	AFNMSUBS
+	AFNMSUBD
+	AFMINNMS
+	AFMINNMD
+	AFCVTDH
+	AFCVTHS
+	AFCVTHD
+	AFCVTSH
+	AAESD
+	AAESE
+	AAESIMC
+	AAESMC
+	ASHA1C
+	ASHA1H
+	ASHA1M
+	ASHA1P
+	ASHA1SU0
+	ASHA1SU1
+	ASHA256H
+	ASHA256H2
+	ASHA256SU0
+	ASHA256SU1
+	ALAST
+	AB  = obj.AJMP
+	ABL = obj.ACALL
+)
diff --git a/src/cmd/internal/obj/arm64/anames.go b/src/cmd/internal/obj/arm64/anames.go
new file mode 100644
index 0000000..924e698
--- /dev/null
+++ b/src/cmd/internal/obj/arm64/anames.go
@@ -0,0 +1,379 @@
+// Generated by stringer -i 7.out.go -o anames.go -p arm64
+// Do not edit.
+
+package arm64
+
+import "cmd/internal/obj"
+
+var Anames = []string{
+	obj.A_ARCHSPECIFIC: "ADC",
+	"ADCS",
+	"ADCSW",
+	"ADCW",
+	"ADD",
+	"ADDS",
+	"ADDSW",
+	"ADDW",
+	"ADR",
+	"ADRP",
+	"AND",
+	"ANDS",
+	"ANDSW",
+	"ANDW",
+	"ASR",
+	"ASRW",
+	"AT",
+	"BFI",
+	"BFIW",
+	"BFM",
+	"BFMW",
+	"BFXIL",
+	"BFXILW",
+	"BIC",
+	"BICS",
+	"BICSW",
+	"BICW",
+	"BRK",
+	"CBNZ",
+	"CBNZW",
+	"CBZ",
+	"CBZW",
+	"CCMN",
+	"CCMNW",
+	"CCMP",
+	"CCMPW",
+	"CINC",
+	"CINCW",
+	"CINV",
+	"CINVW",
+	"CLREX",
+	"CLS",
+	"CLSW",
+	"CLZ",
+	"CLZW",
+	"CMN",
+	"CMNW",
+	"CMP",
+	"CMPW",
+	"CNEG",
+	"CNEGW",
+	"CRC32B",
+	"CRC32CB",
+	"CRC32CH",
+	"CRC32CW",
+	"CRC32CX",
+	"CRC32H",
+	"CRC32W",
+	"CRC32X",
+	"CSEL",
+	"CSELW",
+	"CSET",
+	"CSETM",
+	"CSETMW",
+	"CSETW",
+	"CSINC",
+	"CSINCW",
+	"CSINV",
+	"CSINVW",
+	"CSNEG",
+	"CSNEGW",
+	"DC",
+	"DCPS1",
+	"DCPS2",
+	"DCPS3",
+	"DMB",
+	"DRPS",
+	"DSB",
+	"EON",
+	"EONW",
+	"EOR",
+	"EORW",
+	"ERET",
+	"EXTR",
+	"EXTRW",
+	"HINT",
+	"HLT",
+	"HVC",
+	"IC",
+	"ISB",
+	"LDAR",
+	"LDARB",
+	"LDARH",
+	"LDARW",
+	"LDAXP",
+	"LDAXPW",
+	"LDAXR",
+	"LDAXRB",
+	"LDAXRH",
+	"LDAXRW",
+	"LDP",
+	"LDXR",
+	"LDXRB",
+	"LDXRH",
+	"LDXRW",
+	"LDXP",
+	"LDXPW",
+	"LSL",
+	"LSLW",
+	"LSR",
+	"LSRW",
+	"MADD",
+	"MADDW",
+	"MNEG",
+	"MNEGW",
+	"MOVK",
+	"MOVKW",
+	"MOVN",
+	"MOVNW",
+	"MOVZ",
+	"MOVZW",
+	"MRS",
+	"MSR",
+	"MSUB",
+	"MSUBW",
+	"MUL",
+	"MULW",
+	"MVN",
+	"MVNW",
+	"NEG",
+	"NEGS",
+	"NEGSW",
+	"NEGW",
+	"NGC",
+	"NGCS",
+	"NGCSW",
+	"NGCW",
+	"ORN",
+	"ORNW",
+	"ORR",
+	"ORRW",
+	"PRFM",
+	"PRFUM",
+	"RBIT",
+	"RBITW",
+	"REM",
+	"REMW",
+	"REV",
+	"REV16",
+	"REV16W",
+	"REV32",
+	"REVW",
+	"ROR",
+	"RORW",
+	"SBC",
+	"SBCS",
+	"SBCSW",
+	"SBCW",
+	"SBFIZ",
+	"SBFIZW",
+	"SBFM",
+	"SBFMW",
+	"SBFX",
+	"SBFXW",
+	"SDIV",
+	"SDIVW",
+	"SEV",
+	"SEVL",
+	"SMADDL",
+	"SMC",
+	"SMNEGL",
+	"SMSUBL",
+	"SMULH",
+	"SMULL",
+	"STXR",
+	"STXRB",
+	"STXRH",
+	"STXP",
+	"STXPW",
+	"STXRW",
+	"STLP",
+	"STLPW",
+	"STLR",
+	"STLRB",
+	"STLRH",
+	"STLRW",
+	"STLXP",
+	"STLXPW",
+	"STLXR",
+	"STLXRB",
+	"STLXRH",
+	"STLXRW",
+	"STP",
+	"SUB",
+	"SUBS",
+	"SUBSW",
+	"SUBW",
+	"SVC",
+	"SXTB",
+	"SXTBW",
+	"SXTH",
+	"SXTHW",
+	"SXTW",
+	"SYS",
+	"SYSL",
+	"TBNZ",
+	"TBZ",
+	"TLBI",
+	"TST",
+	"TSTW",
+	"UBFIZ",
+	"UBFIZW",
+	"UBFM",
+	"UBFMW",
+	"UBFX",
+	"UBFXW",
+	"UDIV",
+	"UDIVW",
+	"UMADDL",
+	"UMNEGL",
+	"UMSUBL",
+	"UMULH",
+	"UMULL",
+	"UREM",
+	"UREMW",
+	"UXTB",
+	"UXTH",
+	"UXTW",
+	"UXTBW",
+	"UXTHW",
+	"WFE",
+	"WFI",
+	"YIELD",
+	"MOVB",
+	"MOVBU",
+	"MOVH",
+	"MOVHU",
+	"MOVW",
+	"MOVWU",
+	"MOVD",
+	"MOVNP",
+	"MOVNPW",
+	"MOVP",
+	"MOVPD",
+	"MOVPQ",
+	"MOVPS",
+	"MOVPSW",
+	"MOVPW",
+	"BEQ",
+	"BNE",
+	"BCS",
+	"BHS",
+	"BCC",
+	"BLO",
+	"BMI",
+	"BPL",
+	"BVS",
+	"BVC",
+	"BHI",
+	"BLS",
+	"BGE",
+	"BLT",
+	"BGT",
+	"BLE",
+	"FABSD",
+	"FABSS",
+	"FADDD",
+	"FADDS",
+	"FCCMPD",
+	"FCCMPED",
+	"FCCMPS",
+	"FCCMPES",
+	"FCMPD",
+	"FCMPED",
+	"FCMPES",
+	"FCMPS",
+	"FCVTSD",
+	"FCVTDS",
+	"FCVTZSD",
+	"FCVTZSDW",
+	"FCVTZSS",
+	"FCVTZSSW",
+	"FCVTZUD",
+	"FCVTZUDW",
+	"FCVTZUS",
+	"FCVTZUSW",
+	"FDIVD",
+	"FDIVS",
+	"FMOVD",
+	"FMOVS",
+	"FMULD",
+	"FMULS",
+	"FNEGD",
+	"FNEGS",
+	"FSQRTD",
+	"FSQRTS",
+	"FSUBD",
+	"FSUBS",
+	"SCVTFD",
+	"SCVTFS",
+	"SCVTFWD",
+	"SCVTFWS",
+	"UCVTFD",
+	"UCVTFS",
+	"UCVTFWD",
+	"UCVTFWS",
+	"HISTORY",
+	"NAME",
+	"WORD",
+	"DYNT",
+	"INIT",
+	"BCASE",
+	"CASE",
+	"DWORD",
+	"SIGNAME",
+	"GOK",
+	"END",
+	"FCSELS",
+	"FCSELD",
+	"FMAXS",
+	"FMINS",
+	"FMAXD",
+	"FMIND",
+	"FMAXNMS",
+	"FMAXNMD",
+	"FNMULS",
+	"FNMULD",
+	"FRINTNS",
+	"FRINTND",
+	"FRINTPS",
+	"FRINTPD",
+	"FRINTMS",
+	"FRINTMD",
+	"FRINTZS",
+	"FRINTZD",
+	"FRINTAS",
+	"FRINTAD",
+	"FRINTXS",
+	"FRINTXD",
+	"FRINTIS",
+	"FRINTID",
+	"FMADDS",
+	"FMADDD",
+	"FMSUBS",
+	"FMSUBD",
+	"FNMADDS",
+	"FNMADDD",
+	"FNMSUBS",
+	"FNMSUBD",
+	"FMINNMS",
+	"FMINNMD",
+	"FCVTDH",
+	"FCVTHS",
+	"FCVTHD",
+	"FCVTSH",
+	"AESD",
+	"AESE",
+	"AESIMC",
+	"AESMC",
+	"SHA1C",
+	"SHA1H",
+	"SHA1M",
+	"SHA1P",
+	"SHA1SU0",
+	"SHA1SU1",
+	"SHA256H",
+	"SHA256H2",
+	"SHA256SU0",
+	"SHA256SU1",
+	"LAST",
+}
diff --git a/src/cmd/internal/obj/arm64/anames7.go b/src/cmd/internal/obj/arm64/anames7.go
new file mode 100644
index 0000000..3ff429f
--- /dev/null
+++ b/src/cmd/internal/obj/arm64/anames7.go
@@ -0,0 +1,62 @@
+package arm64
+
+var cnames7 = []string{
+	"NONE",
+	"REG",
+	"RSP",
+	"FREG",
+	"VREG",
+	"PAIR",
+	"SHIFT",
+	"EXTREG",
+	"SPR",
+	"COND",
+	"ZCON",
+	"ADDCON0",
+	"ADDCON",
+	"MOVCON",
+	"BITCON",
+	"ABCON",
+	"MBCON",
+	"LCON",
+	"VCON",
+	"FCON",
+	"VCONADDR",
+	"AACON",
+	"LACON",
+	"AECON",
+	"SBRA",
+	"LBRA",
+	"NPAUTO",
+	"NSAUTO",
+	"PSAUTO",
+	"PPAUTO",
+	"UAUTO4K",
+	"UAUTO8K",
+	"UAUTO16K",
+	"UAUTO32K",
+	"UAUTO64K",
+	"LAUTO",
+	"SEXT1",
+	"SEXT2",
+	"SEXT4",
+	"SEXT8",
+	"SEXT16",
+	"LEXT",
+	"ZOREG",
+	"NPOREG",
+	"NSOREG",
+	"PSOREG",
+	"PPOREG",
+	"UOREG4K",
+	"UOREG8K",
+	"UOREG16K",
+	"UOREG32K",
+	"UOREG64K",
+	"LOREG",
+	"ADDR",
+	"ROFF",
+	"GOK",
+	"TEXTSIZE",
+	"NCLASS",
+}
diff --git a/src/cmd/internal/obj/arm64/asm7.go b/src/cmd/internal/obj/arm64/asm7.go
new file mode 100644
index 0000000..e35a99e
--- /dev/null
+++ b/src/cmd/internal/obj/arm64/asm7.go
@@ -0,0 +1,4141 @@
+// cmd/7l/asm.c, cmd/7l/asmout.c, cmd/7l/optab.c, cmd/7l/span.c, cmd/ld/sub.c, cmd/ld/mod.c, from Vita Nuova.
+// https://code.google.com/p/ken-cc/source/browse/
+//
+// 	Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
+// 	Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
+// 	Portions Copyright © 1997-1999 Vita Nuova Limited
+// 	Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
+// 	Portions Copyright © 2004,2006 Bruce Ellis
+// 	Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
+// 	Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
+// 	Portions Copyright © 2009 The Go Authors.  All rights reserved.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+package arm64
+
+import (
+	"cmd/internal/obj"
+	"fmt"
+	"log"
+	"math"
+	"sort"
+)
+
+const (
+	FuncAlign = 16
+)
+
+const (
+	REGFROM = 1
+)
+
+type Optab struct {
+	as    uint16
+	a1    uint8
+	a2    uint8
+	a3    uint8
+	type_ int8
+	size  int8
+	param int16
+	flag  int8
+	scond uint16
+}
+
+type Oprange struct {
+	start []Optab
+	stop  []Optab
+}
+
+var oprange [ALAST]Oprange
+
+var xcmp [C_NCLASS][C_NCLASS]uint8
+
+const (
+	S32     = 0 << 31
+	S64     = 1 << 31
+	Sbit    = 1 << 29
+	LSL0_32 = 2 << 13
+	LSL0_64 = 3 << 13
+)
+
+func OPDP2(x uint32) uint32 {
+	return 0<<30 | 0<<29 | 0xd6<<21 | x<<10
+}
+
+func OPDP3(sf uint32, op54 uint32, op31 uint32, o0 uint32) uint32 {
+	return sf<<31 | op54<<29 | 0x1B<<24 | op31<<21 | o0<<15
+}
+
+func OPBcc(x uint32) uint32 {
+	return 0x2A<<25 | 0<<24 | 0<<4 | x&15
+}
+
+func OPBLR(x uint32) uint32 {
+	/* x=0, JMP; 1, CALL; 2, RET */
+	return 0x6B<<25 | 0<<23 | x<<21 | 0x1F<<16 | 0<<10
+}
+
+func SYSOP(l uint32, op0 uint32, op1 uint32, crn uint32, crm uint32, op2 uint32, rt uint32) uint32 {
+	return 0x354<<22 | l<<21 | op0<<19 | op1<<16 | crn&15<<12 | crm&15<<8 | op2<<5 | rt
+}
+
+func SYSHINT(x uint32) uint32 {
+	return SYSOP(0, 0, 3, 2, 0, x, 0x1F)
+}
+
+func LDSTR12U(sz uint32, v uint32, opc uint32) uint32 {
+	return sz<<30 | 7<<27 | v<<26 | 1<<24 | opc<<22
+}
+
+func LDSTR9S(sz uint32, v uint32, opc uint32) uint32 {
+	return sz<<30 | 7<<27 | v<<26 | 0<<24 | opc<<22
+}
+
+func LD2STR(o uint32) uint32 {
+	return o &^ (3 << 22)
+}
+
+func LDSTX(sz uint32, o2 uint32, l uint32, o1 uint32, o0 uint32) uint32 {
+	return sz<<30 | 0x8<<24 | o2<<23 | l<<22 | o1<<21 | o0<<15
+}
+
+func FPCMP(m uint32, s uint32, type_ uint32, op uint32, op2 uint32) uint32 {
+	return m<<31 | s<<29 | 0x1E<<24 | type_<<22 | 1<<21 | op<<14 | 8<<10 | op2
+}
+
+func FPCCMP(m uint32, s uint32, type_ uint32, op uint32) uint32 {
+	return m<<31 | s<<29 | 0x1E<<24 | type_<<22 | 1<<21 | 1<<10 | op<<4
+}
+
+func FPOP1S(m uint32, s uint32, type_ uint32, op uint32) uint32 {
+	return m<<31 | s<<29 | 0x1E<<24 | type_<<22 | 1<<21 | op<<15 | 0x10<<10
+}
+
+func FPOP2S(m uint32, s uint32, type_ uint32, op uint32) uint32 {
+	return m<<31 | s<<29 | 0x1E<<24 | type_<<22 | 1<<21 | op<<12 | 2<<10
+}
+
+func FPCVTI(sf uint32, s uint32, type_ uint32, rmode uint32, op uint32) uint32 {
+	return sf<<31 | s<<29 | 0x1E<<24 | type_<<22 | 1<<21 | rmode<<19 | op<<16 | 0<<10
+}
+
+func ADR(p uint32, o uint32, rt uint32) uint32 {
+	return p<<31 | (o&3)<<29 | 0x10<<24 | ((o>>2)&0x7FFFF)<<5 | rt&31
+}
+
+func OPBIT(x uint32) uint32 {
+	return 1<<30 | 0<<29 | 0xD6<<21 | 0<<16 | x<<10
+}
+
+const (
+	LFROM = 1 << 0
+	LTO   = 1 << 1
+	LPOOL = 1 << 2
+)
+
+var optab = []Optab{
+	/* struct Optab:
+	OPCODE, from, prog->reg, to, type,size,param,flag,scond */
+	{obj.ATEXT, C_ADDR, C_NONE, C_TEXTSIZE, 0, 0, 0, 0, 0},
+
+	/* arithmetic operations */
+	{AADD, C_REG, C_REG, C_REG, 1, 4, 0, 0, 0},
+	{AADD, C_REG, C_NONE, C_REG, 1, 4, 0, 0, 0},
+	{AADC, C_REG, C_REG, C_REG, 1, 4, 0, 0, 0},
+	{AADC, C_REG, C_NONE, C_REG, 1, 4, 0, 0, 0},
+	{ANEG, C_REG, C_NONE, C_REG, 25, 4, 0, 0, 0},
+	{ANGC, C_REG, C_NONE, C_REG, 17, 4, 0, 0, 0},
+	{ACMP, C_REG, C_REG, C_NONE, 1, 4, 0, 0, 0},
+	{AADD, C_ADDCON, C_RSP, C_RSP, 2, 4, 0, 0, 0},
+	{AADD, C_ADDCON, C_NONE, C_RSP, 2, 4, 0, 0, 0},
+	{ACMP, C_ADDCON, C_RSP, C_NONE, 2, 4, 0, 0, 0},
+	// TODO: these don't work properly.
+	// {AADD, C_MBCON, C_RSP, C_RSP, 2, 4, 0, 0, 0},
+	// {AADD, C_MBCON, C_NONE, C_RSP, 2, 4, 0, 0, 0},
+	// {ACMP, C_MBCON, C_RSP, C_NONE, 2, 4, 0, 0, 0},
+	{AADD, C_VCON, C_RSP, C_RSP, 13, 8, 0, LFROM, 0},
+	{AADD, C_VCON, C_NONE, C_RSP, 13, 8, 0, LFROM, 0},
+	{ACMP, C_VCON, C_REG, C_NONE, 13, 8, 0, LFROM, 0},
+	{AADD, C_SHIFT, C_REG, C_REG, 3, 4, 0, 0, 0},
+	{AADD, C_SHIFT, C_NONE, C_REG, 3, 4, 0, 0, 0},
+	{AMVN, C_SHIFT, C_NONE, C_REG, 3, 4, 0, 0, 0},
+	{ACMP, C_SHIFT, C_REG, C_NONE, 3, 4, 0, 0, 0},
+	{ANEG, C_SHIFT, C_NONE, C_REG, 26, 4, 0, 0, 0},
+	{AADD, C_REG, C_RSP, C_RSP, 27, 4, 0, 0, 0},
+	{AADD, C_REG, C_NONE, C_RSP, 27, 4, 0, 0, 0},
+	{ACMP, C_REG, C_RSP, C_NONE, 27, 4, 0, 0, 0},
+	{AADD, C_EXTREG, C_RSP, C_RSP, 27, 4, 0, 0, 0},
+	{AADD, C_EXTREG, C_NONE, C_RSP, 27, 4, 0, 0, 0},
+	{AMVN, C_EXTREG, C_NONE, C_RSP, 27, 4, 0, 0, 0},
+	{ACMP, C_EXTREG, C_RSP, C_NONE, 27, 4, 0, 0, 0},
+	{AADD, C_REG, C_REG, C_REG, 1, 4, 0, 0, 0},
+	{AADD, C_REG, C_NONE, C_REG, 1, 4, 0, 0, 0},
+
+	/* logical operations */
+	{AAND, C_REG, C_REG, C_REG, 1, 4, 0, 0, 0},
+	{AAND, C_REG, C_NONE, C_REG, 1, 4, 0, 0, 0},
+	{ABIC, C_REG, C_REG, C_REG, 1, 4, 0, 0, 0},
+	{ABIC, C_REG, C_NONE, C_REG, 1, 4, 0, 0, 0},
+	// TODO: these don't work properly.
+	// {AAND, C_BITCON, C_REG, C_REG, 53, 4, 0, 0, 0},
+	// {AAND, C_BITCON, C_NONE, C_REG, 53, 4, 0, 0, 0},
+	// {ABIC, C_BITCON, C_REG, C_REG, 53, 4, 0, 0, 0},
+	// {ABIC, C_BITCON, C_NONE, C_REG, 53, 4, 0, 0, 0},
+	{AAND, C_VCON, C_REG, C_REG, 28, 8, 0, LFROM, 0},
+	{AAND, C_VCON, C_NONE, C_REG, 28, 8, 0, LFROM, 0},
+	{ABIC, C_VCON, C_REG, C_REG, 28, 8, 0, LFROM, 0},
+	{ABIC, C_VCON, C_NONE, C_REG, 28, 8, 0, LFROM, 0},
+	{AAND, C_SHIFT, C_REG, C_REG, 3, 4, 0, 0, 0},
+	{AAND, C_SHIFT, C_NONE, C_REG, 3, 4, 0, 0, 0},
+	{ABIC, C_SHIFT, C_REG, C_REG, 3, 4, 0, 0, 0},
+	{ABIC, C_SHIFT, C_NONE, C_REG, 3, 4, 0, 0, 0},
+	{AMOVD, C_RSP, C_NONE, C_RSP, 24, 4, 0, 0, 0},
+	{AMVN, C_REG, C_NONE, C_REG, 24, 4, 0, 0, 0},
+	{AMOVB, C_REG, C_NONE, C_REG, 45, 4, 0, 0, 0},
+	{AMOVBU, C_REG, C_NONE, C_REG, 45, 4, 0, 0, 0},
+	{AMOVH, C_REG, C_NONE, C_REG, 45, 4, 0, 0, 0}, /* also MOVHU */
+	{AMOVW, C_REG, C_NONE, C_REG, 45, 4, 0, 0, 0}, /* also MOVWU */
+	/* TODO: MVN C_SHIFT */
+
+	/* MOVs that become MOVK/MOVN/MOVZ/ADD/SUB/OR */
+	{AMOVW, C_MOVCON, C_NONE, C_REG, 32, 4, 0, 0, 0},
+	{AMOVD, C_MOVCON, C_NONE, C_REG, 32, 4, 0, 0, 0},
+
+	// TODO: these don't work properly.
+	// { AMOVW,		C_ADDCON,	C_NONE,	C_REG,		2, 4, 0 , 0},
+	// { AMOVD,		C_ADDCON,	C_NONE,	C_REG,		2, 4, 0 , 0},
+	// { AMOVW,		C_BITCON,	C_NONE,	C_REG,		53, 4, 0 , 0},
+	// { AMOVD,		C_BITCON,	C_NONE,	C_REG,		53, 4, 0 , 0},
+
+	{AMOVK, C_VCON, C_NONE, C_REG, 33, 4, 0, 0, 0},
+	{AMOVD, C_AACON, C_NONE, C_REG, 4, 4, REGFROM, 0, 0},
+	{ASDIV, C_REG, C_NONE, C_REG, 1, 4, 0, 0, 0},
+	{ASDIV, C_REG, C_REG, C_REG, 1, 4, 0, 0, 0},
+	{AB, C_NONE, C_NONE, C_SBRA, 5, 4, 0, 0, 0},
+	{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},
+	{AADRP, C_SBRA, C_NONE, C_REG, 60, 4, 0, 0, 0},
+	{AADR, C_SBRA, C_NONE, C_REG, 61, 4, 0, 0, 0},
+	{ABFM, C_VCON, C_REG, C_REG, 42, 4, 0, 0, 0},
+	{ABFI, C_VCON, C_REG, C_REG, 43, 4, 0, 0, 0},
+	{AEXTR, C_VCON, C_REG, C_REG, 44, 4, 0, 0, 0},
+	{ASXTB, C_REG, C_NONE, C_REG, 45, 4, 0, 0, 0},
+	{ACLS, C_REG, C_NONE, C_REG, 46, 4, 0, 0, 0},
+	{ABEQ, C_NONE, C_NONE, C_SBRA, 7, 4, 0, 0, 0},
+	{ALSL, C_VCON, C_REG, C_REG, 8, 4, 0, 0, 0},
+	{ALSL, C_VCON, C_NONE, C_REG, 8, 4, 0, 0, 0},
+	{ALSL, C_REG, C_NONE, C_REG, 9, 4, 0, 0, 0},
+	{ALSL, C_REG, C_REG, C_REG, 9, 4, 0, 0, 0},
+	{ASVC, C_NONE, C_NONE, C_VCON, 10, 4, 0, 0, 0},
+	{ASVC, C_NONE, C_NONE, C_NONE, 10, 4, 0, 0, 0},
+	{ADWORD, C_NONE, C_NONE, C_VCON, 11, 8, 0, 0, 0},
+	{ADWORD, C_NONE, C_NONE, C_LEXT, 11, 8, 0, 0, 0},
+	{ADWORD, C_NONE, C_NONE, C_ADDR, 11, 8, 0, 0, 0},
+	{ADWORD, C_NONE, C_NONE, C_LACON, 11, 8, 0, 0, 0},
+	{AWORD, C_NONE, C_NONE, C_LCON, 14, 4, 0, 0, 0},
+	{AWORD, C_NONE, C_NONE, C_LEXT, 14, 4, 0, 0, 0},
+	{AWORD, C_NONE, C_NONE, C_ADDR, 14, 4, 0, 0, 0},
+	{AMOVW, C_VCON, C_NONE, C_REG, 12, 4, 0, LFROM, 0},
+	{AMOVD, C_VCON, C_NONE, C_REG, 12, 4, 0, LFROM, 0},
+	{AMOVB, C_REG, C_NONE, C_ADDR, 64, 8, 0, LTO, 0},
+	{AMOVBU, C_REG, C_NONE, C_ADDR, 64, 8, 0, LTO, 0},
+	{AMOVH, C_REG, C_NONE, C_ADDR, 64, 8, 0, LTO, 0},
+	{AMOVW, C_REG, C_NONE, C_ADDR, 64, 8, 0, LTO, 0},
+	{AMOVD, C_REG, C_NONE, C_ADDR, 64, 8, 0, LTO, 0},
+	{AMOVB, C_ADDR, C_NONE, C_REG, 65, 8, 0, LFROM, 0},
+	{AMOVBU, C_ADDR, C_NONE, C_REG, 65, 8, 0, LFROM, 0},
+	{AMOVH, C_ADDR, C_NONE, C_REG, 65, 8, 0, LFROM, 0},
+	{AMOVW, C_ADDR, C_NONE, C_REG, 65, 8, 0, LFROM, 0},
+	{AMOVD, C_ADDR, C_NONE, C_REG, 65, 8, 0, LFROM, 0},
+	{AMUL, C_REG, C_REG, C_REG, 15, 4, 0, 0, 0},
+	{AMUL, C_REG, C_NONE, C_REG, 15, 4, 0, 0, 0},
+	{AMADD, C_REG, C_REG, C_REG, 15, 4, 0, 0, 0},
+	{AREM, C_REG, C_REG, C_REG, 16, 8, 0, 0, 0},
+	{AREM, C_REG, C_NONE, C_REG, 16, 8, 0, 0, 0},
+	{ACSEL, C_COND, C_REG, C_REG, 18, 4, 0, 0, 0}, /* from3 optional */
+	{ACSET, C_COND, C_NONE, C_REG, 18, 4, 0, 0, 0},
+	{ACCMN, C_COND, C_REG, C_VCON, 19, 4, 0, 0, 0}, /* from3 either C_REG or C_VCON */
+
+	/* scaled 12-bit unsigned displacement store */
+	{AMOVB, C_REG, C_NONE, C_UAUTO4K, 20, 4, REGSP, 0, 0},
+	{AMOVB, C_REG, C_NONE, C_UOREG4K, 20, 4, 0, 0, 0},
+	{AMOVBU, C_REG, C_NONE, C_UAUTO4K, 20, 4, REGSP, 0, 0},
+	{AMOVBU, C_REG, C_NONE, C_UOREG4K, 20, 4, 0, 0, 0},
+
+	{AMOVH, C_REG, C_NONE, C_UAUTO8K, 20, 4, REGSP, 0, 0},
+	{AMOVH, C_REG, C_NONE, C_ZOREG, 20, 4, 0, 0, 0},
+	{AMOVH, C_REG, C_NONE, C_UOREG8K, 20, 4, 0, 0, 0},
+
+	{AMOVW, C_REG, C_NONE, C_UAUTO16K, 20, 4, REGSP, 0, 0},
+	{AMOVW, C_REG, C_NONE, C_ZOREG, 20, 4, 0, 0, 0},
+	{AMOVW, C_REG, C_NONE, C_UOREG16K, 20, 4, 0, 0, 0},
+
+	/* unscaled 9-bit signed displacement store */
+	{AMOVB, C_REG, C_NONE, C_NSAUTO, 20, 4, REGSP, 0, 0},
+	{AMOVB, C_REG, C_NONE, C_NSOREG, 20, 4, 0, 0, 0},
+	{AMOVBU, C_REG, C_NONE, C_NSAUTO, 20, 4, REGSP, 0, 0},
+	{AMOVBU, C_REG, C_NONE, C_NSOREG, 20, 4, 0, 0, 0},
+
+	{AMOVH, C_REG, C_NONE, C_NSAUTO, 20, 4, REGSP, 0, 0},
+	{AMOVH, C_REG, C_NONE, C_NSOREG, 20, 4, 0, 0, 0},
+	{AMOVW, C_REG, C_NONE, C_NSAUTO, 20, 4, REGSP, 0, 0},
+	{AMOVW, C_REG, C_NONE, C_NSOREG, 20, 4, 0, 0, 0},
+
+	{AMOVD, C_REG, C_NONE, C_UAUTO32K, 20, 4, REGSP, 0, 0},
+	{AMOVD, C_REG, C_NONE, C_ZOREG, 20, 4, 0, 0, 0},
+	{AMOVD, C_REG, C_NONE, C_UOREG32K, 20, 4, 0, 0, 0},
+	{AMOVD, C_REG, C_NONE, C_NSOREG, 20, 4, 0, 0, 0},
+	{AMOVD, C_REG, C_NONE, C_NSAUTO, 20, 4, REGSP, 0, 0},
+
+	/* short displacement load */
+	{AMOVB, C_UAUTO4K, C_NONE, C_REG, 21, 4, REGSP, 0, 0},
+	{AMOVB, C_NSAUTO, C_NONE, C_REG, 21, 4, REGSP, 0, 0},
+	{AMOVB, C_ZOREG, C_NONE, C_REG, 21, 4, 0, 0, 0},
+	{AMOVB, C_UOREG4K, C_NONE, C_REG, 21, 4, REGSP, 0, 0},
+	{AMOVB, C_NSOREG, C_NONE, C_REG, 21, 4, REGSP, 0, 0},
+
+	{AMOVBU, C_UAUTO4K, C_NONE, C_REG, 21, 4, REGSP, 0, 0},
+	{AMOVBU, C_NSAUTO, C_NONE, C_REG, 21, 4, REGSP, 0, 0},
+	{AMOVBU, C_ZOREG, C_NONE, C_REG, 21, 4, 0, 0, 0},
+	{AMOVBU, C_UOREG4K, C_NONE, C_REG, 21, 4, REGSP, 0, 0},
+	{AMOVBU, C_NSOREG, C_NONE, C_REG, 21, 4, REGSP, 0, 0},
+
+	{AMOVH, C_UAUTO8K, C_NONE, C_REG, 21, 4, REGSP, 0, 0},
+	{AMOVH, C_NSAUTO, C_NONE, C_REG, 21, 4, REGSP, 0, 0},
+	{AMOVH, C_ZOREG, C_NONE, C_REG, 21, 4, 0, 0, 0},
+	{AMOVH, C_UOREG8K, C_NONE, C_REG, 21, 4, REGSP, 0, 0},
+	{AMOVH, C_NSOREG, C_NONE, C_REG, 21, 4, REGSP, 0, 0},
+
+	{AMOVW, C_UAUTO16K, C_NONE, C_REG, 21, 4, REGSP, 0, 0},
+	{AMOVW, C_NSAUTO, C_NONE, C_REG, 21, 4, REGSP, 0, 0},
+	{AMOVW, C_ZOREG, C_NONE, C_REG, 21, 4, 0, 0, 0},
+	{AMOVW, C_UOREG16K, C_NONE, C_REG, 21, 4, REGSP, 0, 0},
+	{AMOVW, C_NSOREG, C_NONE, C_REG, 21, 4, REGSP, 0, 0},
+
+	{AMOVD, C_UAUTO32K, C_NONE, C_REG, 21, 4, REGSP, 0, 0},
+	{AMOVD, C_NSAUTO, C_NONE, C_REG, 21, 4, REGSP, 0, 0},
+	{AMOVD, C_ZOREG, C_NONE, C_REG, 21, 4, 0, 0, 0},
+	{AMOVD, C_UOREG32K, C_NONE, C_REG, 21, 4, REGSP, 0, 0},
+	{AMOVD, C_NSOREG, C_NONE, C_REG, 21, 4, REGSP, 0, 0},
+
+	/* long displacement store */
+	{AMOVB, C_REG, C_NONE, C_LAUTO, 30, 8, REGSP, 0, 0},
+	{AMOVB, C_REG, C_NONE, C_LOREG, 30, 8, 0, 0, 0},
+	{AMOVBU, C_REG, C_NONE, C_LAUTO, 30, 8, REGSP, 0, 0},
+	{AMOVBU, C_REG, C_NONE, C_LOREG, 30, 8, 0, 0, 0},
+	{AMOVH, C_REG, C_NONE, C_LAUTO, 30, 8, REGSP, 0, 0},
+	{AMOVH, C_REG, C_NONE, C_LOREG, 30, 8, 0, 0, 0},
+	{AMOVW, C_REG, C_NONE, C_LAUTO, 30, 8, REGSP, 0, 0},
+	{AMOVW, C_REG, C_NONE, C_LOREG, 30, 8, 0, 0, 0},
+	{AMOVD, C_REG, C_NONE, C_LAUTO, 30, 8, REGSP, 0, 0},
+	{AMOVD, C_REG, C_NONE, C_LOREG, 30, 8, 0, 0, 0},
+
+	/* long displacement load */
+	{AMOVB, C_LAUTO, C_NONE, C_REG, 31, 8, REGSP, 0, 0},
+	{AMOVB, C_LOREG, C_NONE, C_REG, 31, 8, 0, 0, 0},
+	{AMOVB, C_LOREG, C_NONE, C_REG, 31, 8, 0, 0, 0},
+	{AMOVBU, C_LAUTO, C_NONE, C_REG, 31, 8, REGSP, 0, 0},
+	{AMOVBU, C_LOREG, C_NONE, C_REG, 31, 8, 0, 0, 0},
+	{AMOVBU, C_LOREG, C_NONE, C_REG, 31, 8, 0, 0, 0},
+	{AMOVH, C_LAUTO, C_NONE, C_REG, 31, 8, REGSP, 0, 0},
+	{AMOVH, C_LOREG, C_NONE, C_REG, 31, 8, 0, 0, 0},
+	{AMOVH, C_LOREG, C_NONE, C_REG, 31, 8, 0, 0, 0},
+	{AMOVW, C_LAUTO, C_NONE, C_REG, 31, 8, REGSP, 0, 0},
+	{AMOVW, C_LOREG, C_NONE, C_REG, 31, 8, 0, 0, 0},
+	{AMOVW, C_LOREG, C_NONE, C_REG, 31, 8, 0, 0, 0},
+	{AMOVD, C_LAUTO, C_NONE, C_REG, 31, 8, REGSP, 0, 0},
+	{AMOVD, C_LOREG, C_NONE, C_REG, 31, 8, 0, 0, 0},
+	{AMOVD, C_LOREG, C_NONE, C_REG, 31, 8, 0, 0, 0},
+
+	/* load long effective stack address (load int32 offset and add) */
+	{AMOVD, C_LACON, C_NONE, C_REG, 34, 8, REGSP, LFROM, 0},
+
+	/* pre/post-indexed load (unscaled, signed 9-bit offset) */
+	{AMOVD, C_LOREG, C_NONE, C_REG, 22, 4, 0, 0, C_XPOST},
+	{AMOVW, C_LOREG, C_NONE, C_REG, 22, 4, 0, 0, C_XPOST},
+	{AMOVH, C_LOREG, C_NONE, C_REG, 22, 4, 0, 0, C_XPOST},
+	{AMOVB, C_LOREG, C_NONE, C_REG, 22, 4, 0, 0, C_XPOST},
+	{AMOVBU, C_LOREG, C_NONE, C_REG, 22, 4, 0, 0, C_XPOST},
+	{AFMOVS, C_LOREG, C_NONE, C_FREG, 22, 4, 0, 0, C_XPOST},
+	{AFMOVD, C_LOREG, C_NONE, C_FREG, 22, 4, 0, 0, C_XPOST},
+	{AMOVD, C_LOREG, C_NONE, C_REG, 22, 4, 0, 0, C_XPRE},
+	{AMOVW, C_LOREG, C_NONE, C_REG, 22, 4, 0, 0, C_XPRE},
+	{AMOVH, C_LOREG, C_NONE, C_REG, 22, 4, 0, 0, C_XPRE},
+	{AMOVB, C_LOREG, C_NONE, C_REG, 22, 4, 0, 0, C_XPRE},
+	{AMOVBU, C_LOREG, C_NONE, C_REG, 22, 4, 0, 0, C_XPRE},
+	{AFMOVS, C_LOREG, C_NONE, C_FREG, 22, 4, 0, 0, C_XPRE},
+	{AFMOVD, C_LOREG, C_NONE, C_FREG, 22, 4, 0, 0, C_XPRE},
+
+	/* pre/post-indexed store (unscaled, signed 9-bit offset) */
+	{AMOVD, C_REG, C_NONE, C_LOREG, 23, 4, 0, 0, C_XPOST},
+	{AMOVW, C_REG, C_NONE, C_LOREG, 23, 4, 0, 0, C_XPOST},
+	{AMOVH, C_REG, C_NONE, C_LOREG, 23, 4, 0, 0, C_XPOST},
+	{AMOVB, C_REG, C_NONE, C_LOREG, 23, 4, 0, 0, C_XPOST},
+	{AMOVBU, C_REG, C_NONE, C_LOREG, 23, 4, 0, 0, C_XPOST},
+	{AFMOVS, C_FREG, C_NONE, C_LOREG, 23, 4, 0, 0, C_XPOST},
+	{AFMOVD, C_FREG, C_NONE, C_LOREG, 23, 4, 0, 0, C_XPOST},
+	{AMOVD, C_REG, C_NONE, C_LOREG, 23, 4, 0, 0, C_XPRE},
+	{AMOVW, C_REG, C_NONE, C_LOREG, 23, 4, 0, 0, C_XPRE},
+	{AMOVH, C_REG, C_NONE, C_LOREG, 23, 4, 0, 0, C_XPRE},
+	{AMOVB, C_REG, C_NONE, C_LOREG, 23, 4, 0, 0, C_XPRE},
+	{AMOVBU, C_REG, C_NONE, C_LOREG, 23, 4, 0, 0, C_XPRE},
+	{AFMOVS, C_FREG, C_NONE, C_LOREG, 23, 4, 0, 0, C_XPRE},
+	{AFMOVD, C_FREG, C_NONE, C_LOREG, 23, 4, 0, 0, C_XPRE},
+
+	/* pre/post-indexed load/store register pair
+	   (unscaled, signed 10-bit quad-aligned offset) */
+	{ALDP, C_LOREG, C_NONE, C_PAIR, 66, 4, 0, 0, C_XPRE},
+	{ALDP, C_LOREG, C_NONE, C_PAIR, 66, 4, 0, 0, C_XPOST},
+	{ASTP, C_PAIR, C_NONE, C_LOREG, 67, 4, 0, 0, C_XPRE},
+	{ASTP, C_PAIR, C_NONE, C_LOREG, 67, 4, 0, 0, C_XPOST},
+
+	/* special */
+	{AMOVD, C_SPR, C_NONE, C_REG, 35, 4, 0, 0, 0},
+	{AMRS, C_SPR, C_NONE, C_REG, 35, 4, 0, 0, 0},
+	{AMOVD, C_REG, C_NONE, C_SPR, 36, 4, 0, 0, 0},
+	{AMSR, C_REG, C_NONE, C_SPR, 36, 4, 0, 0, 0},
+	{AMOVD, C_VCON, C_NONE, C_SPR, 37, 4, 0, 0, 0},
+	{AMSR, C_VCON, C_NONE, C_SPR, 37, 4, 0, 0, 0},
+	{AERET, C_NONE, C_NONE, C_NONE, 41, 4, 0, 0, 0},
+	{AFMOVS, C_FREG, C_NONE, C_UAUTO16K, 20, 4, REGSP, 0, 0},
+	{AFMOVS, C_FREG, C_NONE, C_NSAUTO, 20, 4, REGSP, 0, 0},
+	{AFMOVS, C_FREG, C_NONE, C_ZOREG, 20, 4, 0, 0, 0},
+	{AFMOVS, C_FREG, C_NONE, C_UOREG16K, 20, 4, 0, 0, 0},
+	{AFMOVS, C_FREG, C_NONE, C_NSOREG, 20, 4, 0, 0, 0},
+	{AFMOVD, C_FREG, C_NONE, C_UAUTO32K, 20, 4, REGSP, 0, 0},
+	{AFMOVD, C_FREG, C_NONE, C_NSAUTO, 20, 4, REGSP, 0, 0},
+	{AFMOVD, C_FREG, C_NONE, C_ZOREG, 20, 4, 0, 0, 0},
+	{AFMOVD, C_FREG, C_NONE, C_UOREG32K, 20, 4, 0, 0, 0},
+	{AFMOVD, C_FREG, C_NONE, C_NSOREG, 20, 4, 0, 0, 0},
+	{AFMOVS, C_UAUTO16K, C_NONE, C_FREG, 21, 4, REGSP, 0, 0},
+	{AFMOVS, C_NSAUTO, C_NONE, C_FREG, 21, 4, REGSP, 0, 0},
+	{AFMOVS, C_ZOREG, C_NONE, C_FREG, 21, 4, 0, 0, 0},
+	{AFMOVS, C_UOREG16K, C_NONE, C_FREG, 21, 4, 0, 0, 0},
+	{AFMOVS, C_NSOREG, C_NONE, C_FREG, 21, 4, 0, 0, 0},
+	{AFMOVD, C_UAUTO32K, C_NONE, C_FREG, 21, 4, REGSP, 0, 0},
+	{AFMOVD, C_NSAUTO, C_NONE, C_FREG, 21, 4, REGSP, 0, 0},
+	{AFMOVD, C_ZOREG, C_NONE, C_FREG, 21, 4, 0, 0, 0},
+	{AFMOVD, C_UOREG32K, C_NONE, C_FREG, 21, 4, 0, 0, 0},
+	{AFMOVD, C_NSOREG, C_NONE, C_FREG, 21, 4, 0, 0, 0},
+	{AFMOVS, C_FREG, C_NONE, C_LAUTO, 30, 8, REGSP, LTO, 0},
+	{AFMOVS, C_FREG, C_NONE, C_LOREG, 30, 8, 0, LTO, 0},
+	{AFMOVD, C_FREG, C_NONE, C_LAUTO, 30, 8, REGSP, LTO, 0},
+	{AFMOVD, C_FREG, C_NONE, C_LOREG, 30, 8, 0, LTO, 0},
+	{AFMOVS, C_LAUTO, C_NONE, C_FREG, 31, 8, REGSP, LFROM, 0},
+	{AFMOVS, C_LOREG, C_NONE, C_FREG, 31, 8, 0, LFROM, 0},
+	{AFMOVD, C_LAUTO, C_NONE, C_FREG, 31, 8, REGSP, LFROM, 0},
+	{AFMOVD, C_LOREG, C_NONE, C_FREG, 31, 8, 0, LFROM, 0},
+	{AFMOVS, C_FREG, C_NONE, C_ADDR, 64, 8, 0, LTO, 0},
+	{AFMOVS, C_ADDR, C_NONE, C_FREG, 65, 8, 0, LFROM, 0},
+	{AFMOVD, C_FREG, C_NONE, C_ADDR, 64, 8, 0, LTO, 0},
+	{AFMOVD, C_ADDR, C_NONE, C_FREG, 65, 8, 0, LFROM, 0},
+	{AFADDS, C_FREG, C_NONE, C_FREG, 54, 4, 0, 0, 0},
+	{AFADDS, C_FREG, C_FREG, C_FREG, 54, 4, 0, 0, 0},
+	{AFADDS, C_FCON, C_NONE, C_FREG, 54, 4, 0, 0, 0},
+	{AFADDS, C_FCON, C_FREG, C_FREG, 54, 4, 0, 0, 0},
+	{AFMOVS, C_FCON, C_NONE, C_FREG, 54, 4, 0, 0, 0},
+	{AFMOVS, C_FREG, C_NONE, C_FREG, 54, 4, 0, 0, 0},
+	{AFMOVD, C_FCON, C_NONE, C_FREG, 54, 4, 0, 0, 0},
+	{AFMOVD, C_FREG, C_NONE, C_FREG, 54, 4, 0, 0, 0},
+	{AFCVTZSD, C_FREG, C_NONE, C_REG, 29, 4, 0, 0, 0},
+	{ASCVTFD, C_REG, C_NONE, C_FREG, 29, 4, 0, 0, 0},
+	{AFCMPS, C_FREG, C_FREG, C_NONE, 56, 4, 0, 0, 0},
+	{AFCMPS, C_FCON, C_FREG, C_NONE, 56, 4, 0, 0, 0},
+	{AFCCMPS, C_COND, C_REG, C_VCON, 57, 4, 0, 0, 0},
+	{AFCSELD, C_COND, C_REG, C_FREG, 18, 4, 0, 0, 0},
+	{AFCVTSD, C_FREG, C_NONE, C_FREG, 29, 4, 0, 0, 0},
+	{ACASE, C_REG, C_NONE, C_REG, 62, 4 * 4, 0, 0, 0},
+	{ABCASE, C_NONE, C_NONE, C_SBRA, 63, 4, 0, 0, 0},
+	{ACLREX, C_NONE, C_NONE, C_VCON, 38, 4, 0, 0, 0},
+	{ACLREX, C_NONE, C_NONE, C_NONE, 38, 4, 0, 0, 0},
+	{ACBZ, C_REG, C_NONE, C_SBRA, 39, 4, 0, 0, 0},
+	{ATBZ, C_VCON, C_REG, C_SBRA, 40, 4, 0, 0, 0},
+	{ASYS, C_VCON, C_NONE, C_NONE, 50, 4, 0, 0, 0},
+	{ASYS, C_VCON, C_REG, C_NONE, 50, 4, 0, 0, 0},
+	{ASYSL, C_VCON, C_NONE, C_REG, 50, 4, 0, 0, 0},
+	{ADMB, C_VCON, C_NONE, C_NONE, 51, 4, 0, 0, 0},
+	{AHINT, C_VCON, C_NONE, C_NONE, 52, 4, 0, 0, 0},
+	{ALDAR, C_ZOREG, C_NONE, C_REG, 58, 4, 0, 0, 0},
+	{ALDXR, C_ZOREG, C_NONE, C_REG, 58, 4, 0, 0, 0},
+	{ALDAXR, C_ZOREG, C_NONE, C_REG, 58, 4, 0, 0, 0},
+	{ALDXP, C_ZOREG, C_REG, C_REG, 58, 4, 0, 0, 0},
+	{ASTLR, C_REG, C_NONE, C_ZOREG, 59, 4, 0, 0, 0},  // to3=C_NONE
+	{ASTXR, C_REG, C_NONE, C_ZOREG, 59, 4, 0, 0, 0},  // to3=C_REG
+	{ASTLXR, C_REG, C_NONE, C_ZOREG, 59, 4, 0, 0, 0}, // to3=C_REG
+
+	//	{ ASTXP,		C_REG, C_NONE,	C_ZOREG,		59, 4, 0 , 0}, // TODO(aram):
+
+	{AAESD, C_VREG, C_NONE, C_VREG, 29, 4, 0, 0, 0},
+	{ASHA1C, C_VREG, C_REG, C_VREG, 1, 4, 0, 0, 0},
+
+	{obj.AUNDEF, C_NONE, C_NONE, C_NONE, 90, 4, 0, 0, 0},
+	{obj.AUSEFIELD, C_ADDR, C_NONE, C_NONE, 0, 0, 0, 0, 0},
+	{obj.APCDATA, C_VCON, C_NONE, C_VCON, 0, 0, 0, 0, 0},
+	{obj.AFUNCDATA, C_VCON, C_NONE, C_ADDR, 0, 0, 0, 0, 0},
+	{obj.ANOP, C_NONE, C_NONE, C_NONE, 0, 0, 0, 0, 0},
+	{obj.ADUFFZERO, C_NONE, C_NONE, C_SBRA, 5, 4, 0, 0, 0}, // same as AB/ABL
+	{obj.ADUFFCOPY, C_NONE, C_NONE, C_SBRA, 5, 4, 0, 0, 0}, // same as AB/ABL
+
+	{obj.AXXX, C_NONE, C_NONE, C_NONE, 0, 4, 0, 0, 0},
+}
+
+/*
+ * valid pstate field values, and value to use in instruction
+ */
+var pstatefield = []struct {
+	a uint32
+	b uint32
+}{
+	{REG_SPSel, 0<<16 | 4<<12 | 5<<5},
+	{REG_DAIFSet, 3<<16 | 4<<12 | 6<<5},
+	{REG_DAIFClr, 3<<16 | 4<<12 | 7<<5},
+}
+
+var pool struct {
+	start uint32
+	size  uint32
+}
+
+func prasm(p *obj.Prog) {
+	fmt.Printf("%v\n", p)
+}
+
+func span7(ctxt *obj.Link, cursym *obj.LSym) {
+	p := cursym.Text
+	if p == nil || p.Link == nil { // handle external functions and ELF section symbols
+		return
+	}
+	ctxt.Cursym = cursym
+	ctxt.Autosize = int32(p.To.Offset&0xffffffff) + 8
+
+	if oprange[AAND].start == nil {
+		buildop(ctxt)
+	}
+
+	bflag := 0
+	c := int32(0)
+	p.Pc = int64(c)
+	var m int
+	var o *Optab
+	for p = p.Link; p != nil; p = p.Link {
+		ctxt.Curp = p
+		if p.As == ADWORD && (c&7) != 0 {
+			c += 4
+		}
+		p.Pc = int64(c)
+		o = oplook(ctxt, p)
+		m = int(o.size)
+		if m == 0 {
+			if p.As != obj.ANOP && p.As != obj.AFUNCDATA && p.As != obj.APCDATA {
+				ctxt.Diag("zero-width instruction\n%v", p)
+			}
+			continue
+		}
+
+		switch o.flag & (LFROM | LTO) {
+		case LFROM:
+			addpool(ctxt, p, &p.From)
+
+		case LTO:
+			addpool(ctxt, p, &p.To)
+			break
+		}
+
+		if p.As == AB || p.As == obj.ARET || p.As == AERET { /* TODO: other unconditional operations */
+			checkpool(ctxt, p, 0)
+		}
+		c += int32(m)
+		if ctxt.Blitrl != nil {
+			checkpool(ctxt, p, 1)
+		}
+	}
+
+	cursym.Size = int64(c)
+
+	/*
+	 * if any procedure is large enough to
+	 * generate a large SBRA branch, then
+	 * generate extra passes putting branches
+	 * around jmps to fix. this is rare.
+	 */
+	for bflag != 0 {
+		bflag = 0
+		c = 0
+		for p = cursym.Text; p != nil; p = p.Link {
+			if p.As == ADWORD && (c&7) != 0 {
+				c += 4
+			}
+			p.Pc = int64(c)
+			o = oplook(ctxt, p)
+
+			/* very large branches
+			if(o->type == 6 && p->cond) {
+				otxt = p->cond->pc - c;
+				if(otxt < 0)
+					otxt = -otxt;
+				if(otxt >= (1L<<17) - 10) {
+					q = ctxt->arch->prg();
+					q->link = p->link;
+					p->link = q;
+					q->as = AB;
+					q->to.type = obj.TYPE_BRANCH;
+					q->cond = p->cond;
+					p->cond = q;
+					q = ctxt->arch->prg();
+					q->link = p->link;
+					p->link = q;
+					q->as = AB;
+					q->to.type = obj.TYPE_BRANCH;
+					q->cond = q->link->link;
+					bflag = 1;
+				}
+			}
+			*/
+			m = int(o.size)
+
+			if m == 0 {
+				if p.As != obj.ANOP && p.As != obj.AFUNCDATA && p.As != obj.APCDATA {
+					ctxt.Diag("zero-width instruction\n%v", p)
+				}
+				continue
+			}
+
+			c += int32(m)
+		}
+	}
+
+	c += -c & (FuncAlign - 1)
+	cursym.Size = int64(c)
+
+	/*
+	 * lay out the code, emitting code and data relocations.
+	 */
+	if ctxt.Tlsg == nil {
+		ctxt.Tlsg = obj.Linklookup(ctxt, "runtime.tlsg", 0)
+	}
+	obj.Symgrow(ctxt, cursym, cursym.Size)
+	bp := cursym.P
+	psz := int32(0)
+	var i int
+	var out [6]uint32
+	for p := cursym.Text.Link; p != nil; p = p.Link {
+		ctxt.Pc = p.Pc
+		ctxt.Curp = p
+		o = oplook(ctxt, p)
+
+		// need to align DWORDs on 8-byte boundary. The ISA doesn't
+		// require it, but the various 64-bit loads we generate assume it.
+		if o.as == ADWORD && psz%8 != 0 {
+			bp[3] = 0
+			bp[2] = bp[3]
+			bp[1] = bp[2]
+			bp[0] = bp[1]
+			bp = bp[4:]
+			psz += 4
+		}
+
+		if int(o.size) > 4*len(out) {
+			log.Fatalf("out array in span7 is too small, need at least %d for %v", o.size/4, p)
+		}
+		asmout(ctxt, p, o, out[:])
+		for i = 0; i < int(o.size/4); i++ {
+			ctxt.Arch.ByteOrder.PutUint32(bp, out[i])
+			bp = bp[4:]
+			psz += 4
+		}
+	}
+}
+
+/*
+ * when the first reference to the literal pool threatens
+ * to go out of range of a 1Mb PC-relative offset
+ * drop the pool now, and branch round it.
+ */
+func checkpool(ctxt *obj.Link, p *obj.Prog, skip int) {
+	if pool.size >= 0xffff0 || !(ispcdisp(int32(p.Pc+4+int64(pool.size)-int64(pool.start)+8)) != 0) {
+		flushpool(ctxt, p, skip)
+	} else if p.Link == nil {
+		flushpool(ctxt, p, 2)
+	}
+}
+
+func flushpool(ctxt *obj.Link, p *obj.Prog, skip int) {
+	if ctxt.Blitrl != nil {
+		if skip != 0 {
+			if ctxt.Debugvlog != 0 && skip == 1 {
+				fmt.Printf("note: flush literal pool at %#x: len=%d ref=%x\n", uint64(p.Pc+4), pool.size, pool.start)
+			}
+			q := ctxt.NewProg()
+			q.As = AB
+			q.To.Type = obj.TYPE_BRANCH
+			q.Pcond = p.Link
+			q.Link = ctxt.Blitrl
+			q.Lineno = p.Lineno
+			ctxt.Blitrl = q
+		} else if p.Pc+int64(pool.size)-int64(pool.start) < 1024*1024 {
+			return
+		}
+		ctxt.Elitrl.Link = p.Link
+		p.Link = ctxt.Blitrl
+
+		// BUG(minux): how to correctly handle line number for constant pool entries?
+		// for now, we set line number to the last instruction preceding them at least
+		// this won't bloat the .debug_line tables
+		for ctxt.Blitrl != nil {
+			ctxt.Blitrl.Lineno = p.Lineno
+			ctxt.Blitrl = ctxt.Blitrl.Link
+		}
+
+		ctxt.Blitrl = nil /* BUG: should refer back to values until out-of-range */
+		ctxt.Elitrl = nil
+		pool.size = 0
+		pool.start = 0
+	}
+}
+
+/*
+ * TODO: hash
+ */
+func addpool(ctxt *obj.Link, p *obj.Prog, a *obj.Addr) {
+	c := aclass(ctxt, a)
+	t := *ctxt.NewProg()
+	t.As = AWORD
+	sz := 4
+
+	// MOVW foo(SB), R is actually
+	//	MOV addr, REGTEMP
+	//	MOVW REGTEMP, R
+	// where addr is the address of the DWORD containing the address of foo.
+	if p.As == AMOVD || c == C_ADDR || c == C_VCON {
+		t.As = ADWORD
+		sz = 8
+	}
+
+	switch c {
+	// TODO(aram): remove.
+	default:
+		if a.Name != obj.NAME_EXTERN {
+			fmt.Printf("addpool: %v in %v shouldn't go to default case\n", DRconv(c), p)
+		}
+
+		t.To.Offset = a.Offset
+		t.To.Sym = a.Sym
+		t.To.Type = a.Type
+		t.To.Name = a.Name
+
+		/* This is here to work around a bug where we generate negative
+		operands that match C_MOVCON, but we use them with
+		instructions that only accept unsigned immediates. This
+		will cause oplook to return a variant of the instruction
+		that loads the negative constant from memory, rather than
+		using the immediate form. Because of that load, we get here,
+		so we need to know what to do with C_MOVCON.
+
+		The correct fix is to use the "negation" instruction variant,
+		e.g. CMN $1, R instead of CMP $-1, R, or SUB $1, R instead
+		of ADD $-1, R. */
+	case C_MOVCON,
+
+		/* This is here because MOV uint12<<12, R is disabled in optab.
+		Because of this, we need to load the constant from memory. */
+		C_ADDCON,
+
+		/* These are here because they are disabled in optab.
+		Because of this, we need to load the constant from memory. */
+		C_BITCON,
+		C_ABCON,
+		C_MBCON,
+		C_PSAUTO,
+		C_PPAUTO,
+		C_UAUTO4K,
+		C_UAUTO8K,
+		C_UAUTO16K,
+		C_UAUTO32K,
+		C_UAUTO64K,
+		C_NSAUTO,
+		C_NPAUTO,
+		C_LAUTO,
+		C_PPOREG,
+		C_PSOREG,
+		C_UOREG4K,
+		C_UOREG8K,
+		C_UOREG16K,
+		C_UOREG32K,
+		C_UOREG64K,
+		C_NSOREG,
+		C_NPOREG,
+		C_LOREG,
+		C_LACON,
+		C_LCON,
+		C_VCON:
+		if a.Name == obj.NAME_EXTERN {
+			fmt.Printf("addpool: %v in %v needs reloc\n", DRconv(c), p)
+		}
+
+		t.To.Type = obj.TYPE_CONST
+		t.To.Offset = ctxt.Instoffset
+		break
+	}
+
+	for q := ctxt.Blitrl; q != nil; q = q.Link { /* could hash on t.t0.offset */
+		if q.To == t.To {
+			p.Pcond = q
+			return
+		}
+	}
+
+	q := ctxt.NewProg()
+	*q = t
+	q.Pc = int64(pool.size)
+	if ctxt.Blitrl == nil {
+		ctxt.Blitrl = q
+		pool.start = uint32(p.Pc)
+	} else {
+		ctxt.Elitrl.Link = q
+	}
+	ctxt.Elitrl = q
+	pool.size = -pool.size & (FuncAlign - 1)
+	pool.size += uint32(sz)
+	p.Pcond = q
+}
+
+func regoff(ctxt *obj.Link, a *obj.Addr) uint32 {
+	ctxt.Instoffset = 0
+	aclass(ctxt, a)
+	return uint32(ctxt.Instoffset)
+}
+
+func ispcdisp(v int32) int {
+	/* pc-relative addressing will reach? */
+	return bool2int(v >= -0xfffff && v <= 0xfffff && (v&3) == 0)
+}
+
+func isaddcon(v int64) int {
+	/* uimm12 or uimm24? */
+	if v < 0 {
+		return 0
+	}
+	if (v & 0xFFF) == 0 {
+		v >>= 12
+	}
+	return bool2int(v <= 0xFFF)
+}
+
+func isbitcon(v uint64) int {
+	/*  fancy bimm32 or bimm64? */
+	// TODO(aram):
+	return 0
+	// return bool2int(findmask(v) != nil || (v>>32) == 0 && findmask(v|(v<<32)) != nil)
+}
+
+func autoclass(l int64) int {
+	if l < 0 {
+		if l >= -256 {
+			return C_NSAUTO
+		}
+		if l >= -512 && (l&7) == 0 {
+			return C_NPAUTO
+		}
+		return C_LAUTO
+	}
+
+	if l <= 255 {
+		return C_PSAUTO
+	}
+	if l <= 504 && (l&7) == 0 {
+		return C_PPAUTO
+	}
+	if l <= 4095 {
+		return C_UAUTO4K
+	}
+	if l <= 8190 && (l&1) == 0 {
+		return C_UAUTO8K
+	}
+	if l <= 16380 && (l&3) == 0 {
+		return C_UAUTO16K
+	}
+	if l <= 32760 && (l&7) == 0 {
+		return C_UAUTO32K
+	}
+	if l <= 65520 && (l&0xF) == 0 {
+		return C_UAUTO64K
+	}
+	return C_LAUTO
+}
+
+func oregclass(l int64) int {
+	if l == 0 {
+		return C_ZOREG
+	}
+	return autoclass(l) - C_NPAUTO + C_NPOREG
+}
+
+/*
+ * given an offset v and a class c (see above)
+ * return the offset value to use in the instruction,
+ * scaled if necessary
+ */
+func offsetshift(ctxt *obj.Link, v int64, c int) int64 {
+	s := 0
+	if c >= C_SEXT1 && c <= C_SEXT16 {
+		s = c - C_SEXT1
+	} else if c >= C_UAUTO4K && c <= C_UAUTO64K {
+		s = c - C_UAUTO4K
+	} else if c >= C_UOREG4K && c <= C_UOREG64K {
+		s = c - C_UOREG4K
+	}
+	vs := v >> uint(s)
+	if vs<<uint(s) != v {
+		ctxt.Diag("odd offset: %d\n%v", v, ctxt.Curp)
+	}
+	return vs
+}
+
+/*
+ * if v contains a single 16-bit value aligned
+ * on a 16-bit field, and thus suitable for movk/movn,
+ * return the field index 0 to 3; otherwise return -1
+ */
+func movcon(v int64) int {
+	for s := 0; s < 64; s += 16 {
+		if (uint64(v) &^ (uint64(0xFFFF) << uint(s))) == 0 {
+			return s / 16
+		}
+	}
+	return -1
+}
+
+func rclass(r int16) int {
+	switch {
+	case REG_R0 <= r && r <= REG_R30: // not 31
+		return C_REG
+	case r == REGZERO:
+		return C_ZCON
+	case REG_F0 <= r && r <= REG_F31:
+		return C_FREG
+	case REG_V0 <= r && r <= REG_V31:
+		return C_VREG
+	case COND_EQ <= r && r <= COND_NV:
+		return C_COND
+	case r == REGSP:
+		return C_RSP
+	case r&REG_EXT != 0:
+		return C_EXTREG
+	case r >= REG_SPECIAL:
+		return C_SPR
+	}
+	return C_GOK
+}
+
+func aclass(ctxt *obj.Link, a *obj.Addr) int {
+	switch a.Type {
+	case obj.TYPE_NONE:
+		return C_NONE
+
+	case obj.TYPE_REG:
+		return rclass(a.Reg)
+
+	case obj.TYPE_REGREG:
+		return C_PAIR
+
+	case obj.TYPE_SHIFT:
+		return C_SHIFT
+
+	case obj.TYPE_MEM:
+		switch a.Name {
+		case obj.NAME_EXTERN,
+			obj.NAME_STATIC:
+			if a.Sym == nil {
+				break
+			}
+			ctxt.Instoffset = a.Offset
+			if a.Sym != nil { // use relocation
+				return C_ADDR
+			}
+			return C_LEXT
+
+		case obj.NAME_AUTO:
+			ctxt.Instoffset = int64(ctxt.Autosize) + a.Offset
+			return autoclass(ctxt.Instoffset)
+
+		case obj.NAME_PARAM:
+			ctxt.Instoffset = int64(ctxt.Autosize) + a.Offset + 8
+			return autoclass(ctxt.Instoffset)
+
+		case obj.TYPE_NONE:
+			ctxt.Instoffset = a.Offset
+			return oregclass(ctxt.Instoffset)
+		}
+		return C_GOK
+
+	case obj.TYPE_FCONST:
+		return C_FCON
+
+	case obj.TYPE_TEXTSIZE:
+		return C_TEXTSIZE
+
+	case obj.TYPE_CONST,
+		obj.TYPE_ADDR:
+		switch a.Name {
+		case obj.TYPE_NONE:
+			ctxt.Instoffset = a.Offset
+			if a.Reg != 0 && a.Reg != REGZERO {
+				goto aconsize
+			}
+			v := ctxt.Instoffset
+			if v == 0 {
+				return C_ZCON
+			}
+			if isaddcon(v) != 0 {
+				if v <= 0xFFF {
+					return C_ADDCON0
+				}
+				if isbitcon(uint64(v)) != 0 {
+					return C_ABCON
+				}
+				return C_ADDCON
+			}
+
+			t := movcon(v)
+			if t >= 0 {
+				if isbitcon(uint64(v)) != 0 {
+					return C_MBCON
+				}
+				return C_MOVCON
+			}
+
+			t = movcon(^v)
+			if t >= 0 {
+				if isbitcon(uint64(v)) != 0 {
+					return C_MBCON
+				}
+				return C_MOVCON
+			}
+
+			if isbitcon(uint64(v)) != 0 {
+				return C_BITCON
+			}
+
+			if uint64(v) == uint64(uint32(v)) || v == int64(int32(v)) {
+				return C_LCON
+			}
+			return C_VCON
+
+		case obj.NAME_EXTERN,
+			obj.NAME_STATIC:
+			s := a.Sym
+			if s == nil {
+				break
+			}
+			ctxt.Instoffset = a.Offset
+			return C_VCONADDR
+
+		case obj.NAME_AUTO:
+			ctxt.Instoffset = int64(ctxt.Autosize) + a.Offset
+			goto aconsize
+
+		case obj.NAME_PARAM:
+			ctxt.Instoffset = int64(ctxt.Autosize) + a.Offset + 8
+			goto aconsize
+		}
+		return C_GOK
+
+	aconsize:
+		if isaddcon(ctxt.Instoffset) != 0 {
+			return C_AACON
+		}
+		return C_LACON
+
+	case obj.TYPE_BRANCH:
+		return C_SBRA
+	}
+
+	return C_GOK
+}
+
+func oplook(ctxt *obj.Link, p *obj.Prog) *Optab {
+	a1 := int(p.Optab)
+	if a1 != 0 {
+		return &optab[a1-1:][0]
+	}
+	a1 = int(p.From.Class)
+	if a1 == 0 {
+		a1 = aclass(ctxt, &p.From) + 1
+		p.From.Class = int8(a1)
+	}
+
+	a1--
+	a3 := int(p.To.Class)
+	if a3 == 0 {
+		a3 = aclass(ctxt, &p.To) + 1
+		p.To.Class = int8(a3)
+	}
+
+	a3--
+	a2 := C_NONE
+	if p.Reg != 0 {
+		a2 = rclass(p.Reg)
+	}
+	r := int(p.As)
+	o := oprange[r].start
+	if o == nil {
+		o = oprange[r].stop /* just generate an error */
+	}
+
+	if false {
+		fmt.Printf("oplook %v %d %d %d\n", obj.Aconv(int(p.As)), a1, a2, a3)
+		fmt.Printf("\t\t%d %d\n", p.From.Type, p.To.Type)
+	}
+
+	e := oprange[r].stop
+	c1 := xcmp[a1][:]
+	c2 := xcmp[a2][:]
+	c3 := xcmp[a3][:]
+	c4 := xcmp[p.Scond>>5][:]
+	for ; -cap(o) < -cap(e); o = o[1:] {
+		if int(o[0].a2) == a2 || c2[o[0].a2] != 0 {
+			if c4[o[0].scond>>5] != 0 {
+				if c1[o[0].a1] != 0 {
+					if c3[o[0].a3] != 0 {
+						p.Optab = uint16((-cap(o) + cap(optab)) + 1)
+						return &o[0]
+					}
+				}
+			}
+		}
+	}
+
+	ctxt.Diag("illegal combination %v %v %v %v, %d %d", p, DRconv(a1), DRconv(a2), DRconv(a3), p.From.Type, p.To.Type)
+	prasm(p)
+	if o == nil {
+		o = optab
+	}
+	return &o[0]
+}
+
+func cmp(a int, b int) bool {
+	if a == b {
+		return true
+	}
+	switch a {
+	case C_RSP:
+		if b == C_REG {
+			return true
+		}
+
+	case C_REG:
+		if b == C_ZCON {
+			return true
+		}
+
+	case C_ADDCON0:
+		if b == C_ZCON {
+			return true
+		}
+
+	case C_ADDCON:
+		if b == C_ZCON || b == C_ADDCON0 || b == C_ABCON {
+			return true
+		}
+
+	case C_BITCON:
+		if b == C_ABCON || b == C_MBCON {
+			return true
+		}
+
+	case C_MOVCON:
+		if b == C_MBCON || b == C_ZCON || b == C_ADDCON0 {
+			return true
+		}
+
+	case C_LCON:
+		if b == C_ZCON || b == C_BITCON || b == C_ADDCON || b == C_ADDCON0 || b == C_ABCON || b == C_MBCON || b == C_MOVCON {
+			return true
+		}
+
+	case C_VCON:
+		if b == C_VCONADDR {
+			return true
+		} else {
+			return cmp(C_LCON, b)
+		}
+		fallthrough
+
+	case C_LACON:
+		if b == C_AACON {
+			return true
+		}
+
+	case C_SEXT2:
+		if b == C_SEXT1 {
+			return true
+		}
+
+	case C_SEXT4:
+		if b == C_SEXT1 || b == C_SEXT2 {
+			return true
+		}
+
+	case C_SEXT8:
+		if b >= C_SEXT1 && b <= C_SEXT4 {
+			return true
+		}
+
+	case C_SEXT16:
+		if b >= C_SEXT1 && b <= C_SEXT8 {
+			return true
+		}
+
+	case C_LEXT:
+		if b >= C_SEXT1 && b <= C_SEXT16 {
+			return true
+		}
+
+	case C_PPAUTO:
+		if b == C_PSAUTO {
+			return true
+		}
+
+	case C_UAUTO4K:
+		if b == C_PSAUTO || b == C_PPAUTO {
+			return true
+		}
+
+	case C_UAUTO8K:
+		return cmp(C_UAUTO4K, b)
+
+	case C_UAUTO16K:
+		return cmp(C_UAUTO8K, b)
+
+	case C_UAUTO32K:
+		return cmp(C_UAUTO16K, b)
+
+	case C_UAUTO64K:
+		return cmp(C_UAUTO32K, b)
+
+	case C_NPAUTO:
+		return cmp(C_NSAUTO, b)
+
+	case C_LAUTO:
+		return cmp(C_NPAUTO, b) || cmp(C_UAUTO64K, b)
+
+	case C_PSOREG:
+		if b == C_ZOREG {
+			return true
+		}
+
+	case C_PPOREG:
+		if b == C_ZOREG || b == C_PSOREG {
+			return true
+		}
+
+	case C_UOREG4K:
+		if b == C_ZOREG || b == C_PSAUTO || b == C_PSOREG || b == C_PPAUTO || b == C_PPOREG {
+			return true
+		}
+
+	case C_UOREG8K:
+		return cmp(C_UOREG4K, b)
+
+	case C_UOREG16K:
+		return cmp(C_UOREG8K, b)
+
+	case C_UOREG32K:
+		return cmp(C_UOREG16K, b)
+
+	case C_UOREG64K:
+		return cmp(C_UOREG32K, b)
+
+	case C_NPOREG:
+		return cmp(C_NSOREG, b)
+
+	case C_LOREG:
+		return cmp(C_NPOREG, b) || cmp(C_UOREG64K, b)
+
+	case C_LBRA:
+		if b == C_SBRA {
+			return true
+		}
+	}
+
+	return false
+}
+
+type ocmp []Optab
+
+func (x ocmp) Len() int {
+	return len(x)
+}
+
+func (x ocmp) Swap(i, j int) {
+	x[i], x[j] = x[j], x[i]
+}
+
+func (x ocmp) Less(i, j int) bool {
+	p1 := &x[i]
+	p2 := &x[j]
+	n := int(p1.as) - int(p2.as)
+	if n != 0 {
+		return n < 0
+	}
+	n = int(p1.a1) - int(p2.a1)
+	if n != 0 {
+		return n < 0
+	}
+	n = int(p1.a2) - int(p2.a2)
+	if n != 0 {
+		return n < 0
+	}
+	n = int(p1.a3) - int(p2.a3)
+	if n != 0 {
+		return n < 0
+	}
+	n = int(p1.scond) - int(p2.scond)
+	if n != 0 {
+		return n < 0
+	}
+	return false
+}
+
+func buildop(ctxt *obj.Link) {
+	var n int
+	for i := 0; i < C_GOK; i++ {
+		for n = 0; n < C_GOK; n++ {
+			if cmp(n, i) {
+				xcmp[i][n] = 1
+			}
+		}
+	}
+	for n = 0; optab[n].as != obj.AXXX; n++ {
+	}
+	sort.Sort(ocmp(optab[:n]))
+	var r int
+	var t Oprange
+	for i := 0; i < n; i++ {
+		r = int(optab[i].as)
+		oprange[r].start = optab[i:]
+		for int(optab[i].as) == r {
+			i++
+		}
+		oprange[r].stop = optab[i:]
+		i--
+		t = oprange[r]
+		switch r {
+		default:
+			ctxt.Diag("unknown op in build: %v", obj.Aconv(r))
+			log.Fatalf("bad code")
+
+		case AADD:
+			oprange[AADDS] = t
+			oprange[ASUB] = t
+			oprange[ASUBS] = t
+			oprange[AADDW] = t
+			oprange[AADDSW] = t
+			oprange[ASUBW] = t
+			oprange[ASUBSW] = t
+
+		case AAND: /* logical immediate, logical shifted register */
+			oprange[AANDS] = t
+
+			oprange[AANDSW] = t
+			oprange[AANDW] = t
+			oprange[AEOR] = t
+			oprange[AEORW] = t
+			oprange[AORR] = t
+			oprange[AORRW] = t
+
+		case ABIC: /* only logical shifted register */
+			oprange[ABICS] = t
+
+			oprange[ABICSW] = t
+			oprange[ABICW] = t
+			oprange[AEON] = t
+			oprange[AEONW] = t
+			oprange[AORN] = t
+			oprange[AORNW] = t
+
+		case ANEG:
+			oprange[ANEGS] = t
+			oprange[ANEGSW] = t
+			oprange[ANEGW] = t
+
+		case AADC: /* rn=Rd */
+			oprange[AADCW] = t
+
+			oprange[AADCS] = t
+			oprange[AADCSW] = t
+			oprange[ASBC] = t
+			oprange[ASBCW] = t
+			oprange[ASBCS] = t
+			oprange[ASBCSW] = t
+
+		case ANGC: /* rn=REGZERO */
+			oprange[ANGCW] = t
+
+			oprange[ANGCS] = t
+			oprange[ANGCSW] = t
+
+		case ACMP:
+			oprange[ACMPW] = t
+			oprange[ACMN] = t
+			oprange[ACMNW] = t
+
+		case ATST:
+			oprange[ATSTW] = t
+
+			/* register/register, and shifted */
+		case AMVN:
+			oprange[AMVNW] = t
+
+		case AMOVK:
+			oprange[AMOVKW] = t
+			oprange[AMOVN] = t
+			oprange[AMOVNW] = t
+			oprange[AMOVZ] = t
+			oprange[AMOVZW] = t
+
+		case ABEQ:
+			oprange[ABNE] = t
+			oprange[ABCS] = t
+			oprange[ABHS] = t
+			oprange[ABCC] = t
+			oprange[ABLO] = t
+			oprange[ABMI] = t
+			oprange[ABPL] = t
+			oprange[ABVS] = t
+			oprange[ABVC] = t
+			oprange[ABHI] = t
+			oprange[ABLS] = t
+			oprange[ABGE] = t
+			oprange[ABLT] = t
+			oprange[ABGT] = t
+			oprange[ABLE] = t
+
+		case ALSL:
+			oprange[ALSLW] = t
+			oprange[ALSR] = t
+			oprange[ALSRW] = t
+			oprange[AASR] = t
+			oprange[AASRW] = t
+			oprange[AROR] = t
+			oprange[ARORW] = t
+
+		case ACLS:
+			oprange[ACLSW] = t
+			oprange[ACLZ] = t
+			oprange[ACLZW] = t
+			oprange[ARBIT] = t
+			oprange[ARBITW] = t
+			oprange[AREV] = t
+			oprange[AREVW] = t
+			oprange[AREV16] = t
+			oprange[AREV16W] = t
+			oprange[AREV32] = t
+
+		case ASDIV:
+			oprange[ASDIVW] = t
+			oprange[AUDIV] = t
+			oprange[AUDIVW] = t
+			oprange[ACRC32B] = t
+			oprange[ACRC32CB] = t
+			oprange[ACRC32CH] = t
+			oprange[ACRC32CW] = t
+			oprange[ACRC32CX] = t
+			oprange[ACRC32H] = t
+			oprange[ACRC32W] = t
+			oprange[ACRC32X] = t
+
+		case AMADD:
+			oprange[AMADDW] = t
+			oprange[AMSUB] = t
+			oprange[AMSUBW] = t
+			oprange[ASMADDL] = t
+			oprange[ASMSUBL] = t
+			oprange[AUMADDL] = t
+			oprange[AUMSUBL] = t
+
+		case AREM:
+			oprange[AREMW] = t
+			oprange[AUREM] = t
+			oprange[AUREMW] = t
+
+		case AMUL:
+			oprange[AMULW] = t
+			oprange[AMNEG] = t
+			oprange[AMNEGW] = t
+			oprange[ASMNEGL] = t
+			oprange[ASMULL] = t
+			oprange[ASMULH] = t
+			oprange[AUMNEGL] = t
+			oprange[AUMULH] = t
+			oprange[AUMULL] = t
+
+		case AMOVB:
+			oprange[AMOVBU] = t
+
+		case AMOVH:
+			oprange[AMOVHU] = t
+
+		case AMOVW:
+			oprange[AMOVWU] = t
+
+		case ABFM:
+			oprange[ABFMW] = t
+			oprange[ASBFM] = t
+			oprange[ASBFMW] = t
+			oprange[AUBFM] = t
+			oprange[AUBFMW] = t
+
+		case ABFI:
+			oprange[ABFIW] = t
+			oprange[ABFXIL] = t
+			oprange[ABFXILW] = t
+			oprange[ASBFIZ] = t
+			oprange[ASBFIZW] = t
+			oprange[ASBFX] = t
+			oprange[ASBFXW] = t
+			oprange[AUBFIZ] = t
+			oprange[AUBFIZW] = t
+			oprange[AUBFX] = t
+			oprange[AUBFXW] = t
+
+		case AEXTR:
+			oprange[AEXTRW] = t
+
+		case ASXTB:
+			oprange[ASXTBW] = t
+			oprange[ASXTH] = t
+			oprange[ASXTHW] = t
+			oprange[ASXTW] = t
+			oprange[AUXTB] = t
+			oprange[AUXTH] = t
+			oprange[AUXTW] = t
+			oprange[AUXTBW] = t
+			oprange[AUXTHW] = t
+
+		case ACCMN:
+			oprange[ACCMNW] = t
+			oprange[ACCMP] = t
+			oprange[ACCMPW] = t
+
+		case ACSEL:
+			oprange[ACSELW] = t
+			oprange[ACSINC] = t
+			oprange[ACSINCW] = t
+			oprange[ACSINV] = t
+			oprange[ACSINVW] = t
+			oprange[ACSNEG] = t
+			oprange[ACSNEGW] = t
+
+			// aliases Rm=Rn, !cond
+			oprange[ACINC] = t
+
+			oprange[ACINCW] = t
+			oprange[ACINV] = t
+			oprange[ACINVW] = t
+			oprange[ACNEG] = t
+			oprange[ACNEGW] = t
+
+			// aliases, Rm=Rn=REGZERO, !cond
+		case ACSET:
+			oprange[ACSETW] = t
+
+			oprange[ACSETM] = t
+			oprange[ACSETMW] = t
+
+		case AMOVD,
+			AMOVBU,
+			AB,
+			ABL,
+			AWORD,
+			ADWORD,
+			obj.ARET,
+			obj.ATEXT,
+			ACASE,
+			ABCASE,
+			ASTP,
+			ALDP:
+			break
+
+		case AERET:
+			oprange[AWFE] = t
+			oprange[AWFI] = t
+			oprange[AYIELD] = t
+			oprange[ASEV] = t
+			oprange[ASEVL] = t
+			oprange[ADRPS] = t
+
+		case ACBZ:
+			oprange[ACBZW] = t
+			oprange[ACBNZ] = t
+			oprange[ACBNZW] = t
+
+		case ATBZ:
+			oprange[ATBNZ] = t
+
+		case AADR, AADRP:
+			break
+
+		case ACLREX:
+			break
+
+		case ASVC:
+			oprange[AHLT] = t
+			oprange[AHVC] = t
+			oprange[ASMC] = t
+			oprange[ABRK] = t
+			oprange[ADCPS1] = t
+			oprange[ADCPS2] = t
+			oprange[ADCPS3] = t
+
+		case AFADDS:
+			oprange[AFADDD] = t
+			oprange[AFSUBS] = t
+			oprange[AFSUBD] = t
+			oprange[AFMULS] = t
+			oprange[AFMULD] = t
+			oprange[AFNMULS] = t
+			oprange[AFNMULD] = t
+			oprange[AFDIVS] = t
+			oprange[AFMAXD] = t
+			oprange[AFMAXS] = t
+			oprange[AFMIND] = t
+			oprange[AFMINS] = t
+			oprange[AFMAXNMD] = t
+			oprange[AFMAXNMS] = t
+			oprange[AFMINNMD] = t
+			oprange[AFMINNMS] = t
+			oprange[AFDIVD] = t
+
+		case AFCVTSD:
+			oprange[AFCVTDS] = t
+			oprange[AFABSD] = t
+			oprange[AFABSS] = t
+			oprange[AFNEGD] = t
+			oprange[AFNEGS] = t
+			oprange[AFSQRTD] = t
+			oprange[AFSQRTS] = t
+			oprange[AFRINTNS] = t
+			oprange[AFRINTND] = t
+			oprange[AFRINTPS] = t
+			oprange[AFRINTPD] = t
+			oprange[AFRINTMS] = t
+			oprange[AFRINTMD] = t
+			oprange[AFRINTZS] = t
+			oprange[AFRINTZD] = t
+			oprange[AFRINTAS] = t
+			oprange[AFRINTAD] = t
+			oprange[AFRINTXS] = t
+			oprange[AFRINTXD] = t
+			oprange[AFRINTIS] = t
+			oprange[AFRINTID] = t
+			oprange[AFCVTDH] = t
+			oprange[AFCVTHS] = t
+			oprange[AFCVTHD] = t
+			oprange[AFCVTSH] = t
+
+		case AFCMPS:
+			oprange[AFCMPD] = t
+			oprange[AFCMPES] = t
+			oprange[AFCMPED] = t
+
+		case AFCCMPS:
+			oprange[AFCCMPD] = t
+			oprange[AFCCMPES] = t
+			oprange[AFCCMPED] = t
+
+		case AFCSELD:
+			oprange[AFCSELS] = t
+
+		case AFMOVS, AFMOVD:
+			break
+
+		case AFCVTZSD:
+			oprange[AFCVTZSDW] = t
+			oprange[AFCVTZSS] = t
+			oprange[AFCVTZSSW] = t
+			oprange[AFCVTZUD] = t
+			oprange[AFCVTZUDW] = t
+			oprange[AFCVTZUS] = t
+			oprange[AFCVTZUSW] = t
+
+		case ASCVTFD:
+			oprange[ASCVTFS] = t
+			oprange[ASCVTFWD] = t
+			oprange[ASCVTFWS] = t
+			oprange[AUCVTFD] = t
+			oprange[AUCVTFS] = t
+			oprange[AUCVTFWD] = t
+			oprange[AUCVTFWS] = t
+
+		case ASYS:
+			oprange[AAT] = t
+			oprange[ADC] = t
+			oprange[AIC] = t
+			oprange[ATLBI] = t
+
+		case ASYSL, AHINT:
+			break
+
+		case ADMB:
+			oprange[ADSB] = t
+			oprange[AISB] = t
+
+		case AMRS, AMSR:
+			break
+
+		case ALDAR:
+			oprange[ALDARW] = t
+			fallthrough
+
+		case ALDXR:
+			oprange[ALDXRB] = t
+			oprange[ALDXRH] = t
+			oprange[ALDXRW] = t
+
+		case ALDAXR:
+			oprange[ALDAXRW] = t
+
+		case ALDXP:
+			oprange[ALDXPW] = t
+
+		case ASTLR:
+			oprange[ASTLRW] = t
+
+		case ASTXR:
+			oprange[ASTXRB] = t
+			oprange[ASTXRH] = t
+			oprange[ASTXRW] = t
+
+		case ASTLXR:
+			oprange[ASTLXRW] = t
+
+		case ASTXP:
+			oprange[ASTXPW] = t
+
+		case AAESD:
+			oprange[AAESE] = t
+			oprange[AAESMC] = t
+			oprange[AAESIMC] = t
+			oprange[ASHA1H] = t
+			oprange[ASHA1SU1] = t
+			oprange[ASHA256SU0] = t
+
+		case ASHA1C:
+			oprange[ASHA1P] = t
+			oprange[ASHA1M] = t
+			oprange[ASHA1SU0] = t
+			oprange[ASHA256H] = t
+			oprange[ASHA256H2] = t
+			oprange[ASHA256SU1] = t
+
+		case obj.ANOP,
+			obj.AUNDEF,
+			obj.AUSEFIELD,
+			obj.AFUNCDATA,
+			obj.APCDATA,
+			obj.ADUFFZERO,
+			obj.ADUFFCOPY:
+			break
+		}
+	}
+}
+
+func chipfloat7(ctxt *obj.Link, e float64) int {
+	ei := math.Float64bits(e)
+	l := uint32(int32(ei))
+	h := uint32(int32(ei >> 32))
+
+	if l != 0 || h&0xffff != 0 {
+		return -1
+	}
+	h1 := h & 0x7fc00000
+	if h1 != 0x40000000 && h1 != 0x3fc00000 {
+		return -1
+	}
+	n := 0
+
+	// sign bit (a)
+	if h&0x80000000 != 0 {
+		n |= 1 << 7
+	}
+
+	// exp sign bit (b)
+	if h1 == 0x3fc00000 {
+		n |= 1 << 6
+	}
+
+	// rest of exp and mantissa (cd-efgh)
+	n |= int((h >> 16) & 0x3f)
+
+	//print("match %.8lux %.8lux %d\n", l, h, n);
+	return n
+}
+
+/* form offset parameter to SYS; special register number */
+func SYSARG5(op0 int, op1 int, Cn int, Cm int, op2 int) int {
+	return op0<<19 | op1<<16 | Cn<<12 | Cm<<8 | op2<<5
+}
+
+func SYSARG4(op1 int, Cn int, Cm int, op2 int) int {
+	return SYSARG5(0, op1, Cn, Cm, op2)
+}
+
+func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) {
+	var lastcase *obj.Prog
+	o1 := uint32(0)
+	o2 := uint32(0)
+	o3 := uint32(0)
+	o4 := uint32(0)
+	o5 := uint32(0)
+	if false { /*debug['P']*/
+		fmt.Printf("%x: %v\ttype %d\n", uint32(p.Pc), p, o.type_)
+	}
+	switch o.type_ {
+	default:
+		ctxt.Diag("unknown asm %d", o.type_)
+		prasm(p)
+
+	case 0: /* pseudo ops */
+		break
+
+	case 1: /* op Rm,[Rn],Rd; default Rn=Rd -> op Rm<<0,[Rn,]Rd (shifted register) */
+		o1 = oprrr(ctxt, int(p.As))
+
+		rf := int(p.From.Reg)
+		rt := int(p.To.Reg)
+		r := int(p.Reg)
+		if p.To.Type == obj.TYPE_NONE {
+			rt = REGZERO
+		}
+		if r == 0 {
+			r = rt
+		}
+		o1 |= (uint32(rf&31) << 16) | (uint32(r&31) << 5) | uint32(rt&31)
+
+	case 2: /* add/sub $(uimm12|uimm24)[,R],R; cmp $(uimm12|uimm24),R */
+		o1 = opirr(ctxt, int(p.As))
+
+		rt := int(p.To.Reg)
+		if p.To.Type == obj.TYPE_NONE {
+			if (o1 & Sbit) == 0 {
+				ctxt.Diag("ineffective ZR destination\n%v", p)
+			}
+			rt = REGZERO
+		}
+
+		r := int(p.Reg)
+		if r == 0 {
+			r = rt
+		}
+		v := int32(regoff(ctxt, &p.From))
+		o1 = oaddi(ctxt, int32(o1), v, r, rt)
+
+	case 3: /* op R<<n[,R],R (shifted register) */
+		o1 = oprrr(ctxt, int(p.As))
+
+		o1 |= uint32(p.From.Offset) /* includes reg, op, etc */
+		rt := int(p.To.Reg)
+		if p.To.Type == obj.TYPE_NONE {
+			rt = REGZERO
+		}
+		r := int(p.Reg)
+		if p.As == AMVN || p.As == AMVNW {
+			r = REGZERO
+		} else if r == 0 {
+			r = rt
+		}
+		o1 |= (uint32(r&31) << 5) | uint32(rt&31)
+
+	case 4: /* mov $addcon, R; mov $recon, R; mov $racon, R */
+		o1 = opirr(ctxt, int(p.As))
+
+		rt := int(p.To.Reg)
+		r := int(o.param)
+		if r == 0 {
+			r = REGZERO
+		} else if r == REGFROM {
+			r = int(p.From.Reg)
+		}
+		if r == 0 {
+			r = REGSP
+		}
+		v := int32(regoff(ctxt, &p.From))
+		if (v & 0xFFF000) != 0 {
+			v >>= 12
+			o1 |= 1 << 22 /* shift, by 12 */
+		}
+
+		o1 |= ((uint32(v) & 0xFFF) << 10) | (uint32(r&31) << 5) | uint32(rt&31)
+
+	case 5: /* b s; bl s */
+		o1 = opbra(ctxt, int(p.As))
+
+		if p.To.Sym == nil {
+			o1 |= uint32(brdist(ctxt, p, 0, 26, 2))
+			break
+		}
+
+		rel := obj.Addrel(ctxt.Cursym)
+		rel.Off = int32(ctxt.Pc)
+		rel.Siz = 4
+		rel.Sym = p.To.Sym
+		rel.Add = int64(o1) | (p.To.Offset>>2)&0x3ffffff
+		rel.Type = obj.R_CALLARM64
+
+	case 6: /* b ,O(R); bl ,O(R) */
+		o1 = opbrr(ctxt, int(p.As))
+
+		o1 |= uint32(p.To.Reg&31) << 5
+		rel := obj.Addrel(ctxt.Cursym)
+		rel.Off = int32(ctxt.Pc)
+		rel.Siz = 0
+		rel.Type = obj.R_CALLIND
+
+	case 7: /* beq s */
+		o1 = opbra(ctxt, int(p.As))
+
+		o1 |= uint32(brdist(ctxt, p, 0, 19, 2) << 5)
+
+	case 8: /* lsl $c,[R],R -> ubfm $(W-1)-c,$(-c MOD (W-1)),Rn,Rd */
+		rt := int(p.To.Reg)
+
+		rf := int(p.Reg)
+		if rf == 0 {
+			rf = rt
+		}
+		v := int32(p.From.Offset)
+		switch p.As {
+		case AASR:
+			o1 = opbfm(ctxt, ASBFM, int(v), 63, rf, rt)
+
+		case AASRW:
+			o1 = opbfm(ctxt, ASBFMW, int(v), 31, rf, rt)
+
+		case ALSL:
+			o1 = opbfm(ctxt, AUBFM, int((64-v)&63), int(63-v), rf, rt)
+
+		case ALSLW:
+			o1 = opbfm(ctxt, AUBFMW, int((32-v)&31), int(31-v), rf, rt)
+
+		case ALSR:
+			o1 = opbfm(ctxt, AUBFM, int(v), 63, rf, rt)
+
+		case ALSRW:
+			o1 = opbfm(ctxt, AUBFMW, int(v), 31, rf, rt)
+
+		case AROR:
+			o1 = opextr(ctxt, AEXTR, v, rf, rf, rt)
+
+		case ARORW:
+			o1 = opextr(ctxt, AEXTRW, v, rf, rf, rt)
+
+		default:
+			ctxt.Diag("bad shift $con\n%v", ctxt.Curp)
+			break
+		}
+
+	case 9: /* lsl Rm,[Rn],Rd -> lslv Rm, Rn, Rd */
+		o1 = oprrr(ctxt, int(p.As))
+
+		r := int(p.Reg)
+		if r == 0 {
+			r = int(p.To.Reg)
+		}
+		o1 |= (uint32(p.From.Reg&31) << 16) | (uint32(r&31) << 5) | uint32(p.To.Reg&31)
+
+	case 10: /* brk/hvc/.../svc [$con] */
+		o1 = opimm(ctxt, int(p.As))
+
+		if p.To.Type != obj.TYPE_NONE {
+			o1 |= uint32((p.To.Offset & 0xffff) << 5)
+		}
+
+	case 11: /* dword */
+		aclass(ctxt, &p.To)
+
+		o1 = uint32(ctxt.Instoffset)
+		o2 = uint32(ctxt.Instoffset >> 32)
+		if p.To.Sym != nil {
+			rel := obj.Addrel(ctxt.Cursym)
+			rel.Off = int32(ctxt.Pc)
+			rel.Siz = 8
+			rel.Sym = p.To.Sym
+			rel.Add = p.To.Offset
+			rel.Type = obj.R_ADDR
+			o2 = 0
+			o1 = o2
+		}
+
+	case 12: /* movT $vcon, reg */
+		o1 = omovlit(ctxt, int(p.As), p, &p.From, int(p.To.Reg))
+
+	case 13: /* addop $vcon, [R], R (64 bit literal); cmp $lcon,R -> addop $lcon,R, ZR */
+		o1 = omovlit(ctxt, AMOVD, p, &p.From, REGTMP)
+
+		if !(o1 != 0) {
+			break
+		}
+		rt := int(p.To.Reg)
+		if p.To.Type == obj.TYPE_NONE {
+			rt = REGZERO
+		}
+		r := int(p.Reg)
+		if r == 0 {
+			r = rt
+		}
+		if p.To.Type != obj.TYPE_NONE && (p.To.Reg == REGSP || r == REGSP) {
+			o2 = opxrrr(ctxt, int(p.As))
+			o2 |= REGTMP & 31 << 16
+			o2 |= LSL0_64
+		} else {
+			o2 = oprrr(ctxt, int(p.As))
+			o2 |= REGTMP & 31 << 16 /* shift is 0 */
+		}
+
+		o2 |= uint32(r&31) << 5
+		o2 |= uint32(rt & 31)
+
+	case 14: /* word */
+		if aclass(ctxt, &p.To) == C_ADDR {
+			ctxt.Diag("address constant needs DWORD\n%v", p)
+		}
+		o1 = uint32(ctxt.Instoffset)
+		if p.To.Sym != nil {
+			// This case happens with words generated
+			// in the PC stream as part of the literal pool.
+			rel := obj.Addrel(ctxt.Cursym)
+
+			rel.Off = int32(ctxt.Pc)
+			rel.Siz = 4
+			rel.Sym = p.To.Sym
+			rel.Add = p.To.Offset
+			rel.Type = obj.R_ADDR
+			o1 = 0
+		}
+
+	case 15: /* mul/mneg/umulh/umull r,[r,]r; madd/msub Rm,Rn,Ra,Rd */
+		o1 = oprrr(ctxt, int(p.As))
+
+		rf := int(p.From.Reg)
+		rt := int(p.To.Reg)
+		var r int
+		var ra int
+		if p.From3.Type == obj.TYPE_REG {
+			r = int(p.From3.Reg)
+			ra = int(p.Reg)
+			if ra == 0 {
+				ra = REGZERO
+			}
+		} else {
+			r = int(p.Reg)
+			if r == 0 {
+				r = rt
+			}
+			ra = REGZERO
+		}
+
+		o1 |= (uint32(rf&31) << 16) | (uint32(ra&31) << 10) | (uint32(r&31) << 5) | uint32(rt&31)
+
+	case 16: /* XremY R[,R],R -> XdivY; XmsubY */
+		o1 = oprrr(ctxt, int(p.As))
+
+		rf := int(p.From.Reg)
+		rt := int(p.To.Reg)
+		r := int(p.Reg)
+		if r == 0 {
+			r = rt
+		}
+		o1 |= (uint32(rf&31) << 16) | (uint32(r&31) << 5) | REGTMP&31
+		o2 = oprrr(ctxt, AMSUBW)
+		o2 |= o1 & (1 << 31) /* same size */
+		o2 |= (uint32(rf&31) << 16) | (uint32(r&31) << 10) | (REGTMP & 31 << 5) | uint32(rt&31)
+
+	case 17: /* op Rm,[Rn],Rd; default Rn=ZR */
+		o1 = oprrr(ctxt, int(p.As))
+
+		rf := int(p.From.Reg)
+		rt := int(p.To.Reg)
+		r := int(p.Reg)
+		if p.To.Type == obj.TYPE_NONE {
+			rt = REGZERO
+		}
+		if r == 0 {
+			r = REGZERO
+		}
+		o1 |= (uint32(rf&31) << 16) | (uint32(r&31) << 5) | uint32(rt&31)
+
+	case 18: /* csel cond,Rn,Rm,Rd; cinc/cinv/cneg cond,Rn,Rd; cset cond,Rd */
+		o1 = oprrr(ctxt, int(p.As))
+
+		cond := int(p.From.Reg)
+		r := int(p.Reg)
+		var rf int
+		if r != 0 {
+			if p.From3.Type == obj.TYPE_NONE {
+				/* CINC/CINV/CNEG */
+				rf = r
+
+				cond ^= 1
+			} else {
+				rf = int(p.From3.Reg) /* CSEL */
+			}
+		} else {
+			/* CSET */
+			if p.From3.Type != obj.TYPE_NONE {
+				ctxt.Diag("invalid combination\n%v", p)
+			}
+			rf = REGZERO
+			r = rf
+			cond ^= 1
+		}
+
+		rt := int(p.To.Reg)
+		o1 |= (uint32(r&31) << 16) | (uint32(cond) << 12) | (uint32(rf&31) << 5) | uint32(rt&31)
+
+	case 19: /* CCMN cond, (Rm|uimm5),Rn, uimm4 -> ccmn Rn,Rm,uimm4,cond */
+		nzcv := int(p.To.Offset)
+
+		cond := int(p.From.Reg)
+		var rf int
+		if p.From3.Type == obj.TYPE_REG {
+			o1 = oprrr(ctxt, int(p.As))
+			rf = int(p.From3.Reg) /* Rm */
+		} else {
+			o1 = opirr(ctxt, int(p.As))
+			rf = int(p.From3.Offset & 0x1F)
+		}
+
+		o1 |= (uint32(rf&31) << 16) | (uint32(cond) << 12) | (uint32(p.Reg&31) << 5) | uint32(nzcv)
+
+	case 20: /* movT R,O(R) -> strT */
+		v := int32(regoff(ctxt, &p.To))
+
+		r := int(p.To.Reg)
+		if r == 0 {
+			r = int(o.param)
+		}
+		if v < 0 { /* unscaled 9-bit signed */
+			o1 = olsr9s(ctxt, int32(opstr9(ctxt, int(p.As))), v, r, int(p.From.Reg))
+		} else {
+			v = int32(offsetshift(ctxt, int64(v), int(o.a3)))
+			o1 = olsr12u(ctxt, int32(opstr12(ctxt, int(p.As))), v, r, int(p.From.Reg))
+		}
+
+	case 21: /* movT O(R),R -> ldrT */
+		v := int32(regoff(ctxt, &p.From))
+
+		r := int(p.From.Reg)
+		if r == 0 {
+			r = int(o.param)
+		}
+		if v < 0 { /* unscaled 9-bit signed */
+			o1 = olsr9s(ctxt, int32(opldr9(ctxt, int(p.As))), v, r, int(p.To.Reg))
+		} else {
+			v = int32(offsetshift(ctxt, int64(v), int(o.a1)))
+
+			//print("offset=%lld v=%ld a1=%d\n", instoffset, v, o->a1);
+			o1 = olsr12u(ctxt, int32(opldr12(ctxt, int(p.As))), v, r, int(p.To.Reg))
+		}
+
+	case 22: /* movT (R)O!,R; movT O(R)!, R -> ldrT */
+		v := int32(p.From.Offset)
+
+		if v < -256 || v > 255 {
+			ctxt.Diag("offset out of range\n%v", p)
+		}
+		o1 = opldrpp(ctxt, int(p.As))
+		if o.scond == C_XPOST {
+			o1 |= 1 << 10
+		} else {
+			o1 |= 3 << 10
+		}
+		o1 |= ((uint32(v) & 0x1FF) << 12) | (uint32(p.From.Reg&31) << 5) | uint32(p.To.Reg&31)
+
+	case 23: /* movT R,(R)O!; movT O(R)!, R -> strT */
+		v := int32(p.To.Offset)
+
+		if v < -256 || v > 255 {
+			ctxt.Diag("offset out of range\n%v", p)
+		}
+		o1 = LD2STR(opldrpp(ctxt, int(p.As)))
+		if o.scond == C_XPOST {
+			o1 |= 1 << 10
+		} else {
+			o1 |= 3 << 10
+		}
+		o1 |= ((uint32(v) & 0x1FF) << 12) | (uint32(p.To.Reg&31) << 5) | uint32(p.From.Reg&31)
+
+	case 24: /* mov/mvn Rs,Rd -> add $0,Rs,Rd or orr Rs,ZR,Rd */
+		rf := int(p.From.Reg)
+		rt := int(p.To.Reg)
+		s := bool2int(rf == REGSP || rt == REGSP)
+		if p.As == AMVN || p.As == AMVNW {
+			if s != 0 {
+				ctxt.Diag("illegal SP reference\n%v", p)
+			}
+			o1 = oprrr(ctxt, int(p.As))
+			o1 |= (uint32(rf&31) << 16) | (REGZERO & 31 << 5) | uint32(rt&31)
+		} else if s != 0 {
+			o1 = opirr(ctxt, int(p.As))
+			o1 |= (uint32(rf&31) << 5) | uint32(rt&31)
+		} else {
+			o1 = oprrr(ctxt, int(p.As))
+			o1 |= (uint32(rf&31) << 16) | (REGZERO & 31 << 5) | uint32(rt&31)
+		}
+
+	case 25: /* negX Rs, Rd -> subX Rs<<0, ZR, Rd */
+		o1 = oprrr(ctxt, int(p.As))
+
+		rf := int(p.From.Reg)
+		rt := int(p.To.Reg)
+		o1 |= (uint32(rf&31) << 16) | (REGZERO & 31 << 5) | uint32(rt&31)
+
+	case 26: /* negX Rm<<s, Rd -> subX Rm<<s, ZR, Rd */
+		o1 = oprrr(ctxt, int(p.As))
+
+		o1 |= uint32(p.From.Offset) /* includes reg, op, etc */
+		rt := int(p.To.Reg)
+		o1 |= (REGZERO & 31 << 5) | uint32(rt&31)
+
+	case 27: /* op Rm<<n[,Rn],Rd (extended register) */
+		o1 = opxrrr(ctxt, int(p.As))
+
+		if (p.From.Reg-obj.RBaseARM64)&REG_EXT != 0 {
+			ctxt.Diag("extended register not implemented\n%v", p)
+			// o1 |= uint32(p.From.Offset) /* includes reg, op, etc */
+		} else {
+			o1 |= uint32(p.From.Reg&31) << 16
+		}
+		rt := int(p.To.Reg)
+		if p.To.Type == obj.TYPE_NONE {
+			rt = REGZERO
+		}
+		r := int(p.Reg)
+		if r == 0 {
+			r = rt
+		}
+		o1 |= (uint32(r&31) << 5) | uint32(rt&31)
+
+	case 28: /* logop $vcon, [R], R (64 bit literal) */
+		o1 = omovlit(ctxt, AMOVD, p, &p.From, REGTMP)
+
+		if !(o1 != 0) {
+			break
+		}
+		r := int(p.Reg)
+		if r == 0 {
+			r = int(p.To.Reg)
+		}
+		o2 = oprrr(ctxt, int(p.As))
+		o2 |= REGTMP & 31 << 16 /* shift is 0 */
+		o2 |= uint32(r&31) << 5
+		o2 |= uint32(p.To.Reg & 31)
+
+	case 29: /* op Rn, Rd */
+		o1 = oprrr(ctxt, int(p.As))
+
+		o1 |= uint32(p.From.Reg&31)<<5 | uint32(p.To.Reg&31)
+
+	case 30: /* movT R,L(R) -> strT */
+		s := movesize(int(o.as))
+
+		if s < 0 {
+			ctxt.Diag("unexpected long move, op %v tab %v\n%v", obj.Aconv(int(p.As)), obj.Aconv(int(o.as)), p)
+		}
+		v := int32(regoff(ctxt, &p.To))
+		if v < 0 {
+			ctxt.Diag("negative large offset\n%v", p)
+		}
+		if (v & ((1 << uint(s)) - 1)) != 0 {
+			ctxt.Diag("misaligned offset\n%v", p)
+		}
+		hi := v - (v & (0xFFF << uint(s)))
+		if (hi & 0xFFF) != 0 {
+			ctxt.Diag("internal: miscalculated offset %d [%d]\n%v", v, s, p)
+		}
+
+		//fprint(2, "v=%ld (%#lux) s=%d hi=%ld (%#lux) v'=%ld (%#lux)\n", v, v, s, hi, hi, ((v-hi)>>s)&0xFFF, ((v-hi)>>s)&0xFFF);
+		r := int(p.To.Reg)
+
+		if r == 0 {
+			r = int(o.param)
+		}
+		o1 = oaddi(ctxt, int32(opirr(ctxt, AADD)), hi, r, REGTMP)
+		o2 = olsr12u(ctxt, int32(opstr12(ctxt, int(p.As))), ((v-hi)>>uint(s))&0xFFF, REGTMP, int(p.From.Reg))
+
+	case 31: /* movT L(R), R -> ldrT */
+		s := movesize(int(o.as))
+
+		if s < 0 {
+			ctxt.Diag("unexpected long move, op %v tab %v\n%v", obj.Aconv(int(p.As)), obj.Aconv(int(o.as)), p)
+		}
+		v := int32(regoff(ctxt, &p.From))
+		if v < 0 {
+			ctxt.Diag("negative large offset\n%v", p)
+		}
+		if (v & ((1 << uint(s)) - 1)) != 0 {
+			ctxt.Diag("misaligned offset\n%v", p)
+		}
+		hi := v - (v & (0xFFF << uint(s)))
+		if (hi & 0xFFF) != 0 {
+			ctxt.Diag("internal: miscalculated offset %d [%d]\n%v", v, s, p)
+		}
+
+		//fprint(2, "v=%ld (%#lux) s=%d hi=%ld (%#lux) v'=%ld (%#lux)\n", v, v, s, hi, hi, ((v-hi)>>s)&0xFFF, ((v-hi)>>s)&0xFFF);
+		r := int(p.From.Reg)
+
+		if r == 0 {
+			r = int(o.param)
+		}
+		o1 = oaddi(ctxt, int32(opirr(ctxt, AADD)), hi, r, REGTMP)
+		o2 = olsr12u(ctxt, int32(opldr12(ctxt, int(p.As))), ((v-hi)>>uint(s))&0xFFF, REGTMP, int(p.To.Reg))
+
+	case 32: /* mov $con, R -> movz/movn */
+		r := 32
+
+		if p.As == AMOVD {
+			r = 64
+		}
+		d := p.From.Offset
+		s := movcon(d)
+		if s < 0 || s >= r {
+			d = ^d
+			s = movcon(d)
+			if s < 0 || s >= r {
+				ctxt.Diag("impossible move wide: %#x\n%v", uint64(p.From.Offset), p)
+			}
+			if p.As == AMOVD {
+				o1 = opirr(ctxt, AMOVN)
+			} else {
+				o1 = opirr(ctxt, AMOVNW)
+			}
+		} else {
+			if p.As == AMOVD {
+				o1 = opirr(ctxt, AMOVZ)
+			} else {
+				o1 = opirr(ctxt, AMOVZW)
+			}
+		}
+
+		rt := int(p.To.Reg)
+		o1 |= uint32((((d >> uint(s*16)) & 0xFFFF) << 5) | int64((uint32(s)&3)<<21) | int64(rt&31))
+
+	case 33: /* movk $uimm16 << pos */
+		o1 = opirr(ctxt, int(p.As))
+
+		d := p.From.Offset
+		if (d >> 16) != 0 {
+			ctxt.Diag("requires uimm16\n%v", p)
+		}
+		s := 0
+		if p.From3.Type != obj.TYPE_NONE {
+			if p.From3.Type != obj.TYPE_CONST {
+				ctxt.Diag("missing bit position\n%v", p)
+			}
+			s = int(p.From3.Offset / 16)
+			if (s*16&0xF) != 0 || s >= 4 || (o1&S64) == 0 && s >= 2 {
+				ctxt.Diag("illegal bit position\n%v", p)
+			}
+		}
+
+		rt := int(p.To.Reg)
+		o1 |= uint32(((d & 0xFFFF) << 5) | int64((uint32(s)&3)<<21) | int64(rt&31))
+
+	case 34: /* mov $lacon,R */
+		o1 = omovlit(ctxt, AMOVD, p, &p.From, REGTMP)
+
+		if !(o1 != 0) {
+			break
+		}
+		o2 = opxrrr(ctxt, AADD)
+		o2 |= REGTMP & 31 << 16
+		o2 |= LSL0_64
+		r := int(p.From.Reg)
+		if r == 0 {
+			r = int(o.param)
+		}
+		o2 |= uint32(r&31) << 5
+		o2 |= uint32(p.To.Reg & 31)
+
+	case 35: /* mov SPR,R -> mrs */
+		o1 = oprrr(ctxt, AMRS)
+
+		v := int32(p.From.Offset)
+		if (o1 & uint32(v&^(3<<19))) != 0 {
+			ctxt.Diag("MRS register value overlap\n%v", p)
+		}
+		o1 |= uint32(v)
+		o1 |= uint32(p.To.Reg & 31)
+
+	case 36: /* mov R,SPR */
+		o1 = oprrr(ctxt, AMSR)
+
+		v := int32(p.To.Offset)
+		if (o1 & uint32(v&^(3<<19))) != 0 {
+			ctxt.Diag("MSR register value overlap\n%v", p)
+		}
+		o1 |= uint32(v)
+		o1 |= uint32(p.From.Reg & 31)
+
+	case 37: /* mov $con,PSTATEfield -> MSR [immediate] */
+		if (uint64(p.From.Offset) &^ uint64(0xF)) != 0 {
+			ctxt.Diag("illegal immediate for PSTATE field\n%v", p)
+		}
+		o1 = opirr(ctxt, AMSR)
+		o1 |= uint32((p.From.Offset & 0xF) << 8) /* Crm */
+		v := int32(0)
+		for i := 0; i < len(pstatefield); i++ {
+			if int64(pstatefield[i].a) == p.To.Offset {
+				v = int32(pstatefield[i].b)
+				break
+			}
+		}
+
+		if v == 0 {
+			ctxt.Diag("illegal PSTATE field for immediate move\n%v", p)
+		}
+		o1 |= uint32(v)
+
+	case 38: /* clrex [$imm] */
+		o1 = opimm(ctxt, int(p.As))
+
+		if p.To.Type == obj.TYPE_NONE {
+			o1 |= 0xF << 8
+		} else {
+			o1 |= uint32((p.To.Offset & 0xF) << 8)
+		}
+
+	case 39: /* cbz R, rel */
+		o1 = opirr(ctxt, int(p.As))
+
+		o1 |= uint32(p.From.Reg & 31)
+		o1 |= uint32(brdist(ctxt, p, 0, 19, 2) << 5)
+
+	case 40: /* tbz */
+		o1 = opirr(ctxt, int(p.As))
+
+		v := int32(p.From.Offset)
+		if v < 0 || v > 63 {
+			ctxt.Diag("illegal bit number\n%v", p)
+		}
+		o1 |= ((uint32(v) & 0x20) << (31 - 5)) | ((uint32(v) & 0x1F) << 19)
+		o1 |= uint32(brdist(ctxt, p, 0, 14, 2) << 5)
+		o1 |= uint32(p.Reg)
+
+	case 41: /* eret, nop, others with no operands */
+		o1 = op0(ctxt, int(p.As))
+
+	case 42: /* bfm R,r,s,R */
+		o1 = opbfm(ctxt, int(p.As), int(p.From.Offset), int(p.From3.Offset), int(p.Reg), int(p.To.Reg))
+
+	case 43: /* bfm aliases */
+		r := int(p.From.Offset)
+
+		s := int(p.From3.Offset)
+		rf := int(p.Reg)
+		rt := int(p.To.Reg)
+		if rf == 0 {
+			rf = rt
+		}
+		switch p.As {
+		case ABFI:
+			o1 = opbfm(ctxt, ABFM, 64-r, s-1, rf, rt)
+
+		case ABFIW:
+			o1 = opbfm(ctxt, ABFMW, 32-r, s-1, rf, rt)
+
+		case ABFXIL:
+			o1 = opbfm(ctxt, ABFM, r, r+s-1, rf, rt)
+
+		case ABFXILW:
+			o1 = opbfm(ctxt, ABFMW, r, r+s-1, rf, rt)
+
+		case ASBFIZ:
+			o1 = opbfm(ctxt, ASBFM, 64-r, s-1, rf, rt)
+
+		case ASBFIZW:
+			o1 = opbfm(ctxt, ASBFMW, 32-r, s-1, rf, rt)
+
+		case ASBFX:
+			o1 = opbfm(ctxt, ASBFM, r, r+s-1, rf, rt)
+
+		case ASBFXW:
+			o1 = opbfm(ctxt, ASBFMW, r, r+s-1, rf, rt)
+
+		case AUBFIZ:
+			o1 = opbfm(ctxt, AUBFM, 64-r, s-1, rf, rt)
+
+		case AUBFIZW:
+			o1 = opbfm(ctxt, AUBFMW, 32-r, s-1, rf, rt)
+
+		case AUBFX:
+			o1 = opbfm(ctxt, AUBFM, r, r+s-1, rf, rt)
+
+		case AUBFXW:
+			o1 = opbfm(ctxt, AUBFMW, r, r+s-1, rf, rt)
+
+		default:
+			ctxt.Diag("bad bfm alias\n%v", ctxt.Curp)
+			break
+		}
+
+	case 44: /* extr $b, Rn, Rm, Rd */
+		o1 = opextr(ctxt, int(p.As), int32(p.From.Offset), int(p.From3.Reg), int(p.Reg), int(p.To.Reg))
+
+	case 45: /* sxt/uxt[bhw] R,R; movT R,R -> sxtT R,R */
+		rf := int(p.From.Reg)
+
+		rt := int(p.To.Reg)
+		as := int(p.As)
+		if rf == REGZERO {
+			as = AMOVWU /* clearer in disassembly */
+		}
+		switch as {
+		case AMOVB, ASXTB:
+			o1 = opbfm(ctxt, ASBFM, 0, 7, rf, rt)
+
+		case AMOVH, ASXTH:
+			o1 = opbfm(ctxt, ASBFM, 0, 15, rf, rt)
+
+		case AMOVW, ASXTW:
+			o1 = opbfm(ctxt, ASBFM, 0, 31, rf, rt)
+
+		case AMOVBU, AUXTB:
+			o1 = opbfm(ctxt, AUBFM, 0, 7, rf, rt)
+
+		case AMOVHU, AUXTH:
+			o1 = opbfm(ctxt, AUBFM, 0, 15, rf, rt)
+
+		case AMOVWU:
+			o1 = oprrr(ctxt, as) | (uint32(rf&31) << 16) | (REGZERO & 31 << 5) | uint32(rt&31)
+
+		case AUXTW:
+			o1 = opbfm(ctxt, AUBFM, 0, 31, rf, rt)
+
+		case ASXTBW:
+			o1 = opbfm(ctxt, ASBFMW, 0, 7, rf, rt)
+
+		case ASXTHW:
+			o1 = opbfm(ctxt, ASBFMW, 0, 15, rf, rt)
+
+		case AUXTBW:
+			o1 = opbfm(ctxt, AUBFMW, 0, 7, rf, rt)
+
+		case AUXTHW:
+			o1 = opbfm(ctxt, AUBFMW, 0, 15, rf, rt)
+
+		default:
+			ctxt.Diag("bad sxt %v", obj.Aconv(as))
+			break
+		}
+
+	case 46: /* cls */
+		o1 = opbit(ctxt, int(p.As))
+
+		o1 |= uint32(p.From.Reg&31) << 5
+		o1 |= uint32(p.To.Reg & 31)
+
+	case 47: /* movT R,V(R) -> strT (huge offset) */
+		o1 = omovlit(ctxt, AMOVW, p, &p.To, REGTMP)
+
+		if !(o1 != 0) {
+			break
+		}
+		r := int(p.To.Reg)
+		if r == 0 {
+			r = int(o.param)
+		}
+		o2 = olsxrr(ctxt, int(p.As), REGTMP, r, int(p.From.Reg))
+
+	case 48: /* movT V(R), R -> ldrT (huge offset) */
+		o1 = omovlit(ctxt, AMOVW, p, &p.From, REGTMP)
+
+		if !(o1 != 0) {
+			break
+		}
+		r := int(p.From.Reg)
+		if r == 0 {
+			r = int(o.param)
+		}
+		o2 = olsxrr(ctxt, int(p.As), REGTMP, r, int(p.To.Reg))
+
+	case 50: /* sys/sysl */
+		o1 = opirr(ctxt, int(p.As))
+
+		if (p.From.Offset &^ int64(SYSARG4(0x7, 0xF, 0xF, 0x7))) != 0 {
+			ctxt.Diag("illegal SYS argument\n%v", p)
+		}
+		o1 |= uint32(p.From.Offset)
+		if p.To.Type == obj.TYPE_REG {
+			o1 |= uint32(p.To.Reg & 31)
+		} else if p.Reg != 0 {
+			o1 |= uint32(p.Reg & 31)
+		} else {
+			o1 |= 0x1F
+		}
+
+	case 51: /* dmb */
+		o1 = opirr(ctxt, int(p.As))
+
+		if p.From.Type == obj.TYPE_CONST {
+			o1 |= uint32((p.From.Offset & 0xF) << 8)
+		}
+
+	case 52: /* hint */
+		o1 = opirr(ctxt, int(p.As))
+
+		o1 |= uint32((p.From.Offset & 0x7F) << 5)
+
+	case 53: /* and/or/eor/bic/... $bimmN, Rn, Rd -> op (N,r,s), Rn, Rd */
+		ctxt.Diag("bitmask immediate not implemented\n%v", p)
+
+	case 54: /* floating point arith */
+		o1 = oprrr(ctxt, int(p.As))
+
+		var rf int
+		if p.From.Type == obj.TYPE_CONST {
+			rf = chipfloat7(ctxt, p.From.Val.(float64))
+			if rf < 0 || true {
+				ctxt.Diag("invalid floating-point immediate\n%v", p)
+				rf = 0
+			}
+
+			rf |= (1 << 3)
+		} else {
+			rf = int(p.From.Reg)
+		}
+		rt := int(p.To.Reg)
+		r := int(p.Reg)
+		if (o1&(0x1F<<24)) == (0x1E<<24) && (o1&(1<<11)) == 0 { /* monadic */
+			r = rf
+			rf = 0
+		} else if r == 0 {
+			r = rt
+		}
+		o1 |= (uint32(rf&31) << 16) | (uint32(r&31) << 5) | uint32(rt&31)
+
+	case 56: /* floating point compare */
+		o1 = oprrr(ctxt, int(p.As))
+
+		var rf int
+		if p.From.Type == obj.TYPE_CONST {
+			o1 |= 8 /* zero */
+			rf = 0
+		} else {
+			rf = int(p.From.Reg)
+		}
+		rt := int(p.Reg)
+		o1 |= uint32(rf&31)<<16 | uint32(rt&31)<<5
+
+	case 57: /* floating point conditional compare */
+		o1 = oprrr(ctxt, int(p.As))
+
+		cond := int(p.From.Reg)
+		nzcv := int(p.To.Offset)
+		if nzcv&^0xF != 0 {
+			ctxt.Diag("implausible condition\n%v", p)
+		}
+		rf := int(p.Reg)
+		if p.From3.Reg < REG_F0 || p.From3.Reg > REG_F31 {
+			ctxt.Diag("illegal FCCMP\n%v", p)
+		}
+		rt := int(p.From3.Reg)
+		o1 |= uint32(rf&31)<<16 | uint32(cond)<<12 | uint32(rt&31)<<5 | uint32(nzcv)
+
+	case 58: /* ldar/ldxr/ldaxr */
+		o1 = opload(ctxt, int(p.As))
+
+		o1 |= 0x1F << 16
+		o1 |= uint32(p.From.Reg) << 5
+		if p.Reg != 0 {
+			o1 |= uint32(p.Reg) << 10
+		} else {
+			o1 |= 0x1F << 10
+		}
+		o1 |= uint32(p.To.Reg & 31)
+
+	case 59: /* stxr/stlxr */
+		o1 = opstore(ctxt, int(p.As))
+
+		if p.To2.Type != obj.TYPE_NONE {
+			o1 |= uint32(p.To2.Reg&31) << 16
+		} else {
+			o1 |= 0x1F << 16
+		}
+
+		// TODO(aram): add support for STXP
+		o1 |= uint32(p.To.Reg&31) << 5
+
+		o1 |= uint32(p.From.Reg & 31)
+
+	case 60: /* adrp label,r */
+		d := brdist(ctxt, p, 12, 21, 0)
+
+		o1 = ADR(1, uint32(d), uint32(p.To.Reg))
+
+	case 61: /* adr label, r */
+		d := brdist(ctxt, p, 0, 21, 0)
+
+		o1 = ADR(0, uint32(d), uint32(p.To.Reg))
+
+	case 62: /* case Rv, Rt -> adr tab, Rt; movw Rt[R<<2], Rl; add Rt, Rl; br (Rl) */
+		// adr 4(pc), Rt
+		o1 = ADR(0, 4*4, uint32(p.To.Reg))
+		// movw Rt[Rv<<2], REGTMP
+		o2 = (2 << 30) | (7 << 27) | (2 << 22) | (1 << 21) | (3 << 13) | (1 << 12) | (2 << 10) | (uint32(p.From.Reg&31) << 16) | (uint32(p.To.Reg&31) << 5) | REGTMP&31
+		// add Rt, REGTMP
+		o3 = oprrr(ctxt, AADD) | (uint32(p.To.Reg) << 16) | (REGTMP << 5) | REGTMP
+		// br (REGTMP)
+		o4 = (0x6b << 25) | (0x1F << 16) | (REGTMP & 31 << 5)
+		lastcase = p
+
+	case 63: /* bcase */
+		if lastcase == nil {
+			ctxt.Diag("missing CASE\n%v", p)
+			break
+		}
+
+		if p.Pcond != nil {
+			o1 = uint32(p.Pcond.Pc - (lastcase.Pc + 4*4))
+			ctxt.Diag("FIXME: some relocation needed in bcase\n%v", p)
+		}
+
+		/* reloc ops */
+	case 64: /* movT R,addr */
+		o1 = omovlit(ctxt, AMOVD, p, &p.To, REGTMP)
+
+		if !(o1 != 0) {
+			break
+		}
+		o2 = olsr12u(ctxt, int32(opstr12(ctxt, int(p.As))), 0, REGTMP, int(p.From.Reg))
+
+	case 65: /* movT addr,R */
+		o1 = omovlit(ctxt, AMOVD, p, &p.From, REGTMP)
+
+		if !(o1 != 0) {
+			break
+		}
+		o2 = olsr12u(ctxt, int32(opldr12(ctxt, int(p.As))), 0, REGTMP, int(p.To.Reg))
+
+	case 66: /* ldp O(R)!, (r1, r2); ldp (R)O!, (r1, r2) */
+		v := int32(p.From.Offset)
+
+		if v < -512 || v > 504 {
+			ctxt.Diag("offset out of range\n%v", p)
+		}
+		if o.scond == C_XPOST {
+			o1 |= 1 << 23
+		} else {
+			o1 |= 3 << 23
+		}
+		o1 |= 1 << 22
+		o1 |= uint32(int64(2<<30|5<<27|((uint32(v)/8)&0x7f)<<15) | p.To.Offset<<10 | int64(uint32(p.From.Reg&31)<<5) | int64(p.To.Reg&31))
+
+	case 67: /* stp (r1, r2), O(R)!; stp (r1, r2), (R)O! */
+		v := int32(p.To.Offset)
+
+		if v < -512 || v > 504 {
+			ctxt.Diag("offset out of range\n%v", p)
+		}
+		if o.scond == C_XPOST {
+			o1 |= 1 << 23
+		} else {
+			o1 |= 3 << 23
+		}
+		o1 |= uint32(int64(2<<30|5<<27|((uint32(v)/8)&0x7f)<<15) | p.From.Offset<<10 | int64(uint32(p.To.Reg&31)<<5) | int64(p.From.Reg&31))
+
+	// This is supposed to be something that stops execution.
+	// It's not supposed to be reached, ever, but if it is, we'd
+	// like to be able to tell how we got there.  Assemble as
+	// 0xbea71700 which is guaranteed to raise undefined instruction
+	// exception.
+	case 90:
+		o1 = 0xbea71700
+
+		break
+	}
+
+	out[0] = o1
+	out[1] = o2
+	out[2] = o3
+	out[3] = o4
+	out[4] = o5
+	return
+}
+
+/*
+ * basic Rm op Rn -> Rd (using shifted register with 0)
+ * also op Rn -> Rt
+ * also Rm*Rn op Ra -> Rd
+ */
+func oprrr(ctxt *obj.Link, a int) uint32 {
+	switch a {
+	case AADC:
+		return S64 | 0<<30 | 0<<29 | 0xd0<<21 | 0<<10
+
+	case AADCW:
+		return S32 | 0<<30 | 0<<29 | 0xd0<<21 | 0<<10
+
+	case AADCS:
+		return S64 | 0<<30 | 1<<29 | 0xd0<<21 | 0<<10
+
+	case AADCSW:
+		return S32 | 0<<30 | 1<<29 | 0xd0<<21 | 0<<10
+
+	case ANGC, ASBC:
+		return S64 | 1<<30 | 0<<29 | 0xd0<<21 | 0<<10
+
+	case ANGCS, ASBCS:
+		return S64 | 1<<30 | 1<<29 | 0xd0<<21 | 0<<10
+
+	case ANGCW, ASBCW:
+		return S32 | 1<<30 | 0<<29 | 0xd0<<21 | 0<<10
+
+	case ANGCSW, ASBCSW:
+		return S32 | 1<<30 | 1<<29 | 0xd0<<21 | 0<<10
+
+	case AADD:
+		return S64 | 0<<30 | 0<<29 | 0x0b<<24 | 0<<22 | 0<<21 | 0<<10
+
+	case AADDW:
+		return S32 | 0<<30 | 0<<29 | 0x0b<<24 | 0<<22 | 0<<21 | 0<<10
+
+	case ACMN, AADDS:
+		return S64 | 0<<30 | 1<<29 | 0x0b<<24 | 0<<22 | 0<<21 | 0<<10
+
+	case ACMNW, AADDSW:
+		return S32 | 0<<30 | 1<<29 | 0x0b<<24 | 0<<22 | 0<<21 | 0<<10
+
+	case ASUB:
+		return S64 | 1<<30 | 0<<29 | 0x0b<<24 | 0<<22 | 0<<21 | 0<<10
+
+	case ASUBW:
+		return S32 | 1<<30 | 0<<29 | 0x0b<<24 | 0<<22 | 0<<21 | 0<<10
+
+	case ACMP, ASUBS:
+		return S64 | 1<<30 | 1<<29 | 0x0b<<24 | 0<<22 | 0<<21 | 0<<10
+
+	case ACMPW, ASUBSW:
+		return S32 | 1<<30 | 1<<29 | 0x0b<<24 | 0<<22 | 0<<21 | 0<<10
+
+	case AAND:
+		return S64 | 0<<29 | 0xA<<24
+
+	case AANDW:
+		return S32 | 0<<29 | 0xA<<24
+
+	case AMOVD, AORR:
+		return S64 | 1<<29 | 0xA<<24
+
+		//	case AMOVW:
+	case AMOVWU, AORRW:
+		return S32 | 1<<29 | 0xA<<24
+
+	case AEOR:
+		return S64 | 2<<29 | 0xA<<24
+
+	case AEORW:
+		return S32 | 2<<29 | 0xA<<24
+
+	case AANDS:
+		return S64 | 3<<29 | 0xA<<24
+
+	case AANDSW:
+		return S32 | 3<<29 | 0xA<<24
+
+	case ABIC:
+		return S64 | 0<<29 | 0xA<<24 | 1<<21
+
+	case ABICW:
+		return S32 | 0<<29 | 0xA<<24 | 1<<21
+
+	case ABICS:
+		return S64 | 3<<29 | 0xA<<24 | 1<<21
+
+	case ABICSW:
+		return S32 | 3<<29 | 0xA<<24 | 1<<21
+
+	case AEON:
+		return S64 | 2<<29 | 0xA<<24 | 1<<21
+
+	case AEONW:
+		return S32 | 2<<29 | 0xA<<24 | 1<<21
+
+	case AMVN, AORN:
+		return S64 | 1<<29 | 0xA<<24 | 1<<21
+
+	case AMVNW, AORNW:
+		return S32 | 1<<29 | 0xA<<24 | 1<<21
+
+	case AASR:
+		return S64 | OPDP2(10) /* also ASRV */
+
+	case AASRW:
+		return S32 | OPDP2(10)
+
+	case ALSL:
+		return S64 | OPDP2(8)
+
+	case ALSLW:
+		return S32 | OPDP2(8)
+
+	case ALSR:
+		return S64 | OPDP2(9)
+
+	case ALSRW:
+		return S32 | OPDP2(9)
+
+	case AROR:
+		return S64 | OPDP2(11)
+
+	case ARORW:
+		return S32 | OPDP2(11)
+
+	case ACCMN:
+		return S64 | 0<<30 | 1<<29 | 0xD2<<21 | 0<<11 | 0<<10 | 0<<4 /* cond<<12 | nzcv<<0 */
+
+	case ACCMNW:
+		return S32 | 0<<30 | 1<<29 | 0xD2<<21 | 0<<11 | 0<<10 | 0<<4
+
+	case ACCMP:
+		return S64 | 1<<30 | 1<<29 | 0xD2<<21 | 0<<11 | 0<<10 | 0<<4 /* imm5<<16 | cond<<12 | nzcv<<0 */
+
+	case ACCMPW:
+		return S32 | 1<<30 | 1<<29 | 0xD2<<21 | 0<<11 | 0<<10 | 0<<4
+
+	case ACRC32B:
+		return S32 | OPDP2(16)
+
+	case ACRC32H:
+		return S32 | OPDP2(17)
+
+	case ACRC32W:
+		return S32 | OPDP2(18)
+
+	case ACRC32X:
+		return S64 | OPDP2(19)
+
+	case ACRC32CB:
+		return S32 | OPDP2(20)
+
+	case ACRC32CH:
+		return S32 | OPDP2(21)
+
+	case ACRC32CW:
+		return S32 | OPDP2(22)
+
+	case ACRC32CX:
+		return S64 | OPDP2(23)
+
+	case ACSEL:
+		return S64 | 0<<30 | 0<<29 | 0xD4<<21 | 0<<11 | 0<<10
+
+	case ACSELW:
+		return S32 | 0<<30 | 0<<29 | 0xD4<<21 | 0<<11 | 0<<10
+
+	case ACSET:
+		return S64 | 0<<30 | 0<<29 | 0xD4<<21 | 0<<11 | 1<<10
+
+	case ACSETW:
+		return S32 | 0<<30 | 0<<29 | 0xD4<<21 | 0<<11 | 1<<10
+
+	case ACSETM:
+		return S64 | 1<<30 | 0<<29 | 0xD4<<21 | 0<<11 | 0<<10
+
+	case ACSETMW:
+		return S32 | 1<<30 | 0<<29 | 0xD4<<21 | 0<<11 | 0<<10
+
+	case ACINC, ACSINC:
+		return S64 | 0<<30 | 0<<29 | 0xD4<<21 | 0<<11 | 1<<10
+
+	case ACINCW, ACSINCW:
+		return S32 | 0<<30 | 0<<29 | 0xD4<<21 | 0<<11 | 1<<10
+
+	case ACINV, ACSINV:
+		return S64 | 1<<30 | 0<<29 | 0xD4<<21 | 0<<11 | 0<<10
+
+	case ACINVW, ACSINVW:
+		return S32 | 1<<30 | 0<<29 | 0xD4<<21 | 0<<11 | 0<<10
+
+	case ACNEG, ACSNEG:
+		return S64 | 1<<30 | 0<<29 | 0xD4<<21 | 0<<11 | 1<<10
+
+	case ACNEGW, ACSNEGW:
+		return S32 | 1<<30 | 0<<29 | 0xD4<<21 | 0<<11 | 1<<10
+
+	case AMUL, AMADD:
+		return S64 | 0<<29 | 0x1B<<24 | 0<<21 | 0<<15
+
+	case AMULW, AMADDW:
+		return S32 | 0<<29 | 0x1B<<24 | 0<<21 | 0<<15
+
+	case AMNEG, AMSUB:
+		return S64 | 0<<29 | 0x1B<<24 | 0<<21 | 1<<15
+
+	case AMNEGW, AMSUBW:
+		return S32 | 0<<29 | 0x1B<<24 | 0<<21 | 1<<15
+
+	case AMRS:
+		return SYSOP(1, 2, 0, 0, 0, 0, 0)
+
+	case AMSR:
+		return SYSOP(0, 2, 0, 0, 0, 0, 0)
+
+	case ANEG:
+		return S64 | 1<<30 | 0<<29 | 0xB<<24 | 0<<21
+
+	case ANEGW:
+		return S32 | 1<<30 | 0<<29 | 0xB<<24 | 0<<21
+
+	case ANEGS:
+		return S64 | 1<<30 | 1<<29 | 0xB<<24 | 0<<21
+
+	case ANEGSW:
+		return S32 | 1<<30 | 1<<29 | 0xB<<24 | 0<<21
+
+	case AREM, ASDIV:
+		return S64 | OPDP2(3)
+
+	case AREMW, ASDIVW:
+		return S32 | OPDP2(3)
+
+	case ASMULL, ASMADDL:
+		return OPDP3(1, 0, 1, 0)
+
+	case ASMNEGL, ASMSUBL:
+		return OPDP3(1, 0, 1, 1)
+
+	case ASMULH:
+		return OPDP3(1, 0, 2, 0)
+
+	case AUMULL, AUMADDL:
+		return OPDP3(1, 0, 5, 0)
+
+	case AUMNEGL, AUMSUBL:
+		return OPDP3(1, 0, 5, 1)
+
+	case AUMULH:
+		return OPDP3(1, 0, 6, 0)
+
+	case AUREM, AUDIV:
+		return S64 | OPDP2(2)
+
+	case AUREMW, AUDIVW:
+		return S32 | OPDP2(2)
+
+	case AAESE:
+		return 0x4E<<24 | 2<<20 | 8<<16 | 4<<12 | 2<<10
+
+	case AAESD:
+		return 0x4E<<24 | 2<<20 | 8<<16 | 5<<12 | 2<<10
+
+	case AAESMC:
+		return 0x4E<<24 | 2<<20 | 8<<16 | 6<<12 | 2<<10
+
+	case AAESIMC:
+		return 0x4E<<24 | 2<<20 | 8<<16 | 7<<12 | 2<<10
+
+	case ASHA1C:
+		return 0x5E<<24 | 0<<12
+
+	case ASHA1P:
+		return 0x5E<<24 | 1<<12
+
+	case ASHA1M:
+		return 0x5E<<24 | 2<<12
+
+	case ASHA1SU0:
+		return 0x5E<<24 | 3<<12
+
+	case ASHA256H:
+		return 0x5E<<24 | 4<<12
+
+	case ASHA256H2:
+		return 0x5E<<24 | 5<<12
+
+	case ASHA256SU1:
+		return 0x5E<<24 | 6<<12
+
+	case ASHA1H:
+		return 0x5E<<24 | 2<<20 | 8<<16 | 0<<12 | 2<<10
+
+	case ASHA1SU1:
+		return 0x5E<<24 | 2<<20 | 8<<16 | 1<<12 | 2<<10
+
+	case ASHA256SU0:
+		return 0x5E<<24 | 2<<20 | 8<<16 | 2<<12 | 2<<10
+
+	case AFCVTZSD:
+		return FPCVTI(1, 0, 1, 3, 0)
+
+	case AFCVTZSDW:
+		return FPCVTI(0, 0, 1, 3, 0)
+
+	case AFCVTZSS:
+		return FPCVTI(1, 0, 0, 3, 0)
+
+	case AFCVTZSSW:
+		return FPCVTI(0, 0, 0, 3, 0)
+
+	case AFCVTZUD:
+		return FPCVTI(1, 0, 1, 3, 1)
+
+	case AFCVTZUDW:
+		return FPCVTI(0, 0, 1, 3, 1)
+
+	case AFCVTZUS:
+		return FPCVTI(1, 0, 0, 3, 1)
+
+	case AFCVTZUSW:
+		return FPCVTI(0, 0, 0, 3, 1)
+
+	case ASCVTFD:
+		return FPCVTI(1, 0, 1, 0, 2)
+
+	case ASCVTFS:
+		return FPCVTI(1, 0, 0, 0, 2)
+
+	case ASCVTFWD:
+		return FPCVTI(0, 0, 1, 0, 2)
+
+	case ASCVTFWS:
+		return FPCVTI(0, 0, 0, 0, 2)
+
+	case AUCVTFD:
+		return FPCVTI(1, 0, 1, 0, 3)
+
+	case AUCVTFS:
+		return FPCVTI(1, 0, 0, 0, 3)
+
+	case AUCVTFWD:
+		return FPCVTI(0, 0, 1, 0, 3)
+
+	case AUCVTFWS:
+		return FPCVTI(0, 0, 0, 0, 3)
+
+	case AFADDS:
+		return FPOP2S(0, 0, 0, 2)
+
+	case AFADDD:
+		return FPOP2S(0, 0, 1, 2)
+
+	case AFSUBS:
+		return FPOP2S(0, 0, 0, 3)
+
+	case AFSUBD:
+		return FPOP2S(0, 0, 1, 3)
+
+	case AFMULS:
+		return FPOP2S(0, 0, 0, 0)
+
+	case AFMULD:
+		return FPOP2S(0, 0, 1, 0)
+
+	case AFDIVS:
+		return FPOP2S(0, 0, 0, 1)
+
+	case AFDIVD:
+		return FPOP2S(0, 0, 1, 1)
+
+	case AFMAXS:
+		return FPOP2S(0, 0, 0, 4)
+
+	case AFMINS:
+		return FPOP2S(0, 0, 0, 5)
+
+	case AFMAXD:
+		return FPOP2S(0, 0, 1, 4)
+
+	case AFMIND:
+		return FPOP2S(0, 0, 1, 5)
+
+	case AFMAXNMS:
+		return FPOP2S(0, 0, 0, 6)
+
+	case AFMAXNMD:
+		return FPOP2S(0, 0, 1, 6)
+
+	case AFMINNMS:
+		return FPOP2S(0, 0, 0, 7)
+
+	case AFMINNMD:
+		return FPOP2S(0, 0, 1, 7)
+
+	case AFNMULS:
+		return FPOP2S(0, 0, 0, 8)
+
+	case AFNMULD:
+		return FPOP2S(0, 0, 1, 8)
+
+	case AFCMPS:
+		return FPCMP(0, 0, 0, 0, 0)
+
+	case AFCMPD:
+		return FPCMP(0, 0, 1, 0, 0)
+
+	case AFCMPES:
+		return FPCMP(0, 0, 0, 0, 16)
+
+	case AFCMPED:
+		return FPCMP(0, 0, 1, 0, 16)
+
+	case AFCCMPS:
+		return FPCCMP(0, 0, 0, 0)
+
+	case AFCCMPD:
+		return FPCCMP(0, 0, 1, 0)
+
+	case AFCCMPES:
+		return FPCCMP(0, 0, 0, 1)
+
+	case AFCCMPED:
+		return FPCCMP(0, 0, 1, 1)
+
+	case AFCSELS:
+		return 0x1E<<24 | 0<<22 | 1<<21 | 3<<10
+
+	case AFCSELD:
+		return 0x1E<<24 | 1<<22 | 1<<21 | 3<<10
+
+	case AFMOVS:
+		return FPOP1S(0, 0, 0, 0)
+
+	case AFABSS:
+		return FPOP1S(0, 0, 0, 1)
+
+	case AFNEGS:
+		return FPOP1S(0, 0, 0, 2)
+
+	case AFSQRTS:
+		return FPOP1S(0, 0, 0, 3)
+
+	case AFCVTSD:
+		return FPOP1S(0, 0, 0, 5)
+
+	case AFCVTSH:
+		return FPOP1S(0, 0, 0, 7)
+
+	case AFRINTNS:
+		return FPOP1S(0, 0, 0, 8)
+
+	case AFRINTPS:
+		return FPOP1S(0, 0, 0, 9)
+
+	case AFRINTMS:
+		return FPOP1S(0, 0, 0, 10)
+
+	case AFRINTZS:
+		return FPOP1S(0, 0, 0, 11)
+
+	case AFRINTAS:
+		return FPOP1S(0, 0, 0, 12)
+
+	case AFRINTXS:
+		return FPOP1S(0, 0, 0, 14)
+
+	case AFRINTIS:
+		return FPOP1S(0, 0, 0, 15)
+
+	case AFMOVD:
+		return FPOP1S(0, 0, 1, 0)
+
+	case AFABSD:
+		return FPOP1S(0, 0, 1, 1)
+
+	case AFNEGD:
+		return FPOP1S(0, 0, 1, 2)
+
+	case AFSQRTD:
+		return FPOP1S(0, 0, 1, 3)
+
+	case AFCVTDS:
+		return FPOP1S(0, 0, 1, 4)
+
+	case AFCVTDH:
+		return FPOP1S(0, 0, 1, 7)
+
+	case AFRINTND:
+		return FPOP1S(0, 0, 1, 8)
+
+	case AFRINTPD:
+		return FPOP1S(0, 0, 1, 9)
+
+	case AFRINTMD:
+		return FPOP1S(0, 0, 1, 10)
+
+	case AFRINTZD:
+		return FPOP1S(0, 0, 1, 11)
+
+	case AFRINTAD:
+		return FPOP1S(0, 0, 1, 12)
+
+	case AFRINTXD:
+		return FPOP1S(0, 0, 1, 14)
+
+	case AFRINTID:
+		return FPOP1S(0, 0, 1, 15)
+
+	case AFCVTHS:
+		return FPOP1S(0, 0, 3, 4)
+
+	case AFCVTHD:
+		return FPOP1S(0, 0, 3, 5)
+	}
+
+	ctxt.Diag("bad rrr %d %v", a, obj.Aconv(a))
+	prasm(ctxt.Curp)
+	return 0
+}
+
+/*
+ * imm -> Rd
+ * imm op Rn -> Rd
+ */
+func opirr(ctxt *obj.Link, a int) uint32 {
+	switch a {
+	/* op $addcon, Rn, Rd */
+	case AMOVD, AADD:
+		return S64 | 0<<30 | 0<<29 | 0x11<<24
+
+	case ACMN, AADDS:
+		return S64 | 0<<30 | 1<<29 | 0x11<<24
+
+	case AMOVW, AADDW:
+		return S32 | 0<<30 | 0<<29 | 0x11<<24
+
+	case ACMNW, AADDSW:
+		return S32 | 0<<30 | 1<<29 | 0x11<<24
+
+	case ASUB:
+		return S64 | 1<<30 | 0<<29 | 0x11<<24
+
+	case ACMP, ASUBS:
+		return S64 | 1<<30 | 1<<29 | 0x11<<24
+
+	case ASUBW:
+		return S32 | 1<<30 | 0<<29 | 0x11<<24
+
+	case ACMPW, ASUBSW:
+		return S32 | 1<<30 | 1<<29 | 0x11<<24
+
+		/* op $imm(SB), Rd; op label, Rd */
+	case AADR:
+		return 0<<31 | 0x10<<24
+
+	case AADRP:
+		return 1<<31 | 0x10<<24
+
+		/* op $bimm, Rn, Rd */
+	case AAND:
+		return S64 | 0<<29 | 0x24<<23
+
+	case AANDW:
+		return S32 | 0<<29 | 0x24<<23 | 0<<22
+
+	case AORR:
+		return S64 | 1<<29 | 0x24<<23
+
+	case AORRW:
+		return S32 | 1<<29 | 0x24<<23 | 0<<22
+
+	case AEOR:
+		return S64 | 2<<29 | 0x24<<23
+
+	case AEORW:
+		return S32 | 2<<29 | 0x24<<23 | 0<<22
+
+	case AANDS:
+		return S64 | 3<<29 | 0x24<<23
+
+	case AANDSW:
+		return S32 | 3<<29 | 0x24<<23 | 0<<22
+
+	case AASR:
+		return S64 | 0<<29 | 0x26<<23 /* alias of SBFM */
+
+	case AASRW:
+		return S32 | 0<<29 | 0x26<<23 | 0<<22
+
+		/* op $width, $lsb, Rn, Rd */
+	case ABFI:
+		return S64 | 2<<29 | 0x26<<23 | 1<<22
+		/* alias of BFM */
+
+	case ABFIW:
+		return S32 | 2<<29 | 0x26<<23 | 0<<22
+
+		/* op $imms, $immr, Rn, Rd */
+	case ABFM:
+		return S64 | 1<<29 | 0x26<<23 | 1<<22
+
+	case ABFMW:
+		return S32 | 1<<29 | 0x26<<23 | 0<<22
+
+	case ASBFM:
+		return S64 | 0<<29 | 0x26<<23 | 1<<22
+
+	case ASBFMW:
+		return S32 | 0<<29 | 0x26<<23 | 0<<22
+
+	case AUBFM:
+		return S64 | 2<<29 | 0x26<<23 | 1<<22
+
+	case AUBFMW:
+		return S32 | 2<<29 | 0x26<<23 | 0<<22
+
+	case ABFXIL:
+		return S64 | 1<<29 | 0x26<<23 | 1<<22 /* alias of BFM */
+
+	case ABFXILW:
+		return S32 | 1<<29 | 0x26<<23 | 0<<22
+
+	case AEXTR:
+		return S64 | 0<<29 | 0x27<<23 | 1<<22 | 0<<21
+
+	case AEXTRW:
+		return S32 | 0<<29 | 0x27<<23 | 0<<22 | 0<<21
+
+	case ACBNZ:
+		return S64 | 0x1A<<25 | 1<<24
+
+	case ACBNZW:
+		return S32 | 0x1A<<25 | 1<<24
+
+	case ACBZ:
+		return S64 | 0x1A<<25 | 0<<24
+
+	case ACBZW:
+		return S32 | 0x1A<<25 | 0<<24
+
+	case ACCMN:
+		return S64 | 0<<30 | 1<<29 | 0xD2<<21 | 1<<11 | 0<<10 | 0<<4 /* imm5<<16 | cond<<12 | nzcv<<0 */
+
+	case ACCMNW:
+		return S32 | 0<<30 | 1<<29 | 0xD2<<21 | 1<<11 | 0<<10 | 0<<4
+
+	case ACCMP:
+		return S64 | 1<<30 | 1<<29 | 0xD2<<21 | 1<<11 | 0<<10 | 0<<4 /* imm5<<16 | cond<<12 | nzcv<<0 */
+
+	case ACCMPW:
+		return S32 | 1<<30 | 1<<29 | 0xD2<<21 | 1<<11 | 0<<10 | 0<<4
+
+	case AMOVK:
+		return S64 | 3<<29 | 0x25<<23
+
+	case AMOVKW:
+		return S32 | 3<<29 | 0x25<<23
+
+	case AMOVN:
+		return S64 | 0<<29 | 0x25<<23
+
+	case AMOVNW:
+		return S32 | 0<<29 | 0x25<<23
+
+	case AMOVZ:
+		return S64 | 2<<29 | 0x25<<23
+
+	case AMOVZW:
+		return S32 | 2<<29 | 0x25<<23
+
+	case AMSR:
+		return SYSOP(0, 0, 0, 4, 0, 0, 0x1F) /* MSR (immediate) */
+
+	case AAT,
+		ADC,
+		AIC,
+		ATLBI,
+		ASYS:
+		return SYSOP(0, 1, 0, 0, 0, 0, 0)
+
+	case ASYSL:
+		return SYSOP(1, 1, 0, 0, 0, 0, 0)
+
+	case ATBZ:
+		return 0x36 << 24
+
+	case ATBNZ:
+		return 0x37 << 24
+
+	case ADSB:
+		return SYSOP(0, 0, 3, 3, 0, 4, 0x1F)
+
+	case ADMB:
+		return SYSOP(0, 0, 3, 3, 0, 5, 0x1F)
+
+	case AISB:
+		return SYSOP(0, 0, 3, 3, 0, 6, 0x1F)
+
+	case AHINT:
+		return SYSOP(0, 0, 3, 2, 0, 0, 0x1F)
+	}
+
+	ctxt.Diag("bad irr %v", obj.Aconv(a))
+	prasm(ctxt.Curp)
+	return 0
+}
+
+func opbit(ctxt *obj.Link, a int) uint32 {
+	switch a {
+	case ACLS:
+		return S64 | OPBIT(5)
+
+	case ACLSW:
+		return S32 | OPBIT(5)
+
+	case ACLZ:
+		return S64 | OPBIT(4)
+
+	case ACLZW:
+		return S32 | OPBIT(4)
+
+	case ARBIT:
+		return S64 | OPBIT(0)
+
+	case ARBITW:
+		return S32 | OPBIT(0)
+
+	case AREV:
+		return S64 | OPBIT(3)
+
+	case AREVW:
+		return S32 | OPBIT(2)
+
+	case AREV16:
+		return S64 | OPBIT(1)
+
+	case AREV16W:
+		return S32 | OPBIT(1)
+
+	case AREV32:
+		return S64 | OPBIT(2)
+
+	default:
+		ctxt.Diag("bad bit op\n%v", ctxt.Curp)
+		return 0
+	}
+}
+
+/*
+ * add/subtract extended register
+ */
+func opxrrr(ctxt *obj.Link, a int) uint32 {
+	switch a {
+	case AADD:
+		return S64 | 0<<30 | 0<<29 | 0x0b<<24 | 0<<22 | 1<<21 | LSL0_64
+
+	case AADDW:
+		return S32 | 0<<30 | 0<<29 | 0x0b<<24 | 0<<22 | 1<<21 | LSL0_32
+
+	case ACMN, AADDS:
+		return S64 | 0<<30 | 1<<29 | 0x0b<<24 | 0<<22 | 1<<21 | LSL0_64
+
+	case ACMNW, AADDSW:
+		return S32 | 0<<30 | 1<<29 | 0x0b<<24 | 0<<22 | 1<<21 | LSL0_32
+
+	case ASUB:
+		return S64 | 1<<30 | 0<<29 | 0x0b<<24 | 0<<22 | 1<<21 | LSL0_64
+
+	case ASUBW:
+		return S32 | 1<<30 | 0<<29 | 0x0b<<24 | 0<<22 | 1<<21 | LSL0_32
+
+	case ACMP, ASUBS:
+		return S64 | 1<<30 | 1<<29 | 0x0b<<24 | 0<<22 | 1<<21 | LSL0_64
+
+	case ACMPW, ASUBSW:
+		return S32 | 1<<30 | 1<<29 | 0x0b<<24 | 0<<22 | 1<<21 | LSL0_32
+	}
+
+	ctxt.Diag("bad opxrrr %v\n%v", obj.Aconv(a), ctxt.Curp)
+	return 0
+}
+
+func opimm(ctxt *obj.Link, a int) uint32 {
+	switch a {
+	case ASVC:
+		return 0xD4<<24 | 0<<21 | 1 /* imm16<<5 */
+
+	case AHVC:
+		return 0xD4<<24 | 0<<21 | 2
+
+	case ASMC:
+		return 0xD4<<24 | 0<<21 | 3
+
+	case ABRK:
+		return 0xD4<<24 | 1<<21 | 0
+
+	case AHLT:
+		return 0xD4<<24 | 2<<21 | 0
+
+	case ADCPS1:
+		return 0xD4<<24 | 5<<21 | 1
+
+	case ADCPS2:
+		return 0xD4<<24 | 5<<21 | 2
+
+	case ADCPS3:
+		return 0xD4<<24 | 5<<21 | 3
+
+	case ACLREX:
+		return SYSOP(0, 0, 3, 3, 0, 2, 0x1F)
+	}
+
+	ctxt.Diag("bad imm %v", obj.Aconv(a))
+	prasm(ctxt.Curp)
+	return 0
+}
+
+func brdist(ctxt *obj.Link, p *obj.Prog, preshift int, flen int, shift int) int64 {
+	v := int64(0)
+	t := int64(0)
+	if p.Pcond != nil {
+		v = (p.Pcond.Pc >> uint(preshift)) - (ctxt.Pc >> uint(preshift))
+		if (v & ((1 << uint(shift)) - 1)) != 0 {
+			ctxt.Diag("misaligned label\n%v", p)
+		}
+		v >>= uint(shift)
+		t = int64(1) << uint(flen-1)
+		if v < -t || v >= t {
+			ctxt.Diag("branch too far\n%v", p)
+		}
+	}
+
+	return v & ((t << 1) - 1)
+}
+
+/*
+ * pc-relative branches
+ */
+func opbra(ctxt *obj.Link, a int) uint32 {
+	switch a {
+	case ABEQ:
+		return OPBcc(0x0)
+
+	case ABNE:
+		return OPBcc(0x1)
+
+	case ABCS:
+		return OPBcc(0x2)
+
+	case ABHS:
+		return OPBcc(0x2)
+
+	case ABCC:
+		return OPBcc(0x3)
+
+	case ABLO:
+		return OPBcc(0x3)
+
+	case ABMI:
+		return OPBcc(0x4)
+
+	case ABPL:
+		return OPBcc(0x5)
+
+	case ABVS:
+		return OPBcc(0x6)
+
+	case ABVC:
+		return OPBcc(0x7)
+
+	case ABHI:
+		return OPBcc(0x8)
+
+	case ABLS:
+		return OPBcc(0x9)
+
+	case ABGE:
+		return OPBcc(0xa)
+
+	case ABLT:
+		return OPBcc(0xb)
+
+	case ABGT:
+		return OPBcc(0xc)
+
+	case ABLE:
+		return OPBcc(0xd) /* imm19<<5 | cond */
+
+	case AB:
+		return 0<<31 | 5<<26 /* imm26 */
+
+	case obj.ADUFFZERO,
+		ABL:
+		return 1<<31 | 5<<26
+	}
+
+	ctxt.Diag("bad bra %v", obj.Aconv(a))
+	prasm(ctxt.Curp)
+	return 0
+}
+
+func opbrr(ctxt *obj.Link, a int) uint32 {
+	switch a {
+	case ABL:
+		return OPBLR(1) /* BLR */
+
+	case AB:
+		return OPBLR(0) /* BR */
+
+	case obj.ARET:
+		return OPBLR(2) /* RET */
+	}
+
+	ctxt.Diag("bad brr %v", obj.Aconv(a))
+	prasm(ctxt.Curp)
+	return 0
+}
+
+func op0(ctxt *obj.Link, a int) uint32 {
+	switch a {
+	case ADRPS:
+		return 0x6B<<25 | 5<<21 | 0x1F<<16 | 0x1F<<5
+
+	case AERET:
+		return 0x6B<<25 | 4<<21 | 0x1F<<16 | 0<<10 | 0x1F<<5
+
+	// case ANOP:
+	// 	return SYSHINT(0)
+
+	case AYIELD:
+		return SYSHINT(1)
+
+	case AWFE:
+		return SYSHINT(2)
+
+	case AWFI:
+		return SYSHINT(3)
+
+	case ASEV:
+		return SYSHINT(4)
+
+	case ASEVL:
+		return SYSHINT(5)
+	}
+
+	ctxt.Diag("bad op0 %v", obj.Aconv(a))
+	prasm(ctxt.Curp)
+	return 0
+}
+
+/*
+ * register offset
+ */
+func opload(ctxt *obj.Link, a int) uint32 {
+	switch a {
+	case ALDAR:
+		return LDSTX(3, 1, 1, 0, 1) | 0x1F<<10
+
+	case ALDARW:
+		return LDSTX(2, 1, 1, 0, 1) | 0x1F<<10
+
+	case ALDARB:
+		return LDSTX(0, 1, 1, 0, 1) | 0x1F<<10
+
+	case ALDARH:
+		return LDSTX(1, 1, 1, 0, 1) | 0x1F<<10
+
+	case ALDAXP:
+		return LDSTX(3, 0, 1, 1, 1)
+
+	case ALDAXPW:
+		return LDSTX(2, 0, 1, 1, 1)
+
+	case ALDAXR:
+		return LDSTX(3, 0, 1, 0, 1) | 0x1F<<10
+
+	case ALDAXRW:
+		return LDSTX(2, 0, 1, 0, 1) | 0x1F<<10
+
+	case ALDAXRB:
+		return LDSTX(0, 0, 1, 0, 1) | 0x1F<<10
+
+	case ALDAXRH:
+		return LDSTX(1, 0, 1, 0, 1) | 0x1F<<10
+
+	case ALDXR:
+		return LDSTX(3, 0, 1, 0, 0) | 0x1F<<10
+
+	case ALDXRB:
+		return LDSTX(0, 0, 1, 0, 0) | 0x1F<<10
+
+	case ALDXRH:
+		return LDSTX(1, 0, 1, 0, 0) | 0x1F<<10
+
+	case ALDXRW:
+		return LDSTX(2, 0, 1, 0, 0) | 0x1F<<10
+
+	case ALDXP:
+		return LDSTX(3, 0, 1, 1, 0)
+
+	case ALDXPW:
+		return LDSTX(2, 0, 1, 1, 0)
+
+	case AMOVNP:
+		return S64 | 0<<30 | 5<<27 | 0<<26 | 0<<23 | 1<<22
+
+	case AMOVNPW:
+		return S32 | 0<<30 | 5<<27 | 0<<26 | 0<<23 | 1<<22
+	}
+
+	ctxt.Diag("bad opload %v\n%v", obj.Aconv(a), ctxt.Curp)
+	return 0
+}
+
+func opstore(ctxt *obj.Link, a int) uint32 {
+	switch a {
+	case ASTLR:
+		return LDSTX(3, 1, 0, 0, 1) | 0x1F<<10
+
+	case ASTLRB:
+		return LDSTX(0, 1, 0, 0, 1) | 0x1F<<10
+
+	case ASTLRH:
+		return LDSTX(1, 1, 0, 0, 1) | 0x1F<<10
+
+	case ASTLP:
+		return LDSTX(3, 0, 0, 1, 1)
+
+	case ASTLPW:
+		return LDSTX(2, 0, 0, 1, 1)
+
+	case ASTLRW:
+		return LDSTX(2, 1, 0, 0, 1) | 0x1F<<10
+
+	case ASTLXP:
+		return LDSTX(2, 0, 0, 1, 1)
+
+	case ASTLXPW:
+		return LDSTX(3, 0, 0, 1, 1)
+
+	case ASTLXR:
+		return LDSTX(3, 0, 0, 0, 1) | 0x1F<<10
+
+	case ASTLXRB:
+		return LDSTX(0, 0, 0, 0, 1) | 0x1F<<10
+
+	case ASTLXRH:
+		return LDSTX(1, 0, 0, 0, 1) | 0x1F<<10
+
+	case ASTLXRW:
+		return LDSTX(2, 0, 0, 0, 1) | 0x1F<<10
+
+	case ASTXR:
+		return LDSTX(3, 0, 0, 0, 0) | 0x1F<<10
+
+	case ASTXRB:
+		return LDSTX(0, 0, 0, 0, 0) | 0x1F<<10
+
+	case ASTXRH:
+		return LDSTX(1, 0, 0, 0, 0) | 0x1F<<10
+
+	case ASTXP:
+		return LDSTX(3, 0, 0, 1, 0)
+
+	case ASTXPW:
+		return LDSTX(2, 0, 0, 1, 0)
+
+	case ASTXRW:
+		return LDSTX(2, 0, 0, 0, 0) | 0x1F<<10
+
+	case AMOVNP:
+		return S64 | 0<<30 | 5<<27 | 0<<26 | 0<<23 | 1<<22
+
+	case AMOVNPW:
+		return S32 | 0<<30 | 5<<27 | 0<<26 | 0<<23 | 1<<22
+	}
+
+	ctxt.Diag("bad opstore %v\n%v", obj.Aconv(a), ctxt.Curp)
+	return 0
+}
+
+/*
+ * load/store register (unsigned immediate) C3.3.13
+ *	these produce 64-bit values (when there's an option)
+ */
+func olsr12u(ctxt *obj.Link, o int32, v int32, b int, r int) uint32 {
+	if v < 0 || v >= (1<<12) {
+		ctxt.Diag("offset out of range: %d\n%v", v, ctxt.Curp)
+	}
+	o |= (v & 0xFFF) << 10
+	o |= int32(b&31) << 5
+	o |= int32(r & 31)
+	return uint32(o)
+}
+
+func opldr12(ctxt *obj.Link, a int) uint32 {
+	switch a {
+	case AMOVD:
+		return LDSTR12U(3, 0, 1) /* imm12<<10 | Rn<<5 | Rt */
+
+	case AMOVW:
+		return LDSTR12U(2, 0, 2)
+
+	case AMOVWU:
+		return LDSTR12U(2, 0, 1)
+
+	case AMOVH:
+		return LDSTR12U(1, 0, 2)
+
+	case AMOVHU:
+		return LDSTR12U(1, 0, 1)
+
+	case AMOVB:
+		return LDSTR12U(0, 0, 2)
+
+	case AMOVBU:
+		return LDSTR12U(0, 0, 1)
+
+	case AFMOVS:
+		return LDSTR12U(2, 1, 1)
+
+	case AFMOVD:
+		return LDSTR12U(3, 1, 1)
+	}
+
+	ctxt.Diag("bad opldr12 %v\n%v", obj.Aconv(a), ctxt.Curp)
+	return 0
+}
+
+func opstr12(ctxt *obj.Link, a int) uint32 {
+	return LD2STR(opldr12(ctxt, a))
+}
+
+/*
+ * load/store register (unscaled immediate) C3.3.12
+ */
+func olsr9s(ctxt *obj.Link, o int32, v int32, b int, r int) uint32 {
+	if v < -256 || v > 255 {
+		ctxt.Diag("offset out of range: %d\n%v", v, ctxt.Curp)
+	}
+	o |= (v & 0x1FF) << 12
+	o |= int32(b&31) << 5
+	o |= int32(r & 31)
+	return uint32(o)
+}
+
+func opldr9(ctxt *obj.Link, a int) uint32 {
+	switch a {
+	case AMOVD:
+		return LDSTR9S(3, 0, 1) /* simm9<<12 | Rn<<5 | Rt */
+
+	case AMOVW:
+		return LDSTR9S(2, 0, 2)
+
+	case AMOVWU:
+		return LDSTR9S(2, 0, 1)
+
+	case AMOVH:
+		return LDSTR9S(1, 0, 2)
+
+	case AMOVHU:
+		return LDSTR9S(1, 0, 1)
+
+	case AMOVB:
+		return LDSTR9S(0, 0, 2)
+
+	case AMOVBU:
+		return LDSTR9S(0, 0, 1)
+
+	case AFMOVS:
+		return LDSTR9S(2, 1, 1)
+
+	case AFMOVD:
+		return LDSTR9S(3, 1, 1)
+	}
+
+	ctxt.Diag("bad opldr9 %v\n%v", obj.Aconv(a), ctxt.Curp)
+	return 0
+}
+
+func opstr9(ctxt *obj.Link, a int) uint32 {
+	return LD2STR(opldr9(ctxt, a))
+}
+
+func opldrpp(ctxt *obj.Link, a int) uint32 {
+	switch a {
+	case AMOVD:
+		return 3<<30 | 7<<27 | 0<<26 | 0<<24 | 1<<22 /* simm9<<12 | Rn<<5 | Rt */
+
+	case AMOVW:
+		return 2<<30 | 7<<27 | 0<<26 | 0<<24 | 2<<22
+
+	case AMOVWU:
+		return 2<<30 | 7<<27 | 0<<26 | 0<<24 | 1<<22
+
+	case AMOVH:
+		return 1<<30 | 7<<27 | 0<<26 | 0<<24 | 2<<22
+
+	case AMOVHU:
+		return 1<<30 | 7<<27 | 0<<26 | 0<<24 | 1<<22
+
+	case AMOVB:
+		return 0<<30 | 7<<27 | 0<<26 | 0<<24 | 2<<22
+
+	case AMOVBU:
+		return 0<<30 | 7<<27 | 0<<26 | 0<<24 | 1<<22
+	}
+
+	ctxt.Diag("bad opldr %v\n%v", obj.Aconv(a), ctxt.Curp)
+	return 0
+}
+
+/*
+ * load/store register (extended register)
+ */
+func olsxrr(ctxt *obj.Link, as int, rt int, r1 int, r2 int) uint32 {
+	ctxt.Diag("need load/store extended register\n%v", ctxt.Curp)
+	return 0xffffffff
+}
+
+func oaddi(ctxt *obj.Link, o1 int32, v int32, r int, rt int) uint32 {
+	if (v & 0xFFF000) != 0 {
+		if v&0xFFF != 0 {
+			ctxt.Diag("%v misuses oaddi", ctxt.Curp)
+		}
+		v >>= 12
+		o1 |= 1 << 22
+	}
+
+	o1 |= ((v & 0xFFF) << 10) | (int32(r&31) << 5) | int32(rt&31)
+	return uint32(o1)
+}
+
+/*
+ * load a a literal value into dr
+ */
+func omovlit(ctxt *obj.Link, as int, p *obj.Prog, a *obj.Addr, dr int) uint32 {
+	var o1 int32
+	if p.Pcond == nil { /* not in literal pool */
+		aclass(ctxt, a)
+		fmt.Fprintf(ctxt.Bso, "omovlit add %d (%#x)\n", ctxt.Instoffset, uint64(ctxt.Instoffset))
+
+		/* TODO: could be clever, and use general constant builder */
+		o1 = int32(opirr(ctxt, AADD))
+
+		v := int32(ctxt.Instoffset)
+		if v != 0 && (v&0xFFF) == 0 {
+			v >>= 12
+			o1 |= 1 << 22 /* shift, by 12 */
+		}
+
+		o1 |= ((v & 0xFFF) << 10) | (REGZERO & 31 << 5) | int32(dr&31)
+	} else {
+		fp := 0
+		w := 0 /* default: 32 bit, unsigned */
+		switch as {
+		case AFMOVS:
+			fp = 1
+
+		case AFMOVD:
+			fp = 1
+			w = 1 /* 64 bit simd&fp */
+
+		case AMOVD:
+			if p.Pcond.As == ADWORD {
+				w = 1 /* 64 bit */
+			} else if p.Pcond.To.Offset < 0 {
+				w = 2 /* sign extend */
+			}
+
+		case AMOVB, AMOVH, AMOVW:
+			w = 2 /* 32 bit, sign-extended to 64 */
+			break
+		}
+
+		v := int32(brdist(ctxt, p, 0, 19, 2))
+		o1 = (int32(w) << 30) | (int32(fp) << 26) | (3 << 27)
+		o1 |= (v & 0x7FFFF) << 5
+		o1 |= int32(dr & 31)
+	}
+
+	return uint32(o1)
+}
+
+func opbfm(ctxt *obj.Link, a int, r int, s int, rf int, rt int) uint32 {
+	var c uint32
+	o := opirr(ctxt, a)
+	if (o & (1 << 31)) == 0 {
+		c = 32
+	} else {
+		c = 64
+	}
+	if r < 0 || uint32(r) >= c {
+		ctxt.Diag("illegal bit number\n%v", ctxt.Curp)
+	}
+	o |= (uint32(r) & 0x3F) << 16
+	if s < 0 || uint32(s) >= c {
+		ctxt.Diag("illegal bit number\n%v", ctxt.Curp)
+	}
+	o |= (uint32(s) & 0x3F) << 10
+	o |= (uint32(rf&31) << 5) | uint32(rt&31)
+	return o
+}
+
+func opextr(ctxt *obj.Link, a int, v int32, rn int, rm int, rt int) uint32 {
+	var c uint32
+	o := opirr(ctxt, a)
+	if (o & (1 << 31)) != 0 {
+		c = 63
+	} else {
+		c = 31
+	}
+	if v < 0 || uint32(v) > c {
+		ctxt.Diag("illegal bit number\n%v", ctxt.Curp)
+	}
+	o |= uint32(v) << 10
+	o |= uint32(rn&31) << 5
+	o |= uint32(rm&31) << 16
+	o |= uint32(rt & 31)
+	return o
+}
+
+/*
+ * size in log2(bytes)
+ */
+func movesize(a int) int {
+	switch a {
+	case AMOVD:
+		return 3
+
+	case AMOVW, AMOVWU:
+		return 2
+
+	case AMOVH, AMOVHU:
+		return 1
+
+	case AMOVB, AMOVBU:
+		return 0
+
+	case AFMOVS:
+		return 2
+
+	case AFMOVD:
+		return 3
+
+	default:
+		return -1
+	}
+}
diff --git a/src/cmd/internal/obj/arm64/list7.go b/src/cmd/internal/obj/arm64/list7.go
new file mode 100644
index 0000000..53d67c9
--- /dev/null
+++ b/src/cmd/internal/obj/arm64/list7.go
@@ -0,0 +1,114 @@
+// cmd/7l/list.c and cmd/7l/sub.c from Vita Nuova.
+// https://code.google.com/p/ken-cc/source/browse/
+//
+// 	Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
+// 	Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
+// 	Portions Copyright © 1997-1999 Vita Nuova Limited
+// 	Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
+// 	Portions Copyright © 2004,2006 Bruce Ellis
+// 	Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
+// 	Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
+// 	Portions Copyright © 2009 The Go Authors.  All rights reserved.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+package arm64
+
+import (
+	"cmd/internal/obj"
+	"fmt"
+)
+
+var strcond = [16]string{
+	"EQ",
+	"NE",
+	"HS",
+	"LO",
+	"MI",
+	"PL",
+	"VS",
+	"VC",
+	"HI",
+	"LS",
+	"GE",
+	"LT",
+	"GT",
+	"LE",
+	"AL",
+	"NV",
+}
+
+func init() {
+	obj.RegisterRegister(obj.RBaseARM64, REG_SPECIAL+1024, Rconv)
+	obj.RegisterOpcode(obj.ABaseARM64, Anames)
+}
+
+func Rconv(r int) string {
+	if r == REGG {
+		return "g"
+	}
+	switch {
+	case REG_R0 <= r && r <= REG_R30:
+		return fmt.Sprintf("R%d", r-REG_R0)
+	case r == REG_R31:
+		return "ZR"
+	case REG_F0 <= r && r <= REG_F31:
+		return fmt.Sprintf("F%d", r-REG_F0)
+	case REG_V0 <= r && r <= REG_V31:
+		return fmt.Sprintf("V%d", r-REG_F0)
+	case COND_EQ <= r && r <= COND_NV:
+		return strcond[r-COND_EQ]
+	case r == REGSP:
+		return "RSP"
+	case r == REG_DAIF:
+		return "DAIF"
+	case r == REG_NZCV:
+		return "NZCV"
+	case r == REG_FPSR:
+		return "FPSR"
+	case r == REG_FPCR:
+		return "FPCR"
+	case r == REG_SPSR_EL1:
+		return "SPSR_EL1"
+	case r == REG_ELR_EL1:
+		return "ELR_EL1"
+	case r == REG_SPSR_EL2:
+		return "SPSR_EL2"
+	case r == REG_ELR_EL2:
+		return "ELR_EL2"
+	case r == REG_CurrentEL:
+		return "CurrentEL"
+	case r == REG_SP_EL0:
+		return "SP_EL0"
+	case r == REG_SPSel:
+		return "SPSel"
+	case r == REG_DAIFSet:
+		return "DAIFSet"
+	case r == REG_DAIFClr:
+		return "DAIFClr"
+	}
+	return fmt.Sprintf("badreg(%d)", r)
+}
+
+func DRconv(a int) string {
+	if a >= C_NONE && a <= C_NCLASS {
+		return cnames7[a]
+	}
+	return "C_??"
+}
diff --git a/src/cmd/internal/obj/arm64/obj7.go b/src/cmd/internal/obj/arm64/obj7.go
new file mode 100644
index 0000000..52eef3f
--- /dev/null
+++ b/src/cmd/internal/obj/arm64/obj7.go
@@ -0,0 +1,828 @@
+// cmd/7l/noop.c, cmd/7l/obj.c, cmd/ld/pass.c from Vita Nuova.
+// https://code.google.com/p/ken-cc/source/browse/
+//
+// 	Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
+// 	Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
+// 	Portions Copyright © 1997-1999 Vita Nuova Limited
+// 	Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
+// 	Portions Copyright © 2004,2006 Bruce Ellis
+// 	Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
+// 	Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
+// 	Portions Copyright © 2009 The Go Authors.  All rights reserved.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+package arm64
+
+import (
+	"cmd/internal/obj"
+	"encoding/binary"
+	"fmt"
+	"log"
+	"math"
+)
+
+var complements = []int16{
+	AADD:  ASUB,
+	AADDW: ASUBW,
+	ASUB:  AADD,
+	ASUBW: AADDW,
+	ACMP:  ACMN,
+	ACMPW: ACMNW,
+	ACMN:  ACMP,
+	ACMNW: ACMPW,
+}
+
+func stacksplit(ctxt *obj.Link, p *obj.Prog, framesize int32, noctxt int) *obj.Prog {
+	// MOV	g_stackguard(g), R1
+	p = obj.Appendp(ctxt, p)
+
+	p.As = AMOVD
+	p.From.Type = obj.TYPE_MEM
+	p.From.Reg = REGG
+	p.From.Offset = 2 * int64(ctxt.Arch.Ptrsize) // G.stackguard0
+	if ctxt.Cursym.Cfunc != 0 {
+		p.From.Offset = 3 * int64(ctxt.Arch.Ptrsize) // G.stackguard1
+	}
+	p.To.Type = obj.TYPE_REG
+	p.To.Reg = REG_R1
+
+	q := (*obj.Prog)(nil)
+	if framesize <= obj.StackSmall {
+		// small stack: SP < stackguard
+		//	MOV	SP, R2
+		//	CMP	stackguard, R2
+		p = obj.Appendp(ctxt, p)
+
+		p.As = AMOVD
+		p.From.Type = obj.TYPE_REG
+		p.From.Reg = REGSP
+		p.To.Type = obj.TYPE_REG
+		p.To.Reg = REG_R2
+
+		p = obj.Appendp(ctxt, p)
+		p.As = ACMP
+		p.From.Type = obj.TYPE_REG
+		p.From.Reg = REG_R1
+		p.Reg = REG_R2
+	} else if framesize <= obj.StackBig {
+		// large stack: SP-framesize < stackguard-StackSmall
+		//	SUB	$framesize, SP, R2
+		//	CMP	stackguard, R2
+		p = obj.Appendp(ctxt, p)
+
+		p.As = ASUB
+		p.From.Type = obj.TYPE_CONST
+		p.From.Offset = int64(framesize)
+		p.Reg = REGSP
+		p.To.Type = obj.TYPE_REG
+		p.To.Reg = REG_R2
+
+		p = obj.Appendp(ctxt, p)
+		p.As = ACMP
+		p.From.Type = obj.TYPE_REG
+		p.From.Reg = REG_R1
+		p.Reg = REG_R2
+	} else {
+		// Such a large stack we need to protect against wraparound
+		// if SP is close to zero.
+		//	SP-stackguard+StackGuard < framesize + (StackGuard-StackSmall)
+		// The +StackGuard on both sides is required to keep the left side positive:
+		// SP is allowed to be slightly below stackguard. See stack.h.
+		//	CMP	$StackPreempt, R1
+		//	BEQ	label_of_call_to_morestack
+		//	ADD	$StackGuard, SP, R2
+		//	SUB	R1, R2
+		//	MOV	$(framesize+(StackGuard-StackSmall)), R3
+		//	CMP	R3, R2
+		p = obj.Appendp(ctxt, p)
+
+		p.As = ACMP
+		p.From.Type = obj.TYPE_CONST
+		p.From.Offset = obj.StackPreempt
+		p.Reg = REG_R1
+
+		p = obj.Appendp(ctxt, p)
+		q = p
+		p.As = ABEQ
+		p.To.Type = obj.TYPE_BRANCH
+
+		p = obj.Appendp(ctxt, p)
+		p.As = AADD
+		p.From.Type = obj.TYPE_CONST
+		p.From.Offset = obj.StackGuard
+		p.Reg = REGSP
+		p.To.Type = obj.TYPE_REG
+		p.To.Reg = REG_R2
+
+		p = obj.Appendp(ctxt, p)
+		p.As = ASUB
+		p.From.Type = obj.TYPE_REG
+		p.From.Reg = REG_R1
+		p.To.Type = obj.TYPE_REG
+		p.To.Reg = REG_R2
+
+		p = obj.Appendp(ctxt, p)
+		p.As = AMOVD
+		p.From.Type = obj.TYPE_CONST
+		p.From.Offset = int64(framesize) + (obj.StackGuard - obj.StackSmall)
+		p.To.Type = obj.TYPE_REG
+		p.To.Reg = REG_R3
+
+		p = obj.Appendp(ctxt, p)
+		p.As = ACMP
+		p.From.Type = obj.TYPE_REG
+		p.From.Reg = REG_R3
+		p.Reg = REG_R2
+	}
+
+	// BHI	done
+	p = obj.Appendp(ctxt, p)
+	q1 := p
+
+	p.As = ABHI
+	p.To.Type = obj.TYPE_BRANCH
+
+	// MOV	LR, R3
+	p = obj.Appendp(ctxt, p)
+
+	p.As = AMOVD
+	p.From.Type = obj.TYPE_REG
+	p.From.Reg = REGLINK
+	p.To.Type = obj.TYPE_REG
+	p.To.Reg = REG_R3
+	if q != nil {
+		q.Pcond = p
+	}
+
+	// TODO(minux): only for debug
+	p = obj.Appendp(ctxt, p)
+	p.As = AMOVD
+	p.From.Type = obj.TYPE_CONST
+	p.From.Offset = int64(framesize)
+	p.To.Type = obj.TYPE_REG
+	p.To.Reg = REGTMP
+
+	// BL	runtime.morestack(SB)
+	p = obj.Appendp(ctxt, p)
+
+	p.As = ABL
+	p.To.Type = obj.TYPE_BRANCH
+	if ctxt.Cursym.Cfunc != 0 {
+		p.To.Sym = obj.Linklookup(ctxt, "runtime.morestackc", 0)
+	} else {
+		p.To.Sym = ctxt.Symmorestack[noctxt]
+	}
+
+	// B	start
+	p = obj.Appendp(ctxt, p)
+
+	p.As = AB
+	p.To.Type = obj.TYPE_BRANCH
+	p.Pcond = ctxt.Cursym.Text.Link
+
+	// placeholder for q1's jump target
+	p = obj.Appendp(ctxt, p)
+
+	p.As = obj.ANOP
+	q1.Pcond = p
+
+	return p
+}
+
+func progedit(ctxt *obj.Link, p *obj.Prog) {
+	p.From.Class = 0
+	p.To.Class = 0
+
+	// $0 results in C_ZCON, which matches both C_REG and various
+	// C_xCON, however the C_REG cases in asmout don't expect a
+	// constant, so they will use the register fields and assemble
+	// a R0. To prevent that, rewrite $0 as ZR.
+	if p.From.Type == obj.TYPE_CONST && p.From.Offset == 0 {
+		p.From.Type = obj.TYPE_REG
+		p.From.Reg = REGZERO
+	}
+	if p.To.Type == obj.TYPE_CONST && p.To.Offset == 0 {
+		p.To.Type = obj.TYPE_REG
+		p.To.Reg = REGZERO
+	}
+
+	// Rewrite BR/BL to symbol as TYPE_BRANCH.
+	switch p.As {
+	case AB,
+		ABL,
+		obj.ARET,
+		obj.ADUFFZERO,
+		obj.ADUFFCOPY:
+		if p.To.Sym != nil {
+			p.To.Type = obj.TYPE_BRANCH
+		}
+		break
+	}
+
+	// Rewrite float constants to values stored in memory.
+	switch p.As {
+	case AFMOVS:
+		if p.From.Type == obj.TYPE_FCONST {
+			f32 := float32(p.From.Val.(float64))
+			i32 := math.Float32bits(f32)
+			literal := fmt.Sprintf("$f32.%08x", uint32(i32))
+			s := obj.Linklookup(ctxt, literal, 0)
+			s.Size = 4
+			p.From.Type = obj.TYPE_MEM
+			p.From.Sym = s
+			p.From.Name = obj.NAME_EXTERN
+			p.From.Offset = 0
+		}
+
+	case AFMOVD:
+		if p.From.Type == obj.TYPE_FCONST {
+			i64 := math.Float64bits(p.From.Val.(float64))
+			literal := fmt.Sprintf("$f64.%016x", uint64(i64))
+			s := obj.Linklookup(ctxt, literal, 0)
+			s.Size = 8
+			p.From.Type = obj.TYPE_MEM
+			p.From.Sym = s
+			p.From.Name = obj.NAME_EXTERN
+			p.From.Offset = 0
+		}
+
+		break
+	}
+
+	// Rewrite negative immediates as positive immediates with
+	// complementary instruction.
+	switch p.As {
+	case AADD,
+		AADDW,
+		ASUB,
+		ASUBW,
+		ACMP,
+		ACMPW,
+		ACMN,
+		ACMNW:
+		if p.From.Type == obj.NAME_EXTERN && p.From.Offset < 0 {
+			p.From.Offset = -p.From.Offset
+			p.As = complements[p.As]
+		}
+
+		break
+	}
+}
+
+func follow(ctxt *obj.Link, s *obj.LSym) {
+	ctxt.Cursym = s
+
+	firstp := ctxt.NewProg()
+	lastp := firstp
+	xfol(ctxt, s.Text, &lastp)
+	lastp.Link = nil
+	s.Text = firstp.Link
+}
+
+func relinv(a int) int {
+	switch a {
+	case ABEQ:
+		return ABNE
+	case ABNE:
+		return ABEQ
+	case ABCS:
+		return ABCC
+	case ABHS:
+		return ABLO
+	case ABCC:
+		return ABCS
+	case ABLO:
+		return ABHS
+	case ABMI:
+		return ABPL
+	case ABPL:
+		return ABMI
+	case ABVS:
+		return ABVC
+	case ABVC:
+		return ABVS
+	case ABHI:
+		return ABLS
+	case ABLS:
+		return ABHI
+	case ABGE:
+		return ABLT
+	case ABLT:
+		return ABGE
+	case ABGT:
+		return ABLE
+	case ABLE:
+		return ABGT
+	}
+
+	log.Fatalf("unknown relation: %s", Anames[a])
+	return 0
+}
+
+func xfol(ctxt *obj.Link, p *obj.Prog, last **obj.Prog) {
+	var q *obj.Prog
+	var r *obj.Prog
+	var a int
+	var i int
+
+loop:
+	if p == nil {
+		return
+	}
+	a = int(p.As)
+	if a == AB {
+		q = p.Pcond
+		if q != nil {
+			p.Mark |= FOLL
+			p = q
+			if !(p.Mark&FOLL != 0) {
+				goto loop
+			}
+		}
+	}
+
+	if p.Mark&FOLL != 0 {
+		i = 0
+		q = p
+		for ; i < 4; i, q = i+1, q.Link {
+			if q == *last || q == nil {
+				break
+			}
+			a = int(q.As)
+			if a == obj.ANOP {
+				i--
+				continue
+			}
+
+			if a == AB || a == obj.ARET || a == AERET {
+				goto copy
+			}
+			if q.Pcond == nil || (q.Pcond.Mark&FOLL != 0) {
+				continue
+			}
+			if a != ABEQ && a != ABNE {
+				continue
+			}
+
+		copy:
+			for {
+				r = ctxt.NewProg()
+				*r = *p
+				if !(r.Mark&FOLL != 0) {
+					fmt.Printf("cant happen 1\n")
+				}
+				r.Mark |= FOLL
+				if p != q {
+					p = p.Link
+					(*last).Link = r
+					*last = r
+					continue
+				}
+
+				(*last).Link = r
+				*last = r
+				if a == AB || a == obj.ARET || a == AERET {
+					return
+				}
+				if a == ABNE {
+					r.As = ABEQ
+				} else {
+					r.As = ABNE
+				}
+				r.Pcond = p.Link
+				r.Link = p.Pcond
+				if !(r.Link.Mark&FOLL != 0) {
+					xfol(ctxt, r.Link, last)
+				}
+				if !(r.Pcond.Mark&FOLL != 0) {
+					fmt.Printf("cant happen 2\n")
+				}
+				return
+			}
+		}
+
+		a = AB
+		q = ctxt.NewProg()
+		q.As = int16(a)
+		q.Lineno = p.Lineno
+		q.To.Type = obj.TYPE_BRANCH
+		q.To.Offset = p.Pc
+		q.Pcond = p
+		p = q
+	}
+
+	p.Mark |= FOLL
+	(*last).Link = p
+	*last = p
+	if a == AB || a == obj.ARET || a == AERET {
+		return
+	}
+	if p.Pcond != nil {
+		if a != ABL && p.Link != nil {
+			q = obj.Brchain(ctxt, p.Link)
+			if a != obj.ATEXT && a != ABCASE {
+				if q != nil && (q.Mark&FOLL != 0) {
+					p.As = int16(relinv(a))
+					p.Link = p.Pcond
+					p.Pcond = q
+				}
+			}
+
+			xfol(ctxt, p.Link, last)
+			q = obj.Brchain(ctxt, p.Pcond)
+			if q == nil {
+				q = p.Pcond
+			}
+			if q.Mark&FOLL != 0 {
+				p.Pcond = q
+				return
+			}
+
+			p = q
+			goto loop
+		}
+	}
+
+	p = p.Link
+	goto loop
+}
+
+func preprocess(ctxt *obj.Link, cursym *obj.LSym) {
+	if ctxt.Symmorestack[0] == nil {
+		ctxt.Symmorestack[0] = obj.Linklookup(ctxt, "runtime.morestack", 0)
+		ctxt.Symmorestack[1] = obj.Linklookup(ctxt, "runtime.morestack_noctxt", 0)
+	}
+
+	ctxt.Cursym = cursym
+
+	if cursym.Text == nil || cursym.Text.Link == nil {
+		return
+	}
+
+	p := cursym.Text
+	textstksiz := p.To.Offset
+	aoffset := int32(textstksiz)
+
+	cursym.Args = p.To.Val.(int32)
+	cursym.Locals = int32(textstksiz)
+
+	/*
+	 * find leaf subroutines
+	 * strip NOPs
+	 * expand RET
+	 */
+	obj.Bflush(ctxt.Bso)
+	q := (*obj.Prog)(nil)
+	var q1 *obj.Prog
+	for p := cursym.Text; p != nil; p = p.Link {
+		switch p.As {
+		case obj.ATEXT:
+			p.Mark |= LEAF
+
+		case obj.ARET:
+			break
+
+		case obj.ANOP:
+			q1 = p.Link
+			q.Link = q1 /* q is non-nop */
+			q1.Mark |= p.Mark
+			continue
+
+		case ABL,
+			obj.ADUFFZERO,
+			obj.ADUFFCOPY:
+			cursym.Text.Mark &^= LEAF
+			fallthrough
+
+		case ACBNZ,
+			ACBZ,
+			ACBNZW,
+			ACBZW,
+			ATBZ,
+			ATBNZ,
+			ABCASE,
+			AB,
+			ABEQ,
+			ABNE,
+			ABCS,
+			ABHS,
+			ABCC,
+			ABLO,
+			ABMI,
+			ABPL,
+			ABVS,
+			ABVC,
+			ABHI,
+			ABLS,
+			ABGE,
+			ABLT,
+			ABGT,
+			ABLE,
+			AADR, /* strange */
+			AADRP:
+			q1 = p.Pcond
+
+			if q1 != nil {
+				for q1.As == obj.ANOP {
+					q1 = q1.Link
+					p.Pcond = q1
+				}
+			}
+
+			break
+		}
+
+		q = p
+	}
+
+	var o int
+	var q2 *obj.Prog
+	var retjmp *obj.LSym
+	var stkadj int64
+	for p := cursym.Text; p != nil; p = p.Link {
+		o = int(p.As)
+		switch o {
+		case obj.ATEXT:
+			cursym.Text = p
+			if textstksiz < 0 {
+				ctxt.Autosize = 0
+			} else {
+				ctxt.Autosize = int32(textstksiz + 8)
+			}
+			if (cursym.Text.Mark&LEAF != 0) && ctxt.Autosize <= 8 {
+				ctxt.Autosize = 0
+			} else if ctxt.Autosize&(16-1) != 0 {
+				stkadj = 16 - (int64(ctxt.Autosize) & (16 - 1))
+				ctxt.Autosize += int32(stkadj)
+				cursym.Locals += int32(stkadj)
+			}
+			p.To.Offset = int64(ctxt.Autosize) - 8
+			if ctxt.Autosize == 0 && !(cursym.Text.Mark&LEAF != 0) {
+				if ctxt.Debugvlog != 0 {
+					fmt.Fprintf(ctxt.Bso, "save suppressed in: %s\n", cursym.Text.From.Sym.Name)
+				}
+				obj.Bflush(ctxt.Bso)
+				cursym.Text.Mark |= LEAF
+			}
+
+			if !(p.From3.Offset&obj.NOSPLIT != 0) {
+				p = stacksplit(ctxt, p, ctxt.Autosize, bool2int(cursym.Text.From3.Offset&obj.NEEDCTXT == 0)) // emit split check
+			}
+
+			aoffset = ctxt.Autosize
+			if aoffset > 0xF0 {
+				aoffset = 0xF0
+			}
+			if cursym.Text.Mark&LEAF != 0 {
+				cursym.Leaf = 1
+				if ctxt.Autosize == 0 {
+					break
+				}
+				aoffset = 0
+			}
+
+			q = p
+			if ctxt.Autosize > aoffset {
+				q = ctxt.NewProg()
+				q.As = ASUB
+				q.Lineno = p.Lineno
+				q.From.Type = obj.TYPE_CONST
+				q.From.Offset = int64(ctxt.Autosize) - int64(aoffset)
+				q.To.Type = obj.TYPE_REG
+				q.To.Reg = REGSP
+				q.Spadj = int32(q.From.Offset)
+				q.Link = p.Link
+				p.Link = q
+				if cursym.Text.Mark&LEAF != 0 {
+					break
+				}
+			}
+
+			q1 = ctxt.NewProg()
+			q1.As = AMOVD
+			q1.Lineno = p.Lineno
+			q1.From.Type = obj.TYPE_REG
+			q1.From.Reg = REGLINK
+			q1.To.Type = obj.TYPE_MEM
+			q1.Scond = C_XPRE
+			q1.To.Offset = int64(-aoffset)
+			q1.To.Reg = REGSP
+			q1.Link = q.Link
+			q1.Spadj = aoffset
+			q.Link = q1
+
+			if cursym.Text.From3.Offset&obj.WRAPPER != 0 {
+				// if(g->panic != nil && g->panic->argp == FP) g->panic->argp = bottom-of-frame
+				//
+				//	MOV g_panic(g), R1
+				//	CMP ZR, R1
+				//	BEQ end
+				//	MOV panic_argp(R1), R2
+				//	ADD $(autosize+8), RSP, R3
+				//	CMP R2, R3
+				//	BNE end
+				//	ADD $8, RSP, R4
+				//	MOVD R4, panic_argp(R1)
+				// end:
+				//	NOP
+				//
+				// The NOP is needed to give the jumps somewhere to land.
+				// It is a liblink NOP, not a ARM64 NOP: it encodes to 0 instruction bytes.
+				q = q1
+
+				q = obj.Appendp(ctxt, q)
+				q.As = AMOVD
+				q.From.Type = obj.TYPE_MEM
+				q.From.Reg = REGG
+				q.From.Offset = 4 * int64(ctxt.Arch.Ptrsize) // G.panic
+				q.To.Type = obj.TYPE_REG
+				q.To.Reg = REG_R1
+
+				q = obj.Appendp(ctxt, q)
+				q.As = ACMP
+				q.From.Type = obj.TYPE_REG
+				q.From.Reg = REGZERO
+				q.Reg = REG_R1
+
+				q = obj.Appendp(ctxt, q)
+				q.As = ABEQ
+				q.To.Type = obj.TYPE_BRANCH
+				q1 = q
+
+				q = obj.Appendp(ctxt, q)
+				q.As = AMOVD
+				q.From.Type = obj.TYPE_MEM
+				q.From.Reg = REG_R1
+				q.From.Offset = 0 // Panic.argp
+				q.To.Type = obj.TYPE_REG
+				q.To.Reg = REG_R2
+
+				q = obj.Appendp(ctxt, q)
+				q.As = AADD
+				q.From.Type = obj.TYPE_CONST
+				q.From.Offset = int64(ctxt.Autosize) + 8
+				q.Reg = REGSP
+				q.To.Type = obj.TYPE_REG
+				q.To.Reg = REG_R3
+
+				q = obj.Appendp(ctxt, q)
+				q.As = ACMP
+				q.From.Type = obj.TYPE_REG
+				q.From.Reg = REG_R2
+				q.Reg = REG_R3
+
+				q = obj.Appendp(ctxt, q)
+				q.As = ABNE
+				q.To.Type = obj.TYPE_BRANCH
+				q2 = q
+
+				q = obj.Appendp(ctxt, q)
+				q.As = AADD
+				q.From.Type = obj.TYPE_CONST
+				q.From.Offset = 8
+				q.Reg = REGSP
+				q.To.Type = obj.TYPE_REG
+				q.To.Reg = REG_R4
+
+				q = obj.Appendp(ctxt, q)
+				q.As = AMOVD
+				q.From.Type = obj.TYPE_REG
+				q.From.Reg = REG_R4
+				q.To.Type = obj.TYPE_MEM
+				q.To.Reg = REG_R1
+				q.To.Offset = 0 // Panic.argp
+
+				q = obj.Appendp(ctxt, q)
+
+				q.As = obj.ANOP
+				q1.Pcond = q
+				q2.Pcond = q
+			}
+
+		case obj.ARET:
+			nocache(p)
+			if p.From.Type == obj.TYPE_CONST {
+				ctxt.Diag("using BECOME (%v) is not supported!", p)
+				break
+			}
+
+			retjmp = p.To.Sym
+			p.To = obj.Addr{}
+			if cursym.Text.Mark&LEAF != 0 {
+				if ctxt.Autosize != 0 {
+					p.As = AADD
+					p.From.Type = obj.TYPE_CONST
+					p.From.Offset = int64(ctxt.Autosize)
+					p.To.Type = obj.TYPE_REG
+					p.To.Reg = REGSP
+					p.Spadj = -ctxt.Autosize
+				}
+			} else {
+				/* want write-back pre-indexed SP+autosize -> SP, loading REGLINK*/
+				aoffset = ctxt.Autosize
+
+				if aoffset > 0xF0 {
+					aoffset = 0xF0
+				}
+				p.As = AMOVD
+				p.From.Type = obj.TYPE_MEM
+				p.Scond = C_XPOST
+				p.From.Offset = int64(aoffset)
+				p.From.Reg = REGSP
+				p.To.Type = obj.TYPE_REG
+				p.To.Reg = REGLINK
+				p.Spadj = -aoffset
+				if ctxt.Autosize > aoffset {
+					q = ctxt.NewProg()
+					q.As = AADD
+					q.From.Type = obj.TYPE_CONST
+					q.From.Offset = int64(ctxt.Autosize) - int64(aoffset)
+					q.To.Type = obj.TYPE_REG
+					q.To.Reg = REGSP
+					q.Link = p.Link
+					q.Spadj = int32(-q.From.Offset)
+					q.Lineno = p.Lineno
+					p.Link = q
+					p = q
+				}
+			}
+
+			if p.As != obj.ARET {
+				q = ctxt.NewProg()
+				q.Lineno = p.Lineno
+				q.Link = p.Link
+				p.Link = q
+				p = q
+			}
+
+			if retjmp != nil { // retjmp
+				p.As = AB
+				p.To.Type = obj.TYPE_BRANCH
+				p.To.Sym = retjmp
+				p.Spadj = +ctxt.Autosize
+				break
+			}
+
+			p.As = obj.ARET
+			p.Lineno = p.Lineno
+			p.To.Type = obj.TYPE_MEM
+			p.To.Offset = 0
+			p.To.Reg = REGLINK
+			p.Spadj = +ctxt.Autosize
+
+		case AADD, ASUB:
+			if p.To.Type == obj.TYPE_REG && p.To.Reg == REGSP && p.From.Type == obj.TYPE_CONST {
+				if p.As == AADD {
+					p.Spadj = int32(-p.From.Offset)
+				} else {
+					p.Spadj = int32(+p.From.Offset)
+				}
+			}
+			break
+		}
+	}
+}
+
+func nocache(p *obj.Prog) {
+	p.Optab = 0
+	p.From.Class = 0
+	p.To.Class = 0
+}
+
+var unaryDst = map[int]bool{
+	AWORD:  true,
+	ADWORD: true,
+	ABL:    true,
+	AB:     true,
+}
+
+var Linkarm64 = obj.LinkArch{
+	ByteOrder:  binary.LittleEndian,
+	Name:       "arm64",
+	Thechar:    '7',
+	Preprocess: preprocess,
+	Assemble:   span7,
+	Follow:     follow,
+	Progedit:   progedit,
+	UnaryDst:   unaryDst,
+	Minlc:      4,
+	Ptrsize:    8,
+	Regsize:    8,
+}
diff --git a/src/cmd/internal/obj/i386/util.go b/src/cmd/internal/obj/arm64/util.go
similarity index 93%
copy from src/cmd/internal/obj/i386/util.go
copy to src/cmd/internal/obj/arm64/util.go
index b3e9643..7cb5040 100644
--- a/src/cmd/internal/obj/i386/util.go
+++ b/src/cmd/internal/obj/arm64/util.go
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-package i386
+package arm64
 
 func bool2int(b bool) int {
 	if b {
diff --git a/src/cmd/internal/obj/data.go b/src/cmd/internal/obj/data.go
index 6321ca4..ab3e209 100644
--- a/src/cmd/internal/obj/data.go
+++ b/src/cmd/internal/obj/data.go
@@ -75,16 +75,16 @@
 			ctxt.Diag("unexpected %d-byte floating point constant", siz)
 
 		case 4:
-			flt := math.Float32bits(float32(p.To.U.Dval))
+			flt := math.Float32bits(float32(p.To.Val.(float64)))
 			ctxt.Arch.ByteOrder.PutUint32(s.P[off:], flt)
 
 		case 8:
-			flt := math.Float64bits(p.To.U.Dval)
+			flt := math.Float64bits(p.To.Val.(float64))
 			ctxt.Arch.ByteOrder.PutUint64(s.P[off:], flt)
 		}
 
 	case TYPE_SCONST:
-		copy(s.P[off:off+siz], p.To.U.Sval)
+		copy(s.P[off:off+siz], p.To.Val.(string))
 
 	case TYPE_CONST, TYPE_ADDR:
 		if p.To.Sym != nil || int(p.To.Type) == TYPE_ADDR {
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/i386/8.out.go b/src/cmd/internal/obj/i386/8.out.go
deleted file mode 100644
index ab58cc1..0000000
--- a/src/cmd/internal/obj/i386/8.out.go
+++ /dev/null
@@ -1,594 +0,0 @@
-// Inferno utils/8c/8.out.h
-// http://code.google.com/p/inferno-os/source/browse/utils/8c/8.out.h
-//
-//	Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
-//	Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
-//	Portions Copyright © 1997-1999 Vita Nuova Limited
-//	Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
-//	Portions Copyright © 2004,2006 Bruce Ellis
-//	Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
-//	Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
-//	Portions Copyright © 2009 The Go Authors.  All rights reserved.
-//
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files (the "Software"), to deal
-// in the Software without restriction, including without limitation the rights
-// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-// copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-// THE SOFTWARE.
-
-package i386
-
-import "cmd/internal/obj"
-
-const (
-	AAAA = obj.A_ARCHSPECIFIC + iota
-	AAAD
-	AAAM
-	AAAS
-	AADCB
-	AADCL
-	AADCW
-	AADDB
-	AADDL
-	AADDW
-	AADJSP
-	AANDB
-	AANDL
-	AANDW
-	AARPL
-	ABOUNDL
-	ABOUNDW
-	ABSFL
-	ABSFW
-	ABSRL
-	ABSRW
-	ABTL
-	ABTW
-	ABTCL
-	ABTCW
-	ABTRL
-	ABTRW
-	ABTSL
-	ABTSW
-	ABYTE
-	ACLC
-	ACLD
-	ACLI
-	ACLTS
-	ACMC
-	ACMPB
-	ACMPL
-	ACMPW
-	ACMPSB
-	ACMPSL
-	ACMPSW
-	ADAA
-	ADAS
-	ADECB
-	ADECL
-	ADECW
-	ADIVB
-	ADIVL
-	ADIVW
-	AENTER
-	AHLT
-	AIDIVB
-	AIDIVL
-	AIDIVW
-	AIMULB
-	AIMULL
-	AIMULW
-	AINB
-	AINL
-	AINW
-	AINCB
-	AINCL
-	AINCW
-	AINSB
-	AINSL
-	AINSW
-	AINT
-	AINTO
-	AIRETL
-	AIRETW
-	AJCC
-	AJCS
-	AJCXZL
-	AJCXZW
-	AJEQ
-	AJGE
-	AJGT
-	AJHI
-	AJLE
-	AJLS
-	AJLT
-	AJMI
-	AJNE
-	AJOC
-	AJOS
-	AJPC
-	AJPL
-	AJPS
-	ALAHF
-	ALARL
-	ALARW
-	ALEAL
-	ALEAW
-	ALEAVEL
-	ALEAVEW
-	ALOCK
-	ALODSB
-	ALODSL
-	ALODSW
-	ALONG
-	ALOOP
-	ALOOPEQ
-	ALOOPNE
-	ALSLL
-	ALSLW
-	AMOVB
-	AMOVL
-	AMOVW
-	AMOVQ
-	AMOVBLSX
-	AMOVBLZX
-	AMOVBWSX
-	AMOVBWZX
-	AMOVWLSX
-	AMOVWLZX
-	AMOVSB
-	AMOVSL
-	AMOVSW
-	AMULB
-	AMULL
-	AMULW
-	ANEGB
-	ANEGL
-	ANEGW
-	ANOTB
-	ANOTL
-	ANOTW
-	AORB
-	AORL
-	AORW
-	AOUTB
-	AOUTL
-	AOUTW
-	AOUTSB
-	AOUTSL
-	AOUTSW
-	APAUSE
-	APOPAL
-	APOPAW
-	APOPFL
-	APOPFW
-	APOPL
-	APOPW
-	APUSHAL
-	APUSHAW
-	APUSHFL
-	APUSHFW
-	APUSHL
-	APUSHW
-	ARCLB
-	ARCLL
-	ARCLW
-	ARCRB
-	ARCRL
-	ARCRW
-	AREP
-	AREPN
-	AROLB
-	AROLL
-	AROLW
-	ARORB
-	ARORL
-	ARORW
-	ASAHF
-	ASALB
-	ASALL
-	ASALW
-	ASARB
-	ASARL
-	ASARW
-	ASBBB
-	ASBBL
-	ASBBW
-	ASCASB
-	ASCASL
-	ASCASW
-	ASETCC
-	ASETCS
-	ASETEQ
-	ASETGE
-	ASETGT
-	ASETHI
-	ASETLE
-	ASETLS
-	ASETLT
-	ASETMI
-	ASETNE
-	ASETOC
-	ASETOS
-	ASETPC
-	ASETPL
-	ASETPS
-	ACDQ
-	ACWD
-	ASHLB
-	ASHLL
-	ASHLW
-	ASHRB
-	ASHRL
-	ASHRW
-	ASTC
-	ASTD
-	ASTI
-	ASTOSB
-	ASTOSL
-	ASTOSW
-	ASUBB
-	ASUBL
-	ASUBW
-	ASYSCALL
-	ATESTB
-	ATESTL
-	ATESTW
-	AVERR
-	AVERW
-	AWAIT
-	AWORD
-	AXCHGB
-	AXCHGL
-	AXCHGW
-	AXLAT
-	AXORB
-	AXORL
-	AXORW
-	AFMOVB
-	AFMOVBP
-	AFMOVD
-	AFMOVDP
-	AFMOVF
-	AFMOVFP
-	AFMOVL
-	AFMOVLP
-	AFMOVV
-	AFMOVVP
-	AFMOVW
-	AFMOVWP
-	AFMOVX
-	AFMOVXP
-	AFCOMB
-	AFCOMBP
-	AFCOMD
-	AFCOMDP
-	AFCOMDPP
-	AFCOMF
-	AFCOMFP
-	AFCOMI
-	AFCOMIP
-	AFCOML
-	AFCOMLP
-	AFCOMW
-	AFCOMWP
-	AFUCOM
-	AFUCOMI
-	AFUCOMIP
-	AFUCOMP
-	AFUCOMPP
-	AFADDDP
-	AFADDW
-	AFADDL
-	AFADDF
-	AFADDD
-	AFMULDP
-	AFMULW
-	AFMULL
-	AFMULF
-	AFMULD
-	AFSUBDP
-	AFSUBW
-	AFSUBL
-	AFSUBF
-	AFSUBD
-	AFSUBRDP
-	AFSUBRW
-	AFSUBRL
-	AFSUBRF
-	AFSUBRD
-	AFDIVDP
-	AFDIVW
-	AFDIVL
-	AFDIVF
-	AFDIVD
-	AFDIVRDP
-	AFDIVRW
-	AFDIVRL
-	AFDIVRF
-	AFDIVRD
-	AFXCHD
-	AFFREE
-	AFLDCW
-	AFLDENV
-	AFRSTOR
-	AFSAVE
-	AFSTCW
-	AFSTENV
-	AFSTSW
-	AF2XM1
-	AFABS
-	AFCHS
-	AFCLEX
-	AFCOS
-	AFDECSTP
-	AFINCSTP
-	AFINIT
-	AFLD1
-	AFLDL2E
-	AFLDL2T
-	AFLDLG2
-	AFLDLN2
-	AFLDPI
-	AFLDZ
-	AFNOP
-	AFPATAN
-	AFPREM
-	AFPREM1
-	AFPTAN
-	AFRNDINT
-	AFSCALE
-	AFSIN
-	AFSINCOS
-	AFSQRT
-	AFTST
-	AFXAM
-	AFXTRACT
-	AFYL2X
-	AFYL2XP1
-	ACMPXCHGB
-	ACMPXCHGL
-	ACMPXCHGW
-	ACMPXCHG8B
-	ACPUID
-	ARDTSC
-	AXADDB
-	AXADDL
-	AXADDW
-	ACMOVLCC
-	ACMOVLCS
-	ACMOVLEQ
-	ACMOVLGE
-	ACMOVLGT
-	ACMOVLHI
-	ACMOVLLE
-	ACMOVLLS
-	ACMOVLLT
-	ACMOVLMI
-	ACMOVLNE
-	ACMOVLOC
-	ACMOVLOS
-	ACMOVLPC
-	ACMOVLPL
-	ACMOVLPS
-	ACMOVWCC
-	ACMOVWCS
-	ACMOVWEQ
-	ACMOVWGE
-	ACMOVWGT
-	ACMOVWHI
-	ACMOVWLE
-	ACMOVWLS
-	ACMOVWLT
-	ACMOVWMI
-	ACMOVWNE
-	ACMOVWOC
-	ACMOVWOS
-	ACMOVWPC
-	ACMOVWPL
-	ACMOVWPS
-	AFCMOVCC
-	AFCMOVCS
-	AFCMOVEQ
-	AFCMOVHI
-	AFCMOVLS
-	AFCMOVNE
-	AFCMOVNU
-	AFCMOVUN
-	ALFENCE
-	AMFENCE
-	ASFENCE
-	AEMMS
-	APREFETCHT0
-	APREFETCHT1
-	APREFETCHT2
-	APREFETCHNTA
-	ABSWAPL
-	AADDPD
-	AADDPS
-	AADDSD
-	AADDSS
-	AANDNPD
-	AANDNPS
-	AANDPD
-	AANDPS
-	ACMPPD
-	ACMPPS
-	ACMPSD
-	ACMPSS
-	ACOMISD
-	ACOMISS
-	ACVTPL2PD
-	ACVTPL2PS
-	ACVTPD2PL
-	ACVTPD2PS
-	ACVTPS2PL
-	ACVTPS2PD
-	ACVTSD2SL
-	ACVTSD2SS
-	ACVTSL2SD
-	ACVTSL2SS
-	ACVTSS2SD
-	ACVTSS2SL
-	ACVTTPD2PL
-	ACVTTPS2PL
-	ACVTTSD2SL
-	ACVTTSS2SL
-	ADIVPD
-	ADIVPS
-	ADIVSD
-	ADIVSS
-	AMASKMOVOU
-	AMAXPD
-	AMAXPS
-	AMAXSD
-	AMAXSS
-	AMINPD
-	AMINPS
-	AMINSD
-	AMINSS
-	AMOVAPD
-	AMOVAPS
-	AMOVO
-	AMOVOU
-	AMOVHLPS
-	AMOVHPD
-	AMOVHPS
-	AMOVLHPS
-	AMOVLPD
-	AMOVLPS
-	AMOVMSKPD
-	AMOVMSKPS
-	AMOVNTO
-	AMOVNTPD
-	AMOVNTPS
-	AMOVSD
-	AMOVSS
-	AMOVUPD
-	AMOVUPS
-	AMULPD
-	AMULPS
-	AMULSD
-	AMULSS
-	AORPD
-	AORPS
-	APADDQ
-	APAND
-	APCMPEQB
-	APMAXSW
-	APMAXUB
-	APMINSW
-	APMINUB
-	APMOVMSKB
-	APSADBW
-	APSUBB
-	APSUBL
-	APSUBQ
-	APSUBSB
-	APSUBSW
-	APSUBUSB
-	APSUBUSW
-	APSUBW
-	APUNPCKHQDQ
-	APUNPCKLQDQ
-	APXOR
-	ARCPPS
-	ARCPSS
-	ARSQRTPS
-	ARSQRTSS
-	ASQRTPD
-	ASQRTPS
-	ASQRTSD
-	ASQRTSS
-	ASUBPD
-	ASUBPS
-	ASUBSD
-	ASUBSS
-	AUCOMISD
-	AUCOMISS
-	AUNPCKHPD
-	AUNPCKHPS
-	AUNPCKLPD
-	AUNPCKLPS
-	AXORPD
-	AXORPS
-	APSHUFHW
-	APSHUFL
-	APSHUFLW
-	AAESENC
-	APINSRD
-	APSHUFB
-	ALAST
-)
-
-const (
-	REG_NONE = 0
-	REG_AL   = obj.RBase386 + 0 + iota - 1
-	REG_CL
-	REG_DL
-	REG_BL
-	REG_AH = obj.RBase386 + 4 + iota - 5
-	REG_CH
-	REG_DH
-	REG_BH
-	REG_AX = obj.RBase386 + 8 + iota - 9
-	REG_CX
-	REG_DX
-	REG_BX
-	REG_SP
-	REG_BP
-	REG_SI
-	REG_DI
-	REG_F0 = obj.RBase386 + 16
-	REG_F7 = obj.RBase386 + REG_F0 + 7
-	REG_CS = obj.RBase386 + 24 + iota - 19
-	REG_SS
-	REG_DS
-	REG_ES
-	REG_FS
-	REG_GS
-	REG_GDTR
-	REG_IDTR
-	REG_LDTR
-	REG_MSW
-	REG_TASK
-	REG_CR = obj.RBase386 + 35
-	REG_DR = obj.RBase386 + 43
-	REG_TR = obj.RBase386 + 51
-	REG_X0 = obj.RBase386 + 59 + iota - 33
-	REG_X1
-	REG_X2
-	REG_X3
-	REG_X4
-	REG_X5
-	REG_X6
-	REG_X7
-	REG_TLS   = obj.RBase386 + 67
-	MAXREG    = obj.RBase386 + 68
-	T_TYPE    = 1 << 0
-	T_INDEX   = 1 << 1
-	T_OFFSET  = 1 << 2
-	T_FCONST  = 1 << 3
-	T_SYM     = 1 << 4
-	T_SCONST  = 1 << 5
-	T_OFFSET2 = 1 << 6
-	T_GOTYPE  = 1 << 7
-	REGARG    = -1
-	REGRET    = REG_AX
-	FREGRET   = REG_F0
-	REGSP     = REG_SP
-	REGTMP    = REG_DI
-	REGCTXT   = REG_DX
-)
diff --git a/src/cmd/internal/obj/i386/anames8.go b/src/cmd/internal/obj/i386/anames8.go
deleted file mode 100644
index ebf2e5e..0000000
--- a/src/cmd/internal/obj/i386/anames8.go
+++ /dev/null
@@ -1,524 +0,0 @@
-package i386
-
-/*
- * this is the ranlib header
- */
-var Anames = []string{
-	"XXX",
-	"CALL",
-	"CHECKNIL",
-	"DATA",
-	"DUFFCOPY",
-	"DUFFZERO",
-	"END",
-	"FUNCDATA",
-	"GLOBL",
-	"JMP",
-	"NOP",
-	"PCDATA",
-	"RET",
-	"TEXT",
-	"TYPE",
-	"UNDEF",
-	"USEFIELD",
-	"VARDEF",
-	"VARKILL",
-	"AAA",
-	"AAD",
-	"AAM",
-	"AAS",
-	"ADCB",
-	"ADCL",
-	"ADCW",
-	"ADDB",
-	"ADDL",
-	"ADDW",
-	"ADJSP",
-	"ANDB",
-	"ANDL",
-	"ANDW",
-	"ARPL",
-	"BOUNDL",
-	"BOUNDW",
-	"BSFL",
-	"BSFW",
-	"BSRL",
-	"BSRW",
-	"BTL",
-	"BTW",
-	"BTCL",
-	"BTCW",
-	"BTRL",
-	"BTRW",
-	"BTSL",
-	"BTSW",
-	"BYTE",
-	"CLC",
-	"CLD",
-	"CLI",
-	"CLTS",
-	"CMC",
-	"CMPB",
-	"CMPL",
-	"CMPW",
-	"CMPSB",
-	"CMPSL",
-	"CMPSW",
-	"DAA",
-	"DAS",
-	"DECB",
-	"DECL",
-	"DECW",
-	"DIVB",
-	"DIVL",
-	"DIVW",
-	"ENTER",
-	"HLT",
-	"IDIVB",
-	"IDIVL",
-	"IDIVW",
-	"IMULB",
-	"IMULL",
-	"IMULW",
-	"INB",
-	"INL",
-	"INW",
-	"INCB",
-	"INCL",
-	"INCW",
-	"INSB",
-	"INSL",
-	"INSW",
-	"INT",
-	"INTO",
-	"IRETL",
-	"IRETW",
-	"JCC",
-	"JCS",
-	"JCXZL",
-	"JCXZW",
-	"JEQ",
-	"JGE",
-	"JGT",
-	"JHI",
-	"JLE",
-	"JLS",
-	"JLT",
-	"JMI",
-	"JNE",
-	"JOC",
-	"JOS",
-	"JPC",
-	"JPL",
-	"JPS",
-	"LAHF",
-	"LARL",
-	"LARW",
-	"LEAL",
-	"LEAW",
-	"LEAVEL",
-	"LEAVEW",
-	"LOCK",
-	"LODSB",
-	"LODSL",
-	"LODSW",
-	"LONG",
-	"LOOP",
-	"LOOPEQ",
-	"LOOPNE",
-	"LSLL",
-	"LSLW",
-	"MOVB",
-	"MOVL",
-	"MOVW",
-	"MOVQ",
-	"MOVBLSX",
-	"MOVBLZX",
-	"MOVBWSX",
-	"MOVBWZX",
-	"MOVWLSX",
-	"MOVWLZX",
-	"MOVSB",
-	"MOVSL",
-	"MOVSW",
-	"MULB",
-	"MULL",
-	"MULW",
-	"NEGB",
-	"NEGL",
-	"NEGW",
-	"NOTB",
-	"NOTL",
-	"NOTW",
-	"ORB",
-	"ORL",
-	"ORW",
-	"OUTB",
-	"OUTL",
-	"OUTW",
-	"OUTSB",
-	"OUTSL",
-	"OUTSW",
-	"PAUSE",
-	"POPAL",
-	"POPAW",
-	"POPFL",
-	"POPFW",
-	"POPL",
-	"POPW",
-	"PUSHAL",
-	"PUSHAW",
-	"PUSHFL",
-	"PUSHFW",
-	"PUSHL",
-	"PUSHW",
-	"RCLB",
-	"RCLL",
-	"RCLW",
-	"RCRB",
-	"RCRL",
-	"RCRW",
-	"REP",
-	"REPN",
-	"ROLB",
-	"ROLL",
-	"ROLW",
-	"RORB",
-	"RORL",
-	"RORW",
-	"SAHF",
-	"SALB",
-	"SALL",
-	"SALW",
-	"SARB",
-	"SARL",
-	"SARW",
-	"SBBB",
-	"SBBL",
-	"SBBW",
-	"SCASB",
-	"SCASL",
-	"SCASW",
-	"SETCC",
-	"SETCS",
-	"SETEQ",
-	"SETGE",
-	"SETGT",
-	"SETHI",
-	"SETLE",
-	"SETLS",
-	"SETLT",
-	"SETMI",
-	"SETNE",
-	"SETOC",
-	"SETOS",
-	"SETPC",
-	"SETPL",
-	"SETPS",
-	"CDQ",
-	"CWD",
-	"SHLB",
-	"SHLL",
-	"SHLW",
-	"SHRB",
-	"SHRL",
-	"SHRW",
-	"STC",
-	"STD",
-	"STI",
-	"STOSB",
-	"STOSL",
-	"STOSW",
-	"SUBB",
-	"SUBL",
-	"SUBW",
-	"SYSCALL",
-	"TESTB",
-	"TESTL",
-	"TESTW",
-	"VERR",
-	"VERW",
-	"WAIT",
-	"WORD",
-	"XCHGB",
-	"XCHGL",
-	"XCHGW",
-	"XLAT",
-	"XORB",
-	"XORL",
-	"XORW",
-	"FMOVB",
-	"FMOVBP",
-	"FMOVD",
-	"FMOVDP",
-	"FMOVF",
-	"FMOVFP",
-	"FMOVL",
-	"FMOVLP",
-	"FMOVV",
-	"FMOVVP",
-	"FMOVW",
-	"FMOVWP",
-	"FMOVX",
-	"FMOVXP",
-	"FCOMB",
-	"FCOMBP",
-	"FCOMD",
-	"FCOMDP",
-	"FCOMDPP",
-	"FCOMF",
-	"FCOMFP",
-	"FCOMI",
-	"FCOMIP",
-	"FCOML",
-	"FCOMLP",
-	"FCOMW",
-	"FCOMWP",
-	"FUCOM",
-	"FUCOMI",
-	"FUCOMIP",
-	"FUCOMP",
-	"FUCOMPP",
-	"FADDDP",
-	"FADDW",
-	"FADDL",
-	"FADDF",
-	"FADDD",
-	"FMULDP",
-	"FMULW",
-	"FMULL",
-	"FMULF",
-	"FMULD",
-	"FSUBDP",
-	"FSUBW",
-	"FSUBL",
-	"FSUBF",
-	"FSUBD",
-	"FSUBRDP",
-	"FSUBRW",
-	"FSUBRL",
-	"FSUBRF",
-	"FSUBRD",
-	"FDIVDP",
-	"FDIVW",
-	"FDIVL",
-	"FDIVF",
-	"FDIVD",
-	"FDIVRDP",
-	"FDIVRW",
-	"FDIVRL",
-	"FDIVRF",
-	"FDIVRD",
-	"FXCHD",
-	"FFREE",
-	"FLDCW",
-	"FLDENV",
-	"FRSTOR",
-	"FSAVE",
-	"FSTCW",
-	"FSTENV",
-	"FSTSW",
-	"F2XM1",
-	"FABS",
-	"FCHS",
-	"FCLEX",
-	"FCOS",
-	"FDECSTP",
-	"FINCSTP",
-	"FINIT",
-	"FLD1",
-	"FLDL2E",
-	"FLDL2T",
-	"FLDLG2",
-	"FLDLN2",
-	"FLDPI",
-	"FLDZ",
-	"FNOP",
-	"FPATAN",
-	"FPREM",
-	"FPREM1",
-	"FPTAN",
-	"FRNDINT",
-	"FSCALE",
-	"FSIN",
-	"FSINCOS",
-	"FSQRT",
-	"FTST",
-	"FXAM",
-	"FXTRACT",
-	"FYL2X",
-	"FYL2XP1",
-	"CMPXCHGB",
-	"CMPXCHGL",
-	"CMPXCHGW",
-	"CMPXCHG8B",
-	"CPUID",
-	"RDTSC",
-	"XADDB",
-	"XADDL",
-	"XADDW",
-	"CMOVLCC",
-	"CMOVLCS",
-	"CMOVLEQ",
-	"CMOVLGE",
-	"CMOVLGT",
-	"CMOVLHI",
-	"CMOVLLE",
-	"CMOVLLS",
-	"CMOVLLT",
-	"CMOVLMI",
-	"CMOVLNE",
-	"CMOVLOC",
-	"CMOVLOS",
-	"CMOVLPC",
-	"CMOVLPL",
-	"CMOVLPS",
-	"CMOVWCC",
-	"CMOVWCS",
-	"CMOVWEQ",
-	"CMOVWGE",
-	"CMOVWGT",
-	"CMOVWHI",
-	"CMOVWLE",
-	"CMOVWLS",
-	"CMOVWLT",
-	"CMOVWMI",
-	"CMOVWNE",
-	"CMOVWOC",
-	"CMOVWOS",
-	"CMOVWPC",
-	"CMOVWPL",
-	"CMOVWPS",
-	"FCMOVCC",
-	"FCMOVCS",
-	"FCMOVEQ",
-	"FCMOVHI",
-	"FCMOVLS",
-	"FCMOVNE",
-	"FCMOVNU",
-	"FCMOVUN",
-	"LFENCE",
-	"MFENCE",
-	"SFENCE",
-	"EMMS",
-	"PREFETCHT0",
-	"PREFETCHT1",
-	"PREFETCHT2",
-	"PREFETCHNTA",
-	"BSWAPL",
-	"ADDPD",
-	"ADDPS",
-	"ADDSD",
-	"ADDSS",
-	"ANDNPD",
-	"ANDNPS",
-	"ANDPD",
-	"ANDPS",
-	"CMPPD",
-	"CMPPS",
-	"CMPSD",
-	"CMPSS",
-	"COMISD",
-	"COMISS",
-	"CVTPL2PD",
-	"CVTPL2PS",
-	"CVTPD2PL",
-	"CVTPD2PS",
-	"CVTPS2PL",
-	"CVTPS2PD",
-	"CVTSD2SL",
-	"CVTSD2SS",
-	"CVTSL2SD",
-	"CVTSL2SS",
-	"CVTSS2SD",
-	"CVTSS2SL",
-	"CVTTPD2PL",
-	"CVTTPS2PL",
-	"CVTTSD2SL",
-	"CVTTSS2SL",
-	"DIVPD",
-	"DIVPS",
-	"DIVSD",
-	"DIVSS",
-	"MASKMOVOU",
-	"MAXPD",
-	"MAXPS",
-	"MAXSD",
-	"MAXSS",
-	"MINPD",
-	"MINPS",
-	"MINSD",
-	"MINSS",
-	"MOVAPD",
-	"MOVAPS",
-	"MOVO",
-	"MOVOU",
-	"MOVHLPS",
-	"MOVHPD",
-	"MOVHPS",
-	"MOVLHPS",
-	"MOVLPD",
-	"MOVLPS",
-	"MOVMSKPD",
-	"MOVMSKPS",
-	"MOVNTO",
-	"MOVNTPD",
-	"MOVNTPS",
-	"MOVSD",
-	"MOVSS",
-	"MOVUPD",
-	"MOVUPS",
-	"MULPD",
-	"MULPS",
-	"MULSD",
-	"MULSS",
-	"ORPD",
-	"ORPS",
-	"PADDQ",
-	"PAND",
-	"PCMPEQB",
-	"PMAXSW",
-	"PMAXUB",
-	"PMINSW",
-	"PMINUB",
-	"PMOVMSKB",
-	"PSADBW",
-	"PSUBB",
-	"PSUBL",
-	"PSUBQ",
-	"PSUBSB",
-	"PSUBSW",
-	"PSUBUSB",
-	"PSUBUSW",
-	"PSUBW",
-	"PUNPCKHQDQ",
-	"PUNPCKLQDQ",
-	"PXOR",
-	"RCPPS",
-	"RCPSS",
-	"RSQRTPS",
-	"RSQRTSS",
-	"SQRTPD",
-	"SQRTPS",
-	"SQRTSD",
-	"SQRTSS",
-	"SUBPD",
-	"SUBPS",
-	"SUBSD",
-	"SUBSS",
-	"UCOMISD",
-	"UCOMISS",
-	"UNPCKHPD",
-	"UNPCKHPS",
-	"UNPCKLPD",
-	"UNPCKLPS",
-	"XORPD",
-	"XORPS",
-	"PSHUFHW",
-	"PSHUFL",
-	"PSHUFLW",
-	"AESENC",
-	"PINSRD",
-	"PSHUFB",
-	"LAST",
-}
diff --git a/src/cmd/internal/obj/i386/asm8.go b/src/cmd/internal/obj/i386/asm8.go
deleted file mode 100644
index 4284586..0000000
--- a/src/cmd/internal/obj/i386/asm8.go
+++ /dev/null
@@ -1,3496 +0,0 @@
-// Inferno utils/8l/span.c
-// http://code.google.com/p/inferno-os/source/browse/utils/8l/span.c
-//
-//	Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
-//	Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
-//	Portions Copyright © 1997-1999 Vita Nuova Limited
-//	Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
-//	Portions Copyright © 2004,2006 Bruce Ellis
-//	Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
-//	Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
-//	Portions Copyright © 2009 The Go Authors.  All rights reserved.
-//
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files (the "Software"), to deal
-// in the Software without restriction, including without limitation the rights
-// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-// copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-// THE SOFTWARE.
-
-package i386
-
-import (
-	"cmd/internal/obj"
-	"fmt"
-	"log"
-	"strings"
-)
-
-// Instruction layout.
-
-const (
-	MaxAlign  = 32
-	FuncAlign = 16
-)
-
-type Optab struct {
-	as     int16
-	ytab   []ytab
-	prefix uint8
-	op     [13]uint8
-}
-
-type ytab struct {
-	from    uint8
-	to      uint8
-	zcase   uint8
-	zoffset uint8
-}
-
-var opindex [ALAST + 1]*Optab
-
-const (
-	Yxxx = 0 + iota
-	Ynone
-	Yi0
-	Yi1
-	Yi8
-	Yi32
-	Yiauto
-	Yal
-	Ycl
-	Yax
-	Ycx
-	Yrb
-	Yrl
-	Yrf
-	Yf0
-	Yrx
-	Ymb
-	Yml
-	Ym
-	Ybr
-	Ycol
-	Ytextsize
-	Ytls
-	Ycs
-	Yss
-	Yds
-	Yes
-	Yfs
-	Ygs
-	Ygdtr
-	Yidtr
-	Yldtr
-	Ymsw
-	Ytask
-	Ycr0
-	Ycr1
-	Ycr2
-	Ycr3
-	Ycr4
-	Ycr5
-	Ycr6
-	Ycr7
-	Ydr0
-	Ydr1
-	Ydr2
-	Ydr3
-	Ydr4
-	Ydr5
-	Ydr6
-	Ydr7
-	Ytr0
-	Ytr1
-	Ytr2
-	Ytr3
-	Ytr4
-	Ytr5
-	Ytr6
-	Ytr7
-	Ymr
-	Ymm
-	Yxr
-	Yxm
-	Ymax
-	Zxxx = 0 + iota - 63
-	Zlit
-	Zlitm_r
-	Z_rp
-	Zbr
-	Zcall
-	Zcallcon
-	Zcallind
-	Zcallindreg
-	Zib_
-	Zib_rp
-	Zibo_m
-	Zil_
-	Zil_rp
-	Zilo_m
-	Zjmp
-	Zjmpcon
-	Zloop
-	Zm_o
-	Zm_r
-	Zm2_r
-	Zm_r_xm
-	Zm_r_i_xm
-	Zaut_r
-	Zo_m
-	Zpseudo
-	Zr_m
-	Zr_m_xm
-	Zr_m_i_xm
-	Zrp_
-	Z_ib
-	Z_il
-	Zm_ibo
-	Zm_ilo
-	Zib_rr
-	Zil_rr
-	Zclr
-	Zibm_r
-	Zbyte
-	Zmov
-	Zmax
-	Px  = 0
-	Pe  = 0x66
-	Pm  = 0x0f
-	Pq  = 0xff
-	Pb  = 0xfe
-	Pf2 = 0xf2
-	Pf3 = 0xf3
-)
-
-var ycover [Ymax * Ymax]uint8
-
-var reg [MAXREG]int
-
-var ynone = []ytab{
-	{Ynone, Ynone, Zlit, 1},
-}
-
-var ytext = []ytab{
-	{Ymb, Ytextsize, Zpseudo, 1},
-}
-
-var ynop = []ytab{
-	{Ynone, Ynone, Zpseudo, 0},
-	{Ynone, Yiauto, Zpseudo, 0},
-	{Ynone, Yml, Zpseudo, 0},
-	{Ynone, Yrf, Zpseudo, 0},
-	{Yiauto, Ynone, Zpseudo, 0},
-	{Ynone, Yxr, Zpseudo, 0},
-	{Yml, Ynone, Zpseudo, 0},
-	{Yrf, Ynone, Zpseudo, 0},
-	{Yxr, Ynone, Zpseudo, 1},
-}
-
-var yfuncdata = []ytab{
-	{Yi32, Ym, Zpseudo, 0},
-}
-
-var ypcdata = []ytab{
-	{Yi32, Yi32, Zpseudo, 0},
-}
-
-var yxorb = []ytab{
-	{Yi32, Yal, Zib_, 1},
-	{Yi32, Ymb, Zibo_m, 2},
-	{Yrb, Ymb, Zr_m, 1},
-	{Ymb, Yrb, Zm_r, 1},
-}
-
-var yxorl = []ytab{
-	{Yi8, Yml, Zibo_m, 2},
-	{Yi32, Yax, Zil_, 1},
-	{Yi32, Yml, Zilo_m, 2},
-	{Yrl, Yml, Zr_m, 1},
-	{Yml, Yrl, Zm_r, 1},
-}
-
-var yaddl = []ytab{
-	{Yi8, Yml, Zibo_m, 2},
-	{Yi32, Yax, Zil_, 1},
-	{Yi32, Yml, Zilo_m, 2},
-	{Yrl, Yml, Zr_m, 1},
-	{Yml, Yrl, Zm_r, 1},
-}
-
-var yincb = []ytab{
-	{Ynone, Ymb, Zo_m, 2},
-}
-
-var yincl = []ytab{
-	{Ynone, Yrl, Z_rp, 1},
-	{Ynone, Yml, Zo_m, 2},
-}
-
-var ycmpb = []ytab{
-	{Yal, Yi32, Z_ib, 1},
-	{Ymb, Yi32, Zm_ibo, 2},
-	{Ymb, Yrb, Zm_r, 1},
-	{Yrb, Ymb, Zr_m, 1},
-}
-
-var ycmpl = []ytab{
-	{Yml, Yi8, Zm_ibo, 2},
-	{Yax, Yi32, Z_il, 1},
-	{Yml, Yi32, Zm_ilo, 2},
-	{Yml, Yrl, Zm_r, 1},
-	{Yrl, Yml, Zr_m, 1},
-}
-
-var yshb = []ytab{
-	{Yi1, Ymb, Zo_m, 2},
-	{Yi32, Ymb, Zibo_m, 2},
-	{Ycx, Ymb, Zo_m, 2},
-}
-
-var yshl = []ytab{
-	{Yi1, Yml, Zo_m, 2},
-	{Yi32, Yml, Zibo_m, 2},
-	{Ycl, Yml, Zo_m, 2},
-	{Ycx, Yml, Zo_m, 2},
-}
-
-var ytestb = []ytab{
-	{Yi32, Yal, Zib_, 1},
-	{Yi32, Ymb, Zibo_m, 2},
-	{Yrb, Ymb, Zr_m, 1},
-	{Ymb, Yrb, Zm_r, 1},
-}
-
-var ytestl = []ytab{
-	{Yi32, Yax, Zil_, 1},
-	{Yi32, Yml, Zilo_m, 2},
-	{Yrl, Yml, Zr_m, 1},
-	{Yml, Yrl, Zm_r, 1},
-}
-
-var ymovb = []ytab{
-	{Yrb, Ymb, Zr_m, 1},
-	{Ymb, Yrb, Zm_r, 1},
-	{Yi32, Yrb, Zib_rp, 1},
-	{Yi32, Ymb, Zibo_m, 2},
-}
-
-var ymovw = []ytab{
-	{Yrl, Yml, Zr_m, 1},
-	{Yml, Yrl, Zm_r, 1},
-	{Yi0, Yrl, Zclr, 1 + 2},
-	//	Yi0,	Yml,	Zibo_m,	2,	// shorter but slower AND $0,dst
-	{Yi32, Yrl, Zil_rp, 1},
-	{Yi32, Yml, Zilo_m, 2},
-	{Yiauto, Yrl, Zaut_r, 1},
-}
-
-var ymovl = []ytab{
-	{Yrl, Yml, Zr_m, 1},
-	{Yml, Yrl, Zm_r, 1},
-	{Yi0, Yrl, Zclr, 1 + 2},
-	//	Yi0,	Yml,	Zibo_m,	2,	// shorter but slower AND $0,dst
-	{Yi32, Yrl, Zil_rp, 1},
-	{Yi32, Yml, Zilo_m, 2},
-	{Yml, Yxr, Zm_r_xm, 2}, // XMM MOVD (32 bit)
-	{Yxr, Yml, Zr_m_xm, 2}, // XMM MOVD (32 bit)
-	{Yiauto, Yrl, Zaut_r, 1},
-}
-
-var ymovq = []ytab{
-	{Yml, Yxr, Zm_r_xm, 2},
-}
-
-var ym_rl = []ytab{
-	{Ym, Yrl, Zm_r, 1},
-}
-
-var yrl_m = []ytab{
-	{Yrl, Ym, Zr_m, 1},
-}
-
-var ymb_rl = []ytab{
-	{Ymb, Yrl, Zm_r, 1},
-}
-
-var yml_rl = []ytab{
-	{Yml, Yrl, Zm_r, 1},
-}
-
-var yrb_mb = []ytab{
-	{Yrb, Ymb, Zr_m, 1},
-}
-
-var yrl_ml = []ytab{
-	{Yrl, Yml, Zr_m, 1},
-}
-
-var yml_mb = []ytab{
-	{Yrb, Ymb, Zr_m, 1},
-	{Ymb, Yrb, Zm_r, 1},
-}
-
-var yxchg = []ytab{
-	{Yax, Yrl, Z_rp, 1},
-	{Yrl, Yax, Zrp_, 1},
-	{Yrl, Yml, Zr_m, 1},
-	{Yml, Yrl, Zm_r, 1},
-}
-
-var ydivl = []ytab{
-	{Yml, Ynone, Zm_o, 2},
-}
-
-var ydivb = []ytab{
-	{Ymb, Ynone, Zm_o, 2},
-}
-
-var yimul = []ytab{
-	{Yml, Ynone, Zm_o, 2},
-	{Yi8, Yrl, Zib_rr, 1},
-	{Yi32, Yrl, Zil_rr, 1},
-}
-
-var ybyte = []ytab{
-	{Yi32, Ynone, Zbyte, 1},
-}
-
-var yin = []ytab{
-	{Yi32, Ynone, Zib_, 1},
-	{Ynone, Ynone, Zlit, 1},
-}
-
-var yint = []ytab{
-	{Yi32, Ynone, Zib_, 1},
-}
-
-var ypushl = []ytab{
-	{Yrl, Ynone, Zrp_, 1},
-	{Ym, Ynone, Zm_o, 2},
-	{Yi8, Ynone, Zib_, 1},
-	{Yi32, Ynone, Zil_, 1},
-}
-
-var ypopl = []ytab{
-	{Ynone, Yrl, Z_rp, 1},
-	{Ynone, Ym, Zo_m, 2},
-}
-
-var ybswap = []ytab{
-	{Ynone, Yrl, Z_rp, 1},
-}
-
-var yscond = []ytab{
-	{Ynone, Ymb, Zo_m, 2},
-}
-
-var yjcond = []ytab{
-	{Ynone, Ybr, Zbr, 0},
-	{Yi0, Ybr, Zbr, 0},
-	{Yi1, Ybr, Zbr, 1},
-}
-
-var yloop = []ytab{
-	{Ynone, Ybr, Zloop, 1},
-}
-
-var ycall = []ytab{
-	{Ynone, Yml, Zcallindreg, 0},
-	{Yrx, Yrx, Zcallindreg, 2},
-	{Ynone, Ycol, Zcallind, 2},
-	{Ynone, Ybr, Zcall, 0},
-	{Ynone, Yi32, Zcallcon, 1},
-}
-
-var yduff = []ytab{
-	{Ynone, Yi32, Zcall, 1},
-}
-
-var yjmp = []ytab{
-	{Ynone, Yml, Zo_m, 2},
-	{Ynone, Ybr, Zjmp, 0},
-	{Ynone, Yi32, Zjmpcon, 1},
-}
-
-var yfmvd = []ytab{
-	{Ym, Yf0, Zm_o, 2},
-	{Yf0, Ym, Zo_m, 2},
-	{Yrf, Yf0, Zm_o, 2},
-	{Yf0, Yrf, Zo_m, 2},
-}
-
-var yfmvdp = []ytab{
-	{Yf0, Ym, Zo_m, 2},
-	{Yf0, Yrf, Zo_m, 2},
-}
-
-var yfmvf = []ytab{
-	{Ym, Yf0, Zm_o, 2},
-	{Yf0, Ym, Zo_m, 2},
-}
-
-var yfmvx = []ytab{
-	{Ym, Yf0, Zm_o, 2},
-}
-
-var yfmvp = []ytab{
-	{Yf0, Ym, Zo_m, 2},
-}
-
-var yfcmv = []ytab{
-	{Yrf, Yf0, Zm_o, 2},
-}
-
-var yfadd = []ytab{
-	{Ym, Yf0, Zm_o, 2},
-	{Yrf, Yf0, Zm_o, 2},
-	{Yf0, Yrf, Zo_m, 2},
-}
-
-var yfaddp = []ytab{
-	{Yf0, Yrf, Zo_m, 2},
-}
-
-var yfxch = []ytab{
-	{Yf0, Yrf, Zo_m, 2},
-	{Yrf, Yf0, Zm_o, 2},
-}
-
-var ycompp = []ytab{
-	{Yf0, Yrf, Zo_m, 2}, /* botch is really f0,f1 */
-}
-
-var ystsw = []ytab{
-	{Ynone, Ym, Zo_m, 2},
-	{Ynone, Yax, Zlit, 1},
-}
-
-var ystcw = []ytab{
-	{Ynone, Ym, Zo_m, 2},
-	{Ym, Ynone, Zm_o, 2},
-}
-
-var ysvrs = []ytab{
-	{Ynone, Ym, Zo_m, 2},
-	{Ym, Ynone, Zm_o, 2},
-}
-
-var ymskb = []ytab{
-	{Yxr, Yrl, Zm_r_xm, 2},
-	{Ymr, Yrl, Zm_r_xm, 1},
-}
-
-var yxm = []ytab{
-	{Yxm, Yxr, Zm_r_xm, 1},
-}
-
-var yxcvm1 = []ytab{
-	{Yxm, Yxr, Zm_r_xm, 2},
-	{Yxm, Ymr, Zm_r_xm, 2},
-}
-
-var yxcvm2 = []ytab{
-	{Yxm, Yxr, Zm_r_xm, 2},
-	{Ymm, Yxr, Zm_r_xm, 2},
-}
-
-var yxmq = []ytab{
-	{Yxm, Yxr, Zm_r_xm, 2},
-}
-
-var yxr = []ytab{
-	{Yxr, Yxr, Zm_r_xm, 1},
-}
-
-var yxr_ml = []ytab{
-	{Yxr, Yml, Zr_m_xm, 1},
-}
-
-var yxcmp = []ytab{
-	{Yxm, Yxr, Zm_r_xm, 1},
-}
-
-var yxcmpi = []ytab{
-	{Yxm, Yxr, Zm_r_i_xm, 2},
-}
-
-var yxmov = []ytab{
-	{Yxm, Yxr, Zm_r_xm, 1},
-	{Yxr, Yxm, Zr_m_xm, 1},
-}
-
-var yxcvfl = []ytab{
-	{Yxm, Yrl, Zm_r_xm, 1},
-}
-
-var yxcvlf = []ytab{
-	{Yml, Yxr, Zm_r_xm, 1},
-}
-
-/*
-var yxcvfq = []ytab{
-	{Yxm, Yrl, Zm_r_xm, 2},
-}
-
-var yxcvqf = []ytab{
-	{Yml, Yxr, Zm_r_xm, 2},
-}
-*/
-
-var yxrrl = []ytab{
-	{Yxr, Yrl, Zm_r, 1},
-}
-
-var yprefetch = []ytab{
-	{Ym, Ynone, Zm_o, 2},
-}
-
-var yaes = []ytab{
-	{Yxm, Yxr, Zlitm_r, 2},
-}
-
-var yinsrd = []ytab{
-	{Yml, Yxr, Zibm_r, 2},
-}
-
-var ymshufb = []ytab{
-	{Yxm, Yxr, Zm2_r, 2},
-}
-
-var yxshuf = []ytab{
-	{Yxm, Yxr, Zibm_r, 2},
-}
-
-var optab = []Optab{ /*	as, ytab, andproto, opcode */
-	Optab{obj.AXXX, nil, 0, [13]uint8{}},
-	Optab{AAAA, ynone, Px, [13]uint8{0x37}},
-	Optab{AAAD, ynone, Px, [13]uint8{0xd5, 0x0a}},
-	Optab{AAAM, ynone, Px, [13]uint8{0xd4, 0x0a}},
-	Optab{AAAS, ynone, Px, [13]uint8{0x3f}},
-	Optab{AADCB, yxorb, Pb, [13]uint8{0x14, 0x80, 02, 0x10, 0x10}},
-	Optab{AADCL, yxorl, Px, [13]uint8{0x83, 02, 0x15, 0x81, 02, 0x11, 0x13}},
-	Optab{AADCW, yxorl, Pe, [13]uint8{0x83, 02, 0x15, 0x81, 02, 0x11, 0x13}},
-	Optab{AADDB, yxorb, Px, [13]uint8{0x04, 0x80, 00, 0x00, 0x02}},
-	Optab{AADDL, yaddl, Px, [13]uint8{0x83, 00, 0x05, 0x81, 00, 0x01, 0x03}},
-	Optab{AADDW, yaddl, Pe, [13]uint8{0x83, 00, 0x05, 0x81, 00, 0x01, 0x03}},
-	Optab{AADJSP, nil, 0, [13]uint8{}},
-	Optab{AANDB, yxorb, Pb, [13]uint8{0x24, 0x80, 04, 0x20, 0x22}},
-	Optab{AANDL, yxorl, Px, [13]uint8{0x83, 04, 0x25, 0x81, 04, 0x21, 0x23}},
-	Optab{AANDW, yxorl, Pe, [13]uint8{0x83, 04, 0x25, 0x81, 04, 0x21, 0x23}},
-	Optab{AARPL, yrl_ml, Px, [13]uint8{0x63}},
-	Optab{ABOUNDL, yrl_m, Px, [13]uint8{0x62}},
-	Optab{ABOUNDW, yrl_m, Pe, [13]uint8{0x62}},
-	Optab{ABSFL, yml_rl, Pm, [13]uint8{0xbc}},
-	Optab{ABSFW, yml_rl, Pq, [13]uint8{0xbc}},
-	Optab{ABSRL, yml_rl, Pm, [13]uint8{0xbd}},
-	Optab{ABSRW, yml_rl, Pq, [13]uint8{0xbd}},
-	Optab{ABTL, yml_rl, Pm, [13]uint8{0xa3}},
-	Optab{ABTW, yml_rl, Pq, [13]uint8{0xa3}},
-	Optab{ABTCL, yml_rl, Pm, [13]uint8{0xbb}},
-	Optab{ABTCW, yml_rl, Pq, [13]uint8{0xbb}},
-	Optab{ABTRL, yml_rl, Pm, [13]uint8{0xb3}},
-	Optab{ABTRW, yml_rl, Pq, [13]uint8{0xb3}},
-	Optab{ABTSL, yml_rl, Pm, [13]uint8{0xab}},
-	Optab{ABTSW, yml_rl, Pq, [13]uint8{0xab}},
-	Optab{ABYTE, ybyte, Px, [13]uint8{1}},
-	Optab{obj.ACALL, ycall, Px, [13]uint8{0xff, 02, 0xff, 0x15, 0xe8}},
-	Optab{ACLC, ynone, Px, [13]uint8{0xf8}},
-	Optab{ACLD, ynone, Px, [13]uint8{0xfc}},
-	Optab{ACLI, ynone, Px, [13]uint8{0xfa}},
-	Optab{ACLTS, ynone, Pm, [13]uint8{0x06}},
-	Optab{ACMC, ynone, Px, [13]uint8{0xf5}},
-	Optab{ACMPB, ycmpb, Pb, [13]uint8{0x3c, 0x80, 07, 0x38, 0x3a}},
-	Optab{ACMPL, ycmpl, Px, [13]uint8{0x83, 07, 0x3d, 0x81, 07, 0x39, 0x3b}},
-	Optab{ACMPW, ycmpl, Pe, [13]uint8{0x83, 07, 0x3d, 0x81, 07, 0x39, 0x3b}},
-	Optab{ACMPSB, ynone, Pb, [13]uint8{0xa6}},
-	Optab{ACMPSL, ynone, Px, [13]uint8{0xa7}},
-	Optab{ACMPSW, ynone, Pe, [13]uint8{0xa7}},
-	Optab{ADAA, ynone, Px, [13]uint8{0x27}},
-	Optab{ADAS, ynone, Px, [13]uint8{0x2f}},
-	Optab{obj.ADATA, nil, 0, [13]uint8{}},
-	Optab{ADECB, yincb, Pb, [13]uint8{0xfe, 01}},
-	Optab{ADECL, yincl, Px, [13]uint8{0x48, 0xff, 01}},
-	Optab{ADECW, yincl, Pe, [13]uint8{0x48, 0xff, 01}},
-	Optab{ADIVB, ydivb, Pb, [13]uint8{0xf6, 06}},
-	Optab{ADIVL, ydivl, Px, [13]uint8{0xf7, 06}},
-	Optab{ADIVW, ydivl, Pe, [13]uint8{0xf7, 06}},
-	Optab{AENTER, nil, 0, [13]uint8{}}, /* botch */
-	Optab{obj.AGLOBL, nil, 0, [13]uint8{}},
-	Optab{AHLT, ynone, Px, [13]uint8{0xf4}},
-	Optab{AIDIVB, ydivb, Pb, [13]uint8{0xf6, 07}},
-	Optab{AIDIVL, ydivl, Px, [13]uint8{0xf7, 07}},
-	Optab{AIDIVW, ydivl, Pe, [13]uint8{0xf7, 07}},
-	Optab{AIMULB, ydivb, Pb, [13]uint8{0xf6, 05}},
-	Optab{AIMULL, yimul, Px, [13]uint8{0xf7, 05, 0x6b, 0x69}},
-	Optab{AIMULW, yimul, Pe, [13]uint8{0xf7, 05, 0x6b, 0x69}},
-	Optab{AINB, yin, Pb, [13]uint8{0xe4, 0xec}},
-	Optab{AINL, yin, Px, [13]uint8{0xe5, 0xed}},
-	Optab{AINW, yin, Pe, [13]uint8{0xe5, 0xed}},
-	Optab{AINCB, yincb, Pb, [13]uint8{0xfe, 00}},
-	Optab{AINCL, yincl, Px, [13]uint8{0x40, 0xff, 00}},
-	Optab{AINCW, yincl, Pe, [13]uint8{0x40, 0xff, 00}},
-	Optab{AINSB, ynone, Pb, [13]uint8{0x6c}},
-	Optab{AINSL, ynone, Px, [13]uint8{0x6d}},
-	Optab{AINSW, ynone, Pe, [13]uint8{0x6d}},
-	Optab{AINT, yint, Px, [13]uint8{0xcd}},
-	Optab{AINTO, ynone, Px, [13]uint8{0xce}},
-	Optab{AIRETL, ynone, Px, [13]uint8{0xcf}},
-	Optab{AIRETW, ynone, Pe, [13]uint8{0xcf}},
-	Optab{AJCC, yjcond, Px, [13]uint8{0x73, 0x83, 00}},
-	Optab{AJCS, yjcond, Px, [13]uint8{0x72, 0x82}},
-	Optab{AJCXZL, yloop, Px, [13]uint8{0xe3}},
-	Optab{AJCXZW, yloop, Px, [13]uint8{0xe3}},
-	Optab{AJEQ, yjcond, Px, [13]uint8{0x74, 0x84}},
-	Optab{AJGE, yjcond, Px, [13]uint8{0x7d, 0x8d}},
-	Optab{AJGT, yjcond, Px, [13]uint8{0x7f, 0x8f}},
-	Optab{AJHI, yjcond, Px, [13]uint8{0x77, 0x87}},
-	Optab{AJLE, yjcond, Px, [13]uint8{0x7e, 0x8e}},
-	Optab{AJLS, yjcond, Px, [13]uint8{0x76, 0x86}},
-	Optab{AJLT, yjcond, Px, [13]uint8{0x7c, 0x8c}},
-	Optab{AJMI, yjcond, Px, [13]uint8{0x78, 0x88}},
-	Optab{obj.AJMP, yjmp, Px, [13]uint8{0xff, 04, 0xeb, 0xe9}},
-	Optab{AJNE, yjcond, Px, [13]uint8{0x75, 0x85}},
-	Optab{AJOC, yjcond, Px, [13]uint8{0x71, 0x81, 00}},
-	Optab{AJOS, yjcond, Px, [13]uint8{0x70, 0x80, 00}},
-	Optab{AJPC, yjcond, Px, [13]uint8{0x7b, 0x8b}},
-	Optab{AJPL, yjcond, Px, [13]uint8{0x79, 0x89}},
-	Optab{AJPS, yjcond, Px, [13]uint8{0x7a, 0x8a}},
-	Optab{ALAHF, ynone, Px, [13]uint8{0x9f}},
-	Optab{ALARL, yml_rl, Pm, [13]uint8{0x02}},
-	Optab{ALARW, yml_rl, Pq, [13]uint8{0x02}},
-	Optab{ALEAL, ym_rl, Px, [13]uint8{0x8d}},
-	Optab{ALEAW, ym_rl, Pe, [13]uint8{0x8d}},
-	Optab{ALEAVEL, ynone, Px, [13]uint8{0xc9}},
-	Optab{ALEAVEW, ynone, Pe, [13]uint8{0xc9}},
-	Optab{ALOCK, ynone, Px, [13]uint8{0xf0}},
-	Optab{ALODSB, ynone, Pb, [13]uint8{0xac}},
-	Optab{ALODSL, ynone, Px, [13]uint8{0xad}},
-	Optab{ALODSW, ynone, Pe, [13]uint8{0xad}},
-	Optab{ALONG, ybyte, Px, [13]uint8{4}},
-	Optab{ALOOP, yloop, Px, [13]uint8{0xe2}},
-	Optab{ALOOPEQ, yloop, Px, [13]uint8{0xe1}},
-	Optab{ALOOPNE, yloop, Px, [13]uint8{0xe0}},
-	Optab{ALSLL, yml_rl, Pm, [13]uint8{0x03}},
-	Optab{ALSLW, yml_rl, Pq, [13]uint8{0x03}},
-	Optab{AMOVB, ymovb, Pb, [13]uint8{0x88, 0x8a, 0xb0, 0xc6, 00}},
-	Optab{AMOVL, ymovl, Px, [13]uint8{0x89, 0x8b, 0x31, 0x83, 04, 0xb8, 0xc7, 00, Pe, 0x6e, Pe, 0x7e, 0}},
-	Optab{AMOVW, ymovw, Pe, [13]uint8{0x89, 0x8b, 0x31, 0x83, 04, 0xb8, 0xc7, 00, 0}},
-	Optab{AMOVQ, ymovq, Pf3, [13]uint8{0x7e}},
-	Optab{AMOVBLSX, ymb_rl, Pm, [13]uint8{0xbe}},
-	Optab{AMOVBLZX, ymb_rl, Pm, [13]uint8{0xb6}},
-	Optab{AMOVBWSX, ymb_rl, Pq, [13]uint8{0xbe}},
-	Optab{AMOVBWZX, ymb_rl, Pq, [13]uint8{0xb6}},
-	Optab{AMOVWLSX, yml_rl, Pm, [13]uint8{0xbf}},
-	Optab{AMOVWLZX, yml_rl, Pm, [13]uint8{0xb7}},
-	Optab{AMOVSB, ynone, Pb, [13]uint8{0xa4}},
-	Optab{AMOVSL, ynone, Px, [13]uint8{0xa5}},
-	Optab{AMOVSW, ynone, Pe, [13]uint8{0xa5}},
-	Optab{AMULB, ydivb, Pb, [13]uint8{0xf6, 04}},
-	Optab{AMULL, ydivl, Px, [13]uint8{0xf7, 04}},
-	Optab{AMULW, ydivl, Pe, [13]uint8{0xf7, 04}},
-	Optab{ANEGB, yscond, Px, [13]uint8{0xf6, 03}},
-	Optab{ANEGL, yscond, Px, [13]uint8{0xf7, 03}}, // TODO(rsc): yscond is wrong here.
-	Optab{ANEGW, yscond, Pe, [13]uint8{0xf7, 03}}, // TODO(rsc): yscond is wrong here.
-	Optab{obj.ANOP, ynop, Px, [13]uint8{0, 0}},
-	Optab{ANOTB, yscond, Px, [13]uint8{0xf6, 02}},
-	Optab{ANOTL, yscond, Px, [13]uint8{0xf7, 02}}, // TODO(rsc): yscond is wrong here.
-	Optab{ANOTW, yscond, Pe, [13]uint8{0xf7, 02}}, // TODO(rsc): yscond is wrong here.
-	Optab{AORB, yxorb, Pb, [13]uint8{0x0c, 0x80, 01, 0x08, 0x0a}},
-	Optab{AORL, yxorl, Px, [13]uint8{0x83, 01, 0x0d, 0x81, 01, 0x09, 0x0b}},
-	Optab{AORW, yxorl, Pe, [13]uint8{0x83, 01, 0x0d, 0x81, 01, 0x09, 0x0b}},
-	Optab{AOUTB, yin, Pb, [13]uint8{0xe6, 0xee}},
-	Optab{AOUTL, yin, Px, [13]uint8{0xe7, 0xef}},
-	Optab{AOUTW, yin, Pe, [13]uint8{0xe7, 0xef}},
-	Optab{AOUTSB, ynone, Pb, [13]uint8{0x6e}},
-	Optab{AOUTSL, ynone, Px, [13]uint8{0x6f}},
-	Optab{AOUTSW, ynone, Pe, [13]uint8{0x6f}},
-	Optab{APAUSE, ynone, Px, [13]uint8{0xf3, 0x90}},
-	Optab{APOPAL, ynone, Px, [13]uint8{0x61}},
-	Optab{APOPAW, ynone, Pe, [13]uint8{0x61}},
-	Optab{APOPFL, ynone, Px, [13]uint8{0x9d}},
-	Optab{APOPFW, ynone, Pe, [13]uint8{0x9d}},
-	Optab{APOPL, ypopl, Px, [13]uint8{0x58, 0x8f, 00}},
-	Optab{APOPW, ypopl, Pe, [13]uint8{0x58, 0x8f, 00}},
-	Optab{APUSHAL, ynone, Px, [13]uint8{0x60}},
-	Optab{APUSHAW, ynone, Pe, [13]uint8{0x60}},
-	Optab{APUSHFL, ynone, Px, [13]uint8{0x9c}},
-	Optab{APUSHFW, ynone, Pe, [13]uint8{0x9c}},
-	Optab{APUSHL, ypushl, Px, [13]uint8{0x50, 0xff, 06, 0x6a, 0x68}},
-	Optab{APUSHW, ypushl, Pe, [13]uint8{0x50, 0xff, 06, 0x6a, 0x68}},
-	Optab{ARCLB, yshb, Pb, [13]uint8{0xd0, 02, 0xc0, 02, 0xd2, 02}},
-	Optab{ARCLL, yshl, Px, [13]uint8{0xd1, 02, 0xc1, 02, 0xd3, 02, 0xd3, 02}},
-	Optab{ARCLW, yshl, Pe, [13]uint8{0xd1, 02, 0xc1, 02, 0xd3, 02, 0xd3, 02}},
-	Optab{ARCRB, yshb, Pb, [13]uint8{0xd0, 03, 0xc0, 03, 0xd2, 03}},
-	Optab{ARCRL, yshl, Px, [13]uint8{0xd1, 03, 0xc1, 03, 0xd3, 03, 0xd3, 03}},
-	Optab{ARCRW, yshl, Pe, [13]uint8{0xd1, 03, 0xc1, 03, 0xd3, 03, 0xd3, 03}},
-	Optab{AREP, ynone, Px, [13]uint8{0xf3}},
-	Optab{AREPN, ynone, Px, [13]uint8{0xf2}},
-	Optab{obj.ARET, ynone, Px, [13]uint8{0xc3}},
-	Optab{AROLB, yshb, Pb, [13]uint8{0xd0, 00, 0xc0, 00, 0xd2, 00}},
-	Optab{AROLL, yshl, Px, [13]uint8{0xd1, 00, 0xc1, 00, 0xd3, 00, 0xd3, 00}},
-	Optab{AROLW, yshl, Pe, [13]uint8{0xd1, 00, 0xc1, 00, 0xd3, 00, 0xd3, 00}},
-	Optab{ARORB, yshb, Pb, [13]uint8{0xd0, 01, 0xc0, 01, 0xd2, 01}},
-	Optab{ARORL, yshl, Px, [13]uint8{0xd1, 01, 0xc1, 01, 0xd3, 01, 0xd3, 01}},
-	Optab{ARORW, yshl, Pe, [13]uint8{0xd1, 01, 0xc1, 01, 0xd3, 01, 0xd3, 01}},
-	Optab{ASAHF, ynone, Px, [13]uint8{0x9e}},
-	Optab{ASALB, yshb, Pb, [13]uint8{0xd0, 04, 0xc0, 04, 0xd2, 04}},
-	Optab{ASALL, yshl, Px, [13]uint8{0xd1, 04, 0xc1, 04, 0xd3, 04, 0xd3, 04}},
-	Optab{ASALW, yshl, Pe, [13]uint8{0xd1, 04, 0xc1, 04, 0xd3, 04, 0xd3, 04}},
-	Optab{ASARB, yshb, Pb, [13]uint8{0xd0, 07, 0xc0, 07, 0xd2, 07}},
-	Optab{ASARL, yshl, Px, [13]uint8{0xd1, 07, 0xc1, 07, 0xd3, 07, 0xd3, 07}},
-	Optab{ASARW, yshl, Pe, [13]uint8{0xd1, 07, 0xc1, 07, 0xd3, 07, 0xd3, 07}},
-	Optab{ASBBB, yxorb, Pb, [13]uint8{0x1c, 0x80, 03, 0x18, 0x1a}},
-	Optab{ASBBL, yxorl, Px, [13]uint8{0x83, 03, 0x1d, 0x81, 03, 0x19, 0x1b}},
-	Optab{ASBBW, yxorl, Pe, [13]uint8{0x83, 03, 0x1d, 0x81, 03, 0x19, 0x1b}},
-	Optab{ASCASB, ynone, Pb, [13]uint8{0xae}},
-	Optab{ASCASL, ynone, Px, [13]uint8{0xaf}},
-	Optab{ASCASW, ynone, Pe, [13]uint8{0xaf}},
-	Optab{ASETCC, yscond, Pm, [13]uint8{0x93, 00}},
-	Optab{ASETCS, yscond, Pm, [13]uint8{0x92, 00}},
-	Optab{ASETEQ, yscond, Pm, [13]uint8{0x94, 00}},
-	Optab{ASETGE, yscond, Pm, [13]uint8{0x9d, 00}},
-	Optab{ASETGT, yscond, Pm, [13]uint8{0x9f, 00}},
-	Optab{ASETHI, yscond, Pm, [13]uint8{0x97, 00}},
-	Optab{ASETLE, yscond, Pm, [13]uint8{0x9e, 00}},
-	Optab{ASETLS, yscond, Pm, [13]uint8{0x96, 00}},
-	Optab{ASETLT, yscond, Pm, [13]uint8{0x9c, 00}},
-	Optab{ASETMI, yscond, Pm, [13]uint8{0x98, 00}},
-	Optab{ASETNE, yscond, Pm, [13]uint8{0x95, 00}},
-	Optab{ASETOC, yscond, Pm, [13]uint8{0x91, 00}},
-	Optab{ASETOS, yscond, Pm, [13]uint8{0x90, 00}},
-	Optab{ASETPC, yscond, Pm, [13]uint8{0x9b, 00}},
-	Optab{ASETPL, yscond, Pm, [13]uint8{0x99, 00}},
-	Optab{ASETPS, yscond, Pm, [13]uint8{0x9a, 00}},
-	Optab{ACDQ, ynone, Px, [13]uint8{0x99}},
-	Optab{ACWD, ynone, Pe, [13]uint8{0x99}},
-	Optab{ASHLB, yshb, Pb, [13]uint8{0xd0, 04, 0xc0, 04, 0xd2, 04}},
-	Optab{ASHLL, yshl, Px, [13]uint8{0xd1, 04, 0xc1, 04, 0xd3, 04, 0xd3, 04}},
-	Optab{ASHLW, yshl, Pe, [13]uint8{0xd1, 04, 0xc1, 04, 0xd3, 04, 0xd3, 04}},
-	Optab{ASHRB, yshb, Pb, [13]uint8{0xd0, 05, 0xc0, 05, 0xd2, 05}},
-	Optab{ASHRL, yshl, Px, [13]uint8{0xd1, 05, 0xc1, 05, 0xd3, 05, 0xd3, 05}},
-	Optab{ASHRW, yshl, Pe, [13]uint8{0xd1, 05, 0xc1, 05, 0xd3, 05, 0xd3, 05}},
-	Optab{ASTC, ynone, Px, [13]uint8{0xf9}},
-	Optab{ASTD, ynone, Px, [13]uint8{0xfd}},
-	Optab{ASTI, ynone, Px, [13]uint8{0xfb}},
-	Optab{ASTOSB, ynone, Pb, [13]uint8{0xaa}},
-	Optab{ASTOSL, ynone, Px, [13]uint8{0xab}},
-	Optab{ASTOSW, ynone, Pe, [13]uint8{0xab}},
-	Optab{ASUBB, yxorb, Pb, [13]uint8{0x2c, 0x80, 05, 0x28, 0x2a}},
-	Optab{ASUBL, yaddl, Px, [13]uint8{0x83, 05, 0x2d, 0x81, 05, 0x29, 0x2b}},
-	Optab{ASUBW, yaddl, Pe, [13]uint8{0x83, 05, 0x2d, 0x81, 05, 0x29, 0x2b}},
-	Optab{ASYSCALL, ynone, Px, [13]uint8{0xcd, 100}},
-	Optab{ATESTB, ytestb, Pb, [13]uint8{0xa8, 0xf6, 00, 0x84, 0x84}},
-	Optab{ATESTL, ytestl, Px, [13]uint8{0xa9, 0xf7, 00, 0x85, 0x85}},
-	Optab{ATESTW, ytestl, Pe, [13]uint8{0xa9, 0xf7, 00, 0x85, 0x85}},
-	Optab{obj.ATEXT, ytext, Px, [13]uint8{}},
-	Optab{AVERR, ydivl, Pm, [13]uint8{0x00, 04}},
-	Optab{AVERW, ydivl, Pm, [13]uint8{0x00, 05}},
-	Optab{AWAIT, ynone, Px, [13]uint8{0x9b}},
-	Optab{AWORD, ybyte, Px, [13]uint8{2}},
-	Optab{AXCHGB, yml_mb, Pb, [13]uint8{0x86, 0x86}},
-	Optab{AXCHGL, yxchg, Px, [13]uint8{0x90, 0x90, 0x87, 0x87}},
-	Optab{AXCHGW, yxchg, Pe, [13]uint8{0x90, 0x90, 0x87, 0x87}},
-	Optab{AXLAT, ynone, Px, [13]uint8{0xd7}},
-	Optab{AXORB, yxorb, Pb, [13]uint8{0x34, 0x80, 06, 0x30, 0x32}},
-	Optab{AXORL, yxorl, Px, [13]uint8{0x83, 06, 0x35, 0x81, 06, 0x31, 0x33}},
-	Optab{AXORW, yxorl, Pe, [13]uint8{0x83, 06, 0x35, 0x81, 06, 0x31, 0x33}},
-	Optab{AFMOVB, yfmvx, Px, [13]uint8{0xdf, 04}},
-	Optab{AFMOVBP, yfmvp, Px, [13]uint8{0xdf, 06}},
-	Optab{AFMOVD, yfmvd, Px, [13]uint8{0xdd, 00, 0xdd, 02, 0xd9, 00, 0xdd, 02}},
-	Optab{AFMOVDP, yfmvdp, Px, [13]uint8{0xdd, 03, 0xdd, 03}},
-	Optab{AFMOVF, yfmvf, Px, [13]uint8{0xd9, 00, 0xd9, 02}},
-	Optab{AFMOVFP, yfmvp, Px, [13]uint8{0xd9, 03}},
-	Optab{AFMOVL, yfmvf, Px, [13]uint8{0xdb, 00, 0xdb, 02}},
-	Optab{AFMOVLP, yfmvp, Px, [13]uint8{0xdb, 03}},
-	Optab{AFMOVV, yfmvx, Px, [13]uint8{0xdf, 05}},
-	Optab{AFMOVVP, yfmvp, Px, [13]uint8{0xdf, 07}},
-	Optab{AFMOVW, yfmvf, Px, [13]uint8{0xdf, 00, 0xdf, 02}},
-	Optab{AFMOVWP, yfmvp, Px, [13]uint8{0xdf, 03}},
-	Optab{AFMOVX, yfmvx, Px, [13]uint8{0xdb, 05}},
-	Optab{AFMOVXP, yfmvp, Px, [13]uint8{0xdb, 07}},
-	Optab{AFCOMB, nil, 0, [13]uint8{}},
-	Optab{AFCOMBP, nil, 0, [13]uint8{}},
-	Optab{AFCOMD, yfadd, Px, [13]uint8{0xdc, 02, 0xd8, 02, 0xdc, 02}},  /* botch */
-	Optab{AFCOMDP, yfadd, Px, [13]uint8{0xdc, 03, 0xd8, 03, 0xdc, 03}}, /* botch */
-	Optab{AFCOMDPP, ycompp, Px, [13]uint8{0xde, 03}},
-	Optab{AFCOMF, yfmvx, Px, [13]uint8{0xd8, 02}},
-	Optab{AFCOMFP, yfmvx, Px, [13]uint8{0xd8, 03}},
-	Optab{AFCOMI, yfmvx, Px, [13]uint8{0xdb, 06}},
-	Optab{AFCOMIP, yfmvx, Px, [13]uint8{0xdf, 06}},
-	Optab{AFCOML, yfmvx, Px, [13]uint8{0xda, 02}},
-	Optab{AFCOMLP, yfmvx, Px, [13]uint8{0xda, 03}},
-	Optab{AFCOMW, yfmvx, Px, [13]uint8{0xde, 02}},
-	Optab{AFCOMWP, yfmvx, Px, [13]uint8{0xde, 03}},
-	Optab{AFUCOM, ycompp, Px, [13]uint8{0xdd, 04}},
-	Optab{AFUCOMI, ycompp, Px, [13]uint8{0xdb, 05}},
-	Optab{AFUCOMIP, ycompp, Px, [13]uint8{0xdf, 05}},
-	Optab{AFUCOMP, ycompp, Px, [13]uint8{0xdd, 05}},
-	Optab{AFUCOMPP, ycompp, Px, [13]uint8{0xda, 13}},
-	Optab{AFADDDP, yfaddp, Px, [13]uint8{0xde, 00}},
-	Optab{AFADDW, yfmvx, Px, [13]uint8{0xde, 00}},
-	Optab{AFADDL, yfmvx, Px, [13]uint8{0xda, 00}},
-	Optab{AFADDF, yfmvx, Px, [13]uint8{0xd8, 00}},
-	Optab{AFADDD, yfadd, Px, [13]uint8{0xdc, 00, 0xd8, 00, 0xdc, 00}},
-	Optab{AFMULDP, yfaddp, Px, [13]uint8{0xde, 01}},
-	Optab{AFMULW, yfmvx, Px, [13]uint8{0xde, 01}},
-	Optab{AFMULL, yfmvx, Px, [13]uint8{0xda, 01}},
-	Optab{AFMULF, yfmvx, Px, [13]uint8{0xd8, 01}},
-	Optab{AFMULD, yfadd, Px, [13]uint8{0xdc, 01, 0xd8, 01, 0xdc, 01}},
-	Optab{AFSUBDP, yfaddp, Px, [13]uint8{0xde, 05}},
-	Optab{AFSUBW, yfmvx, Px, [13]uint8{0xde, 04}},
-	Optab{AFSUBL, yfmvx, Px, [13]uint8{0xda, 04}},
-	Optab{AFSUBF, yfmvx, Px, [13]uint8{0xd8, 04}},
-	Optab{AFSUBD, yfadd, Px, [13]uint8{0xdc, 04, 0xd8, 04, 0xdc, 05}},
-	Optab{AFSUBRDP, yfaddp, Px, [13]uint8{0xde, 04}},
-	Optab{AFSUBRW, yfmvx, Px, [13]uint8{0xde, 05}},
-	Optab{AFSUBRL, yfmvx, Px, [13]uint8{0xda, 05}},
-	Optab{AFSUBRF, yfmvx, Px, [13]uint8{0xd8, 05}},
-	Optab{AFSUBRD, yfadd, Px, [13]uint8{0xdc, 05, 0xd8, 05, 0xdc, 04}},
-	Optab{AFDIVDP, yfaddp, Px, [13]uint8{0xde, 07}},
-	Optab{AFDIVW, yfmvx, Px, [13]uint8{0xde, 06}},
-	Optab{AFDIVL, yfmvx, Px, [13]uint8{0xda, 06}},
-	Optab{AFDIVF, yfmvx, Px, [13]uint8{0xd8, 06}},
-	Optab{AFDIVD, yfadd, Px, [13]uint8{0xdc, 06, 0xd8, 06, 0xdc, 07}},
-	Optab{AFDIVRDP, yfaddp, Px, [13]uint8{0xde, 06}},
-	Optab{AFDIVRW, yfmvx, Px, [13]uint8{0xde, 07}},
-	Optab{AFDIVRL, yfmvx, Px, [13]uint8{0xda, 07}},
-	Optab{AFDIVRF, yfmvx, Px, [13]uint8{0xd8, 07}},
-	Optab{AFDIVRD, yfadd, Px, [13]uint8{0xdc, 07, 0xd8, 07, 0xdc, 06}},
-	Optab{AFXCHD, yfxch, Px, [13]uint8{0xd9, 01, 0xd9, 01}},
-	Optab{AFFREE, nil, 0, [13]uint8{}},
-	Optab{AFLDCW, ystcw, Px, [13]uint8{0xd9, 05, 0xd9, 05}},
-	Optab{AFLDENV, ystcw, Px, [13]uint8{0xd9, 04, 0xd9, 04}},
-	Optab{AFRSTOR, ysvrs, Px, [13]uint8{0xdd, 04, 0xdd, 04}},
-	Optab{AFSAVE, ysvrs, Px, [13]uint8{0xdd, 06, 0xdd, 06}},
-	Optab{AFSTCW, ystcw, Px, [13]uint8{0xd9, 07, 0xd9, 07}},
-	Optab{AFSTENV, ystcw, Px, [13]uint8{0xd9, 06, 0xd9, 06}},
-	Optab{AFSTSW, ystsw, Px, [13]uint8{0xdd, 07, 0xdf, 0xe0}},
-	Optab{AF2XM1, ynone, Px, [13]uint8{0xd9, 0xf0}},
-	Optab{AFABS, ynone, Px, [13]uint8{0xd9, 0xe1}},
-	Optab{AFCHS, ynone, Px, [13]uint8{0xd9, 0xe0}},
-	Optab{AFCLEX, ynone, Px, [13]uint8{0xdb, 0xe2}},
-	Optab{AFCOS, ynone, Px, [13]uint8{0xd9, 0xff}},
-	Optab{AFDECSTP, ynone, Px, [13]uint8{0xd9, 0xf6}},
-	Optab{AFINCSTP, ynone, Px, [13]uint8{0xd9, 0xf7}},
-	Optab{AFINIT, ynone, Px, [13]uint8{0xdb, 0xe3}},
-	Optab{AFLD1, ynone, Px, [13]uint8{0xd9, 0xe8}},
-	Optab{AFLDL2E, ynone, Px, [13]uint8{0xd9, 0xea}},
-	Optab{AFLDL2T, ynone, Px, [13]uint8{0xd9, 0xe9}},
-	Optab{AFLDLG2, ynone, Px, [13]uint8{0xd9, 0xec}},
-	Optab{AFLDLN2, ynone, Px, [13]uint8{0xd9, 0xed}},
-	Optab{AFLDPI, ynone, Px, [13]uint8{0xd9, 0xeb}},
-	Optab{AFLDZ, ynone, Px, [13]uint8{0xd9, 0xee}},
-	Optab{AFNOP, ynone, Px, [13]uint8{0xd9, 0xd0}},
-	Optab{AFPATAN, ynone, Px, [13]uint8{0xd9, 0xf3}},
-	Optab{AFPREM, ynone, Px, [13]uint8{0xd9, 0xf8}},
-	Optab{AFPREM1, ynone, Px, [13]uint8{0xd9, 0xf5}},
-	Optab{AFPTAN, ynone, Px, [13]uint8{0xd9, 0xf2}},
-	Optab{AFRNDINT, ynone, Px, [13]uint8{0xd9, 0xfc}},
-	Optab{AFSCALE, ynone, Px, [13]uint8{0xd9, 0xfd}},
-	Optab{AFSIN, ynone, Px, [13]uint8{0xd9, 0xfe}},
-	Optab{AFSINCOS, ynone, Px, [13]uint8{0xd9, 0xfb}},
-	Optab{AFSQRT, ynone, Px, [13]uint8{0xd9, 0xfa}},
-	Optab{AFTST, ynone, Px, [13]uint8{0xd9, 0xe4}},
-	Optab{AFXAM, ynone, Px, [13]uint8{0xd9, 0xe5}},
-	Optab{AFXTRACT, ynone, Px, [13]uint8{0xd9, 0xf4}},
-	Optab{AFYL2X, ynone, Px, [13]uint8{0xd9, 0xf1}},
-	Optab{AFYL2XP1, ynone, Px, [13]uint8{0xd9, 0xf9}},
-	Optab{obj.AEND, nil, 0, [13]uint8{}},
-	Optab{ACMPXCHGB, yrb_mb, Pm, [13]uint8{0xb0}},
-	Optab{ACMPXCHGL, yrl_ml, Pm, [13]uint8{0xb1}},
-	Optab{ACMPXCHGW, yrl_ml, Pm, [13]uint8{0xb1}},
-	Optab{ACMPXCHG8B, yscond, Pm, [13]uint8{0xc7, 01}}, // TODO(rsc): yscond is wrong here.
-
-	Optab{ACPUID, ynone, Pm, [13]uint8{0xa2}},
-	Optab{ARDTSC, ynone, Pm, [13]uint8{0x31}},
-	Optab{AXADDB, yrb_mb, Pb, [13]uint8{0x0f, 0xc0}},
-	Optab{AXADDL, yrl_ml, Pm, [13]uint8{0xc1}},
-	Optab{AXADDW, yrl_ml, Pe, [13]uint8{0x0f, 0xc1}},
-	Optab{ACMOVLCC, yml_rl, Pm, [13]uint8{0x43}},
-	Optab{ACMOVLCS, yml_rl, Pm, [13]uint8{0x42}},
-	Optab{ACMOVLEQ, yml_rl, Pm, [13]uint8{0x44}},
-	Optab{ACMOVLGE, yml_rl, Pm, [13]uint8{0x4d}},
-	Optab{ACMOVLGT, yml_rl, Pm, [13]uint8{0x4f}},
-	Optab{ACMOVLHI, yml_rl, Pm, [13]uint8{0x47}},
-	Optab{ACMOVLLE, yml_rl, Pm, [13]uint8{0x4e}},
-	Optab{ACMOVLLS, yml_rl, Pm, [13]uint8{0x46}},
-	Optab{ACMOVLLT, yml_rl, Pm, [13]uint8{0x4c}},
-	Optab{ACMOVLMI, yml_rl, Pm, [13]uint8{0x48}},
-	Optab{ACMOVLNE, yml_rl, Pm, [13]uint8{0x45}},
-	Optab{ACMOVLOC, yml_rl, Pm, [13]uint8{0x41}},
-	Optab{ACMOVLOS, yml_rl, Pm, [13]uint8{0x40}},
-	Optab{ACMOVLPC, yml_rl, Pm, [13]uint8{0x4b}},
-	Optab{ACMOVLPL, yml_rl, Pm, [13]uint8{0x49}},
-	Optab{ACMOVLPS, yml_rl, Pm, [13]uint8{0x4a}},
-	Optab{ACMOVWCC, yml_rl, Pq, [13]uint8{0x43}},
-	Optab{ACMOVWCS, yml_rl, Pq, [13]uint8{0x42}},
-	Optab{ACMOVWEQ, yml_rl, Pq, [13]uint8{0x44}},
-	Optab{ACMOVWGE, yml_rl, Pq, [13]uint8{0x4d}},
-	Optab{ACMOVWGT, yml_rl, Pq, [13]uint8{0x4f}},
-	Optab{ACMOVWHI, yml_rl, Pq, [13]uint8{0x47}},
-	Optab{ACMOVWLE, yml_rl, Pq, [13]uint8{0x4e}},
-	Optab{ACMOVWLS, yml_rl, Pq, [13]uint8{0x46}},
-	Optab{ACMOVWLT, yml_rl, Pq, [13]uint8{0x4c}},
-	Optab{ACMOVWMI, yml_rl, Pq, [13]uint8{0x48}},
-	Optab{ACMOVWNE, yml_rl, Pq, [13]uint8{0x45}},
-	Optab{ACMOVWOC, yml_rl, Pq, [13]uint8{0x41}},
-	Optab{ACMOVWOS, yml_rl, Pq, [13]uint8{0x40}},
-	Optab{ACMOVWPC, yml_rl, Pq, [13]uint8{0x4b}},
-	Optab{ACMOVWPL, yml_rl, Pq, [13]uint8{0x49}},
-	Optab{ACMOVWPS, yml_rl, Pq, [13]uint8{0x4a}},
-	Optab{AFCMOVCC, yfcmv, Px, [13]uint8{0xdb, 00}},
-	Optab{AFCMOVCS, yfcmv, Px, [13]uint8{0xda, 00}},
-	Optab{AFCMOVEQ, yfcmv, Px, [13]uint8{0xda, 01}},
-	Optab{AFCMOVHI, yfcmv, Px, [13]uint8{0xdb, 02}},
-	Optab{AFCMOVLS, yfcmv, Px, [13]uint8{0xda, 02}},
-	Optab{AFCMOVNE, yfcmv, Px, [13]uint8{0xdb, 01}},
-	Optab{AFCMOVNU, yfcmv, Px, [13]uint8{0xdb, 03}},
-	Optab{AFCMOVUN, yfcmv, Px, [13]uint8{0xda, 03}},
-	Optab{ALFENCE, ynone, Pm, [13]uint8{0xae, 0xe8}},
-	Optab{AMFENCE, ynone, Pm, [13]uint8{0xae, 0xf0}},
-	Optab{ASFENCE, ynone, Pm, [13]uint8{0xae, 0xf8}},
-	Optab{AEMMS, ynone, Pm, [13]uint8{0x77}},
-	Optab{APREFETCHT0, yprefetch, Pm, [13]uint8{0x18, 01}},
-	Optab{APREFETCHT1, yprefetch, Pm, [13]uint8{0x18, 02}},
-	Optab{APREFETCHT2, yprefetch, Pm, [13]uint8{0x18, 03}},
-	Optab{APREFETCHNTA, yprefetch, Pm, [13]uint8{0x18, 00}},
-	Optab{ABSWAPL, ybswap, Pm, [13]uint8{0xc8}},
-	Optab{obj.AUNDEF, ynone, Px, [13]uint8{0x0f, 0x0b}},
-	Optab{AADDPD, yxm, Pq, [13]uint8{0x58}},
-	Optab{AADDPS, yxm, Pm, [13]uint8{0x58}},
-	Optab{AADDSD, yxm, Pf2, [13]uint8{0x58}},
-	Optab{AADDSS, yxm, Pf3, [13]uint8{0x58}},
-	Optab{AANDNPD, yxm, Pq, [13]uint8{0x55}},
-	Optab{AANDNPS, yxm, Pm, [13]uint8{0x55}},
-	Optab{AANDPD, yxm, Pq, [13]uint8{0x54}},
-	Optab{AANDPS, yxm, Pq, [13]uint8{0x54}},
-	Optab{ACMPPD, yxcmpi, Px, [13]uint8{Pe, 0xc2}},
-	Optab{ACMPPS, yxcmpi, Pm, [13]uint8{0xc2, 0}},
-	Optab{ACMPSD, yxcmpi, Px, [13]uint8{Pf2, 0xc2}},
-	Optab{ACMPSS, yxcmpi, Px, [13]uint8{Pf3, 0xc2}},
-	Optab{ACOMISD, yxcmp, Pe, [13]uint8{0x2f}},
-	Optab{ACOMISS, yxcmp, Pm, [13]uint8{0x2f}},
-	Optab{ACVTPL2PD, yxcvm2, Px, [13]uint8{Pf3, 0xe6, Pe, 0x2a}},
-	Optab{ACVTPL2PS, yxcvm2, Pm, [13]uint8{0x5b, 0, 0x2a, 0}},
-	Optab{ACVTPD2PL, yxcvm1, Px, [13]uint8{Pf2, 0xe6, Pe, 0x2d}},
-	Optab{ACVTPD2PS, yxm, Pe, [13]uint8{0x5a}},
-	Optab{ACVTPS2PL, yxcvm1, Px, [13]uint8{Pe, 0x5b, Pm, 0x2d}},
-	Optab{ACVTPS2PD, yxm, Pm, [13]uint8{0x5a}},
-	Optab{ACVTSD2SL, yxcvfl, Pf2, [13]uint8{0x2d}},
-	Optab{ACVTSD2SS, yxm, Pf2, [13]uint8{0x5a}},
-	Optab{ACVTSL2SD, yxcvlf, Pf2, [13]uint8{0x2a}},
-	Optab{ACVTSL2SS, yxcvlf, Pf3, [13]uint8{0x2a}},
-	Optab{ACVTSS2SD, yxm, Pf3, [13]uint8{0x5a}},
-	Optab{ACVTSS2SL, yxcvfl, Pf3, [13]uint8{0x2d}},
-	Optab{ACVTTPD2PL, yxcvm1, Px, [13]uint8{Pe, 0xe6, Pe, 0x2c}},
-	Optab{ACVTTPS2PL, yxcvm1, Px, [13]uint8{Pf3, 0x5b, Pm, 0x2c}},
-	Optab{ACVTTSD2SL, yxcvfl, Pf2, [13]uint8{0x2c}},
-	Optab{ACVTTSS2SL, yxcvfl, Pf3, [13]uint8{0x2c}},
-	Optab{ADIVPD, yxm, Pe, [13]uint8{0x5e}},
-	Optab{ADIVPS, yxm, Pm, [13]uint8{0x5e}},
-	Optab{ADIVSD, yxm, Pf2, [13]uint8{0x5e}},
-	Optab{ADIVSS, yxm, Pf3, [13]uint8{0x5e}},
-	Optab{AMASKMOVOU, yxr, Pe, [13]uint8{0xf7}},
-	Optab{AMAXPD, yxm, Pe, [13]uint8{0x5f}},
-	Optab{AMAXPS, yxm, Pm, [13]uint8{0x5f}},
-	Optab{AMAXSD, yxm, Pf2, [13]uint8{0x5f}},
-	Optab{AMAXSS, yxm, Pf3, [13]uint8{0x5f}},
-	Optab{AMINPD, yxm, Pe, [13]uint8{0x5d}},
-	Optab{AMINPS, yxm, Pm, [13]uint8{0x5d}},
-	Optab{AMINSD, yxm, Pf2, [13]uint8{0x5d}},
-	Optab{AMINSS, yxm, Pf3, [13]uint8{0x5d}},
-	Optab{AMOVAPD, yxmov, Pe, [13]uint8{0x28, 0x29}},
-	Optab{AMOVAPS, yxmov, Pm, [13]uint8{0x28, 0x29}},
-	Optab{AMOVO, yxmov, Pe, [13]uint8{0x6f, 0x7f}},
-	Optab{AMOVOU, yxmov, Pf3, [13]uint8{0x6f, 0x7f}},
-	Optab{AMOVHLPS, yxr, Pm, [13]uint8{0x12}},
-	Optab{AMOVHPD, yxmov, Pe, [13]uint8{0x16, 0x17}},
-	Optab{AMOVHPS, yxmov, Pm, [13]uint8{0x16, 0x17}},
-	Optab{AMOVLHPS, yxr, Pm, [13]uint8{0x16}},
-	Optab{AMOVLPD, yxmov, Pe, [13]uint8{0x12, 0x13}},
-	Optab{AMOVLPS, yxmov, Pm, [13]uint8{0x12, 0x13}},
-	Optab{AMOVMSKPD, yxrrl, Pq, [13]uint8{0x50}},
-	Optab{AMOVMSKPS, yxrrl, Pm, [13]uint8{0x50}},
-	Optab{AMOVNTO, yxr_ml, Pe, [13]uint8{0xe7}},
-	Optab{AMOVNTPD, yxr_ml, Pe, [13]uint8{0x2b}},
-	Optab{AMOVNTPS, yxr_ml, Pm, [13]uint8{0x2b}},
-	Optab{AMOVSD, yxmov, Pf2, [13]uint8{0x10, 0x11}},
-	Optab{AMOVSS, yxmov, Pf3, [13]uint8{0x10, 0x11}},
-	Optab{AMOVUPD, yxmov, Pe, [13]uint8{0x10, 0x11}},
-	Optab{AMOVUPS, yxmov, Pm, [13]uint8{0x10, 0x11}},
-	Optab{AMULPD, yxm, Pe, [13]uint8{0x59}},
-	Optab{AMULPS, yxm, Ym, [13]uint8{0x59}},
-	Optab{AMULSD, yxm, Pf2, [13]uint8{0x59}},
-	Optab{AMULSS, yxm, Pf3, [13]uint8{0x59}},
-	Optab{AORPD, yxm, Pq, [13]uint8{0x56}},
-	Optab{AORPS, yxm, Pm, [13]uint8{0x56}},
-	Optab{APADDQ, yxm, Pe, [13]uint8{0xd4}},
-	Optab{APAND, yxm, Pe, [13]uint8{0xdb}},
-	Optab{APCMPEQB, yxmq, Pe, [13]uint8{0x74}},
-	Optab{APMAXSW, yxm, Pe, [13]uint8{0xee}},
-	Optab{APMAXUB, yxm, Pe, [13]uint8{0xde}},
-	Optab{APMINSW, yxm, Pe, [13]uint8{0xea}},
-	Optab{APMINUB, yxm, Pe, [13]uint8{0xda}},
-	Optab{APMOVMSKB, ymskb, Px, [13]uint8{Pe, 0xd7, 0xd7}},
-	Optab{APSADBW, yxm, Pq, [13]uint8{0xf6}},
-	Optab{APSUBB, yxm, Pe, [13]uint8{0xf8}},
-	Optab{APSUBL, yxm, Pe, [13]uint8{0xfa}},
-	Optab{APSUBQ, yxm, Pe, [13]uint8{0xfb}},
-	Optab{APSUBSB, yxm, Pe, [13]uint8{0xe8}},
-	Optab{APSUBSW, yxm, Pe, [13]uint8{0xe9}},
-	Optab{APSUBUSB, yxm, Pe, [13]uint8{0xd8}},
-	Optab{APSUBUSW, yxm, Pe, [13]uint8{0xd9}},
-	Optab{APSUBW, yxm, Pe, [13]uint8{0xf9}},
-	Optab{APUNPCKHQDQ, yxm, Pe, [13]uint8{0x6d}},
-	Optab{APUNPCKLQDQ, yxm, Pe, [13]uint8{0x6c}},
-	Optab{APXOR, yxm, Pe, [13]uint8{0xef}},
-	Optab{ARCPPS, yxm, Pm, [13]uint8{0x53}},
-	Optab{ARCPSS, yxm, Pf3, [13]uint8{0x53}},
-	Optab{ARSQRTPS, yxm, Pm, [13]uint8{0x52}},
-	Optab{ARSQRTSS, yxm, Pf3, [13]uint8{0x52}},
-	Optab{ASQRTPD, yxm, Pe, [13]uint8{0x51}},
-	Optab{ASQRTPS, yxm, Pm, [13]uint8{0x51}},
-	Optab{ASQRTSD, yxm, Pf2, [13]uint8{0x51}},
-	Optab{ASQRTSS, yxm, Pf3, [13]uint8{0x51}},
-	Optab{ASUBPD, yxm, Pe, [13]uint8{0x5c}},
-	Optab{ASUBPS, yxm, Pm, [13]uint8{0x5c}},
-	Optab{ASUBSD, yxm, Pf2, [13]uint8{0x5c}},
-	Optab{ASUBSS, yxm, Pf3, [13]uint8{0x5c}},
-	Optab{AUCOMISD, yxcmp, Pe, [13]uint8{0x2e}},
-	Optab{AUCOMISS, yxcmp, Pm, [13]uint8{0x2e}},
-	Optab{AUNPCKHPD, yxm, Pe, [13]uint8{0x15}},
-	Optab{AUNPCKHPS, yxm, Pm, [13]uint8{0x15}},
-	Optab{AUNPCKLPD, yxm, Pe, [13]uint8{0x14}},
-	Optab{AUNPCKLPS, yxm, Pm, [13]uint8{0x14}},
-	Optab{AXORPD, yxm, Pe, [13]uint8{0x57}},
-	Optab{AXORPS, yxm, Pm, [13]uint8{0x57}},
-	Optab{APSHUFHW, yxshuf, Pf3, [13]uint8{0x70, 00}},
-	Optab{APSHUFL, yxshuf, Pq, [13]uint8{0x70, 00}},
-	Optab{APSHUFLW, yxshuf, Pf2, [13]uint8{0x70, 00}},
-	Optab{AAESENC, yaes, Pq, [13]uint8{0x38, 0xdc, 0}},
-	Optab{APINSRD, yinsrd, Pq, [13]uint8{0x3a, 0x22, 00}},
-	Optab{APSHUFB, ymshufb, Pq, [13]uint8{0x38, 0x00}},
-	Optab{obj.AUSEFIELD, ynop, Px, [13]uint8{0, 0}},
-	Optab{obj.ATYPE, nil, 0, [13]uint8{}},
-	Optab{obj.AFUNCDATA, yfuncdata, Px, [13]uint8{0, 0}},
-	Optab{obj.APCDATA, ypcdata, Px, [13]uint8{0, 0}},
-	Optab{obj.ACHECKNIL, nil, 0, [13]uint8{}},
-	Optab{obj.AVARDEF, nil, 0, [13]uint8{}},
-	Optab{obj.AVARKILL, nil, 0, [13]uint8{}},
-	Optab{obj.ADUFFCOPY, yduff, Px, [13]uint8{0xe8}},
-	Optab{obj.ADUFFZERO, yduff, Px, [13]uint8{0xe8}},
-	Optab{0, nil, 0, [13]uint8{}},
-}
-
-// single-instruction no-ops of various lengths.
-// constructed by hand and disassembled with gdb to verify.
-// see http://www.agner.org/optimize/optimizing_assembly.pdf for discussion.
-var nop = [][16]uint8{
-	[16]uint8{0x90},
-	[16]uint8{0x66, 0x90},
-	[16]uint8{0x0F, 0x1F, 0x00},
-	[16]uint8{0x0F, 0x1F, 0x40, 0x00},
-	[16]uint8{0x0F, 0x1F, 0x44, 0x00, 0x00},
-	[16]uint8{0x66, 0x0F, 0x1F, 0x44, 0x00, 0x00},
-	[16]uint8{0x0F, 0x1F, 0x80, 0x00, 0x00, 0x00, 0x00},
-	[16]uint8{0x0F, 0x1F, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00},
-	[16]uint8{0x66, 0x0F, 0x1F, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00},
-}
-
-// Native Client rejects the repeated 0x66 prefix.
-// {0x66, 0x66, 0x0F, 0x1F, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00},
-func fillnop(p []byte, n int) {
-	var m int
-
-	for n > 0 {
-		m = n
-		if m > len(nop) {
-			m = len(nop)
-		}
-		copy(p[:m], nop[m-1][:m])
-		p = p[m:]
-		n -= m
-	}
-}
-
-func naclpad(ctxt *obj.Link, s *obj.LSym, c int32, pad int32) int32 {
-	obj.Symgrow(ctxt, s, int64(c)+int64(pad))
-	fillnop(s.P[c:], int(pad))
-	return c + pad
-}
-
-func span8(ctxt *obj.Link, s *obj.LSym) {
-	var p *obj.Prog
-	var q *obj.Prog
-	var c int32
-	var v int32
-	var loop int32
-	var bp []byte
-	var n int
-	var m int
-	var i int
-
-	ctxt.Cursym = s
-
-	if s.Text == nil || s.Text.Link == nil {
-		return
-	}
-
-	if ycover[0] == 0 {
-		instinit()
-	}
-
-	for p = s.Text; p != nil; p = p.Link {
-		if p.To.Type == obj.TYPE_BRANCH {
-			if p.Pcond == nil {
-				p.Pcond = p
-			}
-		}
-		if p.As == AADJSP {
-			p.To.Type = obj.TYPE_REG
-			p.To.Reg = REG_SP
-			v = int32(-p.From.Offset)
-			p.From.Offset = int64(v)
-			p.As = AADDL
-			if v < 0 {
-				p.As = ASUBL
-				v = -v
-				p.From.Offset = int64(v)
-			}
-
-			if v == 0 {
-				p.As = obj.ANOP
-			}
-		}
-	}
-
-	for p = s.Text; p != nil; p = p.Link {
-		p.Back = 2 // use short branches first time through
-		q = p.Pcond
-		if q != nil && (q.Back&2 != 0) {
-			p.Back |= 1 // backward jump
-		}
-
-		if p.As == AADJSP {
-			p.To.Type = obj.TYPE_REG
-			p.To.Reg = REG_SP
-			v = int32(-p.From.Offset)
-			p.From.Offset = int64(v)
-			p.As = AADDL
-			if v < 0 {
-				p.As = ASUBL
-				v = -v
-				p.From.Offset = int64(v)
-			}
-
-			if v == 0 {
-				p.As = obj.ANOP
-			}
-		}
-	}
-
-	n = 0
-	for {
-		loop = 0
-		for i = 0; i < len(s.R); i++ {
-			s.R[i] = obj.Reloc{}
-		}
-		s.R = s.R[:0]
-		s.P = s.P[:0]
-		c = 0
-		for p = s.Text; p != nil; p = p.Link {
-			if ctxt.Headtype == obj.Hnacl && p.Isize > 0 {
-				var deferreturn *obj.LSym
-
-				if deferreturn == nil {
-					deferreturn = obj.Linklookup(ctxt, "runtime.deferreturn", 0)
-				}
-
-				// pad everything to avoid crossing 32-byte boundary
-				if c>>5 != (c+int32(p.Isize)-1)>>5 {
-					c = naclpad(ctxt, s, c, -c&31)
-				}
-
-				// pad call deferreturn to start at 32-byte boundary
-				// so that subtracting 5 in jmpdefer will jump back
-				// to that boundary and rerun the call.
-				if p.As == obj.ACALL && p.To.Sym == deferreturn {
-					c = naclpad(ctxt, s, c, -c&31)
-				}
-
-				// pad call to end at 32-byte boundary
-				if p.As == obj.ACALL {
-					c = naclpad(ctxt, s, c, -(c+int32(p.Isize))&31)
-				}
-
-				// the linker treats REP and STOSQ as different instructions
-				// but in fact the REP is a prefix on the STOSQ.
-				// make sure REP has room for 2 more bytes, so that
-				// padding will not be inserted before the next instruction.
-				if p.As == AREP && c>>5 != (c+3-1)>>5 {
-					c = naclpad(ctxt, s, c, -c&31)
-				}
-
-				// same for LOCK.
-				// various instructions follow; the longest is 4 bytes.
-				// give ourselves 8 bytes so as to avoid surprises.
-				if p.As == ALOCK && c>>5 != (c+8-1)>>5 {
-					c = naclpad(ctxt, s, c, -c&31)
-				}
-			}
-
-			p.Pc = int64(c)
-
-			// process forward jumps to p
-			for q = p.Comefrom; q != nil; q = q.Forwd {
-				v = int32(p.Pc - (q.Pc + int64(q.Mark)))
-				if q.Back&2 != 0 { // short
-					if v > 127 {
-						loop++
-						q.Back ^= 2
-					}
-
-					if q.As == AJCXZW {
-						s.P[q.Pc+2] = byte(v)
-					} else {
-						s.P[q.Pc+1] = byte(v)
-					}
-				} else {
-					bp = s.P[q.Pc+int64(q.Mark)-4:]
-					bp[0] = byte(v)
-					bp = bp[1:]
-					bp[0] = byte(v >> 8)
-					bp = bp[1:]
-					bp[0] = byte(v >> 16)
-					bp = bp[1:]
-					bp[0] = byte(v >> 24)
-				}
-			}
-
-			p.Comefrom = nil
-
-			p.Pc = int64(c)
-			asmins(ctxt, p)
-			m = -cap(ctxt.Andptr) + cap(ctxt.And[:])
-			if int(p.Isize) != m {
-				p.Isize = uint8(m)
-				loop++
-			}
-
-			obj.Symgrow(ctxt, s, p.Pc+int64(m))
-			copy(s.P[p.Pc:][:m], ctxt.And[:m])
-			p.Mark = uint16(m)
-			c += int32(m)
-		}
-
-		n++
-		if n > 20 {
-			ctxt.Diag("span must be looping")
-			log.Fatalf("bad code")
-		}
-		if loop == 0 {
-			break
-		}
-	}
-
-	if ctxt.Headtype == obj.Hnacl {
-		c = naclpad(ctxt, s, c, -c&31)
-	}
-	c += -c & (FuncAlign - 1)
-	s.Size = int64(c)
-
-	if false { /* debug['a'] > 1 */
-		fmt.Printf("span1 %s %d (%d tries)\n %.6x", s.Name, s.Size, n, 0)
-		for i = 0; i < len(s.P); i++ {
-			fmt.Printf(" %.2x", s.P[i])
-			if i%16 == 15 {
-				fmt.Printf("\n  %.6x", uint(i+1))
-			}
-		}
-
-		if i%16 != 0 {
-			fmt.Printf("\n")
-		}
-
-		for i = 0; i < len(s.R); i++ {
-			var r *obj.Reloc
-
-			r = &s.R[i]
-			fmt.Printf(" rel %#.4x/%d %s%+d\n", uint32(r.Off), r.Siz, r.Sym.Name, r.Add)
-		}
-	}
-}
-
-func instinit() {
-	var i int
-	var c int
-
-	for i = 1; optab[i].as != 0; i++ {
-		c = int(optab[i].as)
-		if opindex[c] != nil {
-			log.Fatalf("phase error in optab: %d (%v)", i, Aconv(c))
-		}
-		opindex[c] = &optab[i]
-	}
-
-	for i = 0; i < Ymax; i++ {
-		ycover[i*Ymax+i] = 1
-	}
-
-	ycover[Yi0*Ymax+Yi8] = 1
-	ycover[Yi1*Ymax+Yi8] = 1
-
-	ycover[Yi0*Ymax+Yi32] = 1
-	ycover[Yi1*Ymax+Yi32] = 1
-	ycover[Yi8*Ymax+Yi32] = 1
-
-	ycover[Yal*Ymax+Yrb] = 1
-	ycover[Ycl*Ymax+Yrb] = 1
-	ycover[Yax*Ymax+Yrb] = 1
-	ycover[Ycx*Ymax+Yrb] = 1
-	ycover[Yrx*Ymax+Yrb] = 1
-
-	ycover[Yax*Ymax+Yrx] = 1
-	ycover[Ycx*Ymax+Yrx] = 1
-
-	ycover[Yax*Ymax+Yrl] = 1
-	ycover[Ycx*Ymax+Yrl] = 1
-	ycover[Yrx*Ymax+Yrl] = 1
-
-	ycover[Yf0*Ymax+Yrf] = 1
-
-	ycover[Yal*Ymax+Ymb] = 1
-	ycover[Ycl*Ymax+Ymb] = 1
-	ycover[Yax*Ymax+Ymb] = 1
-	ycover[Ycx*Ymax+Ymb] = 1
-	ycover[Yrx*Ymax+Ymb] = 1
-	ycover[Yrb*Ymax+Ymb] = 1
-	ycover[Ym*Ymax+Ymb] = 1
-
-	ycover[Yax*Ymax+Yml] = 1
-	ycover[Ycx*Ymax+Yml] = 1
-	ycover[Yrx*Ymax+Yml] = 1
-	ycover[Yrl*Ymax+Yml] = 1
-	ycover[Ym*Ymax+Yml] = 1
-
-	ycover[Yax*Ymax+Ymm] = 1
-	ycover[Ycx*Ymax+Ymm] = 1
-	ycover[Yrx*Ymax+Ymm] = 1
-	ycover[Yrl*Ymax+Ymm] = 1
-	ycover[Ym*Ymax+Ymm] = 1
-	ycover[Ymr*Ymax+Ymm] = 1
-
-	ycover[Ym*Ymax+Yxm] = 1
-	ycover[Yxr*Ymax+Yxm] = 1
-
-	for i = 0; i < MAXREG; i++ {
-		reg[i] = -1
-		if i >= REG_AL && i <= REG_BH {
-			reg[i] = (i - REG_AL) & 7
-		}
-		if i >= REG_AX && i <= REG_DI {
-			reg[i] = (i - REG_AX) & 7
-		}
-		if i >= REG_F0 && i <= REG_F0+7 {
-			reg[i] = (i - REG_F0) & 7
-		}
-		if i >= REG_X0 && i <= REG_X0+7 {
-			reg[i] = (i - REG_X0) & 7
-		}
-	}
-}
-
-func prefixof(ctxt *obj.Link, a *obj.Addr) int {
-	if a.Type == obj.TYPE_MEM && a.Name == obj.NAME_NONE {
-		switch a.Reg {
-		case REG_CS:
-			return 0x2e
-
-		case REG_DS:
-			return 0x3e
-
-		case REG_ES:
-			return 0x26
-
-		case REG_FS:
-			return 0x64
-
-		case REG_GS:
-			return 0x65
-
-			// NOTE: Systems listed here should be only systems that
-		// support direct TLS references like 8(TLS) implemented as
-		// direct references from FS or GS. Systems that require
-		// the initial-exec model, where you load the TLS base into
-		// a register and then index from that register, do not reach
-		// this code and should not be listed.
-		case REG_TLS:
-			switch ctxt.Headtype {
-			default:
-				log.Fatalf("unknown TLS base register for %s", obj.Headstr(ctxt.Headtype))
-
-			case obj.Hdarwin,
-				obj.Hdragonfly,
-				obj.Hfreebsd,
-				obj.Hnetbsd,
-				obj.Hopenbsd:
-				return 0x65 // GS
-			}
-		}
-	}
-
-	return 0
-}
-
-func oclass(ctxt *obj.Link, p *obj.Prog, a *obj.Addr) int {
-	var v int32
-
-	// TODO(rsc): This special case is for SHRQ $3, AX:DX,
-	// which encodes as SHRQ $32(DX*0), AX.
-	// Similarly SHRQ CX, AX:DX is really SHRQ CX(DX*0), AX.
-	// Change encoding and remove.
-	if (a.Type == obj.TYPE_CONST || a.Type == obj.TYPE_REG) && a.Index != REG_NONE && a.Scale == 0 {
-		return Ycol
-	}
-
-	switch a.Type {
-	case obj.TYPE_NONE:
-		return Ynone
-
-	case obj.TYPE_BRANCH:
-		return Ybr
-
-		// TODO(rsc): Why this is also Ycol is a mystery. Should split the two meanings.
-	case obj.TYPE_INDIR:
-		if a.Name != obj.NAME_NONE && a.Reg == REG_NONE && a.Index == REG_NONE && a.Scale == 0 {
-			return Ycol
-		}
-		return Yxxx
-
-	case obj.TYPE_MEM:
-		return Ym
-
-	case obj.TYPE_ADDR:
-		switch a.Name {
-		case obj.NAME_EXTERN,
-			obj.NAME_STATIC:
-			return Yi32
-
-		case obj.NAME_AUTO,
-			obj.NAME_PARAM:
-			return Yiauto
-		}
-
-		// DUFFZERO/DUFFCOPY encoding forgot to set a->index
-		// and got Yi32 in an earlier version of this code.
-		// Keep doing that until we fix yduff etc.
-		if a.Sym != nil && strings.HasPrefix(a.Sym.Name, "runtime.duff") {
-			return Yi32
-		}
-
-		if a.Sym != nil || a.Name != obj.NAME_NONE {
-			ctxt.Diag("unexpected addr: %v", obj.Dconv(p, a))
-		}
-		fallthrough
-
-		// fall through
-
-	case obj.TYPE_CONST:
-		if a.Sym != nil {
-			ctxt.Diag("TYPE_CONST with symbol: %v", obj.Dconv(p, a))
-		}
-
-		v = int32(a.Offset)
-		if v == 0 {
-			return Yi0
-		}
-		if v == 1 {
-			return Yi1
-		}
-		if v >= -128 && v <= 127 {
-			return Yi8
-		}
-		return Yi32
-
-	case obj.TYPE_TEXTSIZE:
-		return Ytextsize
-	}
-
-	if a.Type != obj.TYPE_REG {
-		ctxt.Diag("unexpected addr1: type=%d %v", a.Type, obj.Dconv(p, a))
-		return Yxxx
-	}
-
-	switch a.Reg {
-	case REG_AL:
-		return Yal
-
-	case REG_AX:
-		return Yax
-
-	case REG_CL,
-		REG_DL,
-		REG_BL,
-		REG_AH,
-		REG_CH,
-		REG_DH,
-		REG_BH:
-		return Yrb
-
-	case REG_CX:
-		return Ycx
-
-	case REG_DX,
-		REG_BX:
-		return Yrx
-
-	case REG_SP,
-		REG_BP,
-		REG_SI,
-		REG_DI:
-		return Yrl
-
-	case REG_F0 + 0:
-		return Yf0
-
-	case REG_F0 + 1,
-		REG_F0 + 2,
-		REG_F0 + 3,
-		REG_F0 + 4,
-		REG_F0 + 5,
-		REG_F0 + 6,
-		REG_F0 + 7:
-		return Yrf
-
-	case REG_X0 + 0,
-		REG_X0 + 1,
-		REG_X0 + 2,
-		REG_X0 + 3,
-		REG_X0 + 4,
-		REG_X0 + 5,
-		REG_X0 + 6,
-		REG_X0 + 7:
-		return Yxr
-
-	case REG_CS:
-		return Ycs
-	case REG_SS:
-		return Yss
-	case REG_DS:
-		return Yds
-	case REG_ES:
-		return Yes
-	case REG_FS:
-		return Yfs
-	case REG_GS:
-		return Ygs
-	case REG_TLS:
-		return Ytls
-
-	case REG_GDTR:
-		return Ygdtr
-	case REG_IDTR:
-		return Yidtr
-	case REG_LDTR:
-		return Yldtr
-	case REG_MSW:
-		return Ymsw
-	case REG_TASK:
-		return Ytask
-
-	case REG_CR + 0:
-		return Ycr0
-	case REG_CR + 1:
-		return Ycr1
-	case REG_CR + 2:
-		return Ycr2
-	case REG_CR + 3:
-		return Ycr3
-	case REG_CR + 4:
-		return Ycr4
-	case REG_CR + 5:
-		return Ycr5
-	case REG_CR + 6:
-		return Ycr6
-	case REG_CR + 7:
-		return Ycr7
-
-	case REG_DR + 0:
-		return Ydr0
-	case REG_DR + 1:
-		return Ydr1
-	case REG_DR + 2:
-		return Ydr2
-	case REG_DR + 3:
-		return Ydr3
-	case REG_DR + 4:
-		return Ydr4
-	case REG_DR + 5:
-		return Ydr5
-	case REG_DR + 6:
-		return Ydr6
-	case REG_DR + 7:
-		return Ydr7
-
-	case REG_TR + 0:
-		return Ytr0
-	case REG_TR + 1:
-		return Ytr1
-	case REG_TR + 2:
-		return Ytr2
-	case REG_TR + 3:
-		return Ytr3
-	case REG_TR + 4:
-		return Ytr4
-	case REG_TR + 5:
-		return Ytr5
-	case REG_TR + 6:
-		return Ytr6
-	case REG_TR + 7:
-		return Ytr7
-	}
-
-	return Yxxx
-}
-
-func asmidx(ctxt *obj.Link, scale int, index int, base int) {
-	var i int
-
-	switch index {
-	default:
-		goto bad
-
-	case obj.TYPE_NONE:
-		i = 4 << 3
-		goto bas
-
-	case REG_AX,
-		REG_CX,
-		REG_DX,
-		REG_BX,
-		REG_BP,
-		REG_SI,
-		REG_DI:
-		i = reg[index] << 3
-	}
-
-	switch scale {
-	default:
-		goto bad
-
-	case 1:
-		break
-
-	case 2:
-		i |= 1 << 6
-
-	case 4:
-		i |= 2 << 6
-
-	case 8:
-		i |= 3 << 6
-	}
-
-bas:
-	switch base {
-	default:
-		goto bad
-
-	case REG_NONE: /* must be mod=00 */
-		i |= 5
-
-	case REG_AX,
-		REG_CX,
-		REG_DX,
-		REG_BX,
-		REG_SP,
-		REG_BP,
-		REG_SI,
-		REG_DI:
-		i |= reg[base]
-	}
-
-	ctxt.Andptr[0] = byte(i)
-	ctxt.Andptr = ctxt.Andptr[1:]
-	return
-
-bad:
-	ctxt.Diag("asmidx: bad address %d,%d,%d", scale, index, base)
-	ctxt.Andptr[0] = 0
-	ctxt.Andptr = ctxt.Andptr[1:]
-	return
-}
-
-func put4(ctxt *obj.Link, v int32) {
-	ctxt.Andptr[0] = byte(v)
-	ctxt.Andptr[1] = byte(v >> 8)
-	ctxt.Andptr[2] = byte(v >> 16)
-	ctxt.Andptr[3] = byte(v >> 24)
-	ctxt.Andptr = ctxt.Andptr[4:]
-}
-
-func relput4(ctxt *obj.Link, p *obj.Prog, a *obj.Addr) {
-	var v int64
-	var rel obj.Reloc
-	var r *obj.Reloc
-
-	v = int64(vaddr(ctxt, p, a, &rel))
-	if rel.Siz != 0 {
-		if rel.Siz != 4 {
-			ctxt.Diag("bad reloc")
-		}
-		r = obj.Addrel(ctxt.Cursym)
-		*r = rel
-		r.Off = int32(p.Pc + int64(-cap(ctxt.Andptr)+cap(ctxt.And[:])))
-	}
-
-	put4(ctxt, int32(v))
-}
-
-func vaddr(ctxt *obj.Link, p *obj.Prog, a *obj.Addr, r *obj.Reloc) int32 {
-	var s *obj.LSym
-
-	if r != nil {
-		*r = obj.Reloc{}
-	}
-
-	switch a.Name {
-	case obj.NAME_STATIC,
-		obj.NAME_EXTERN:
-		s = a.Sym
-		if s != nil {
-			if r == nil {
-				ctxt.Diag("need reloc for %v", obj.Dconv(p, a))
-				log.Fatalf("bad code")
-			}
-
-			r.Type = obj.R_ADDR
-			r.Siz = 4
-			r.Off = -1
-			r.Sym = s
-			r.Add = a.Offset
-			return 0
-		}
-
-		return int32(a.Offset)
-	}
-
-	if (a.Type == obj.TYPE_MEM || a.Type == obj.TYPE_ADDR) && a.Reg == REG_TLS {
-		if r == nil {
-			ctxt.Diag("need reloc for %v", obj.Dconv(p, a))
-			log.Fatalf("bad code")
-		}
-
-		r.Type = obj.R_TLS_LE
-		r.Siz = 4
-		r.Off = -1 // caller must fill in
-		r.Add = a.Offset
-		return 0
-	}
-
-	return int32(a.Offset)
-}
-
-func asmand(ctxt *obj.Link, p *obj.Prog, a *obj.Addr, r int) {
-	var v int32
-	var base int
-	var rel obj.Reloc
-
-	v = int32(a.Offset)
-	rel.Siz = 0
-
-	switch a.Type {
-	case obj.TYPE_ADDR:
-		if a.Name == obj.NAME_NONE {
-			ctxt.Diag("unexpected TYPE_ADDR with NAME_NONE")
-		}
-		if a.Index == REG_TLS {
-			ctxt.Diag("unexpected TYPE_ADDR with index==REG_TLS")
-		}
-		goto bad
-
-	case obj.TYPE_REG:
-		if (a.Reg < REG_AL || REG_F7 < a.Reg) && (a.Reg < REG_X0 || REG_X0+7 < a.Reg) {
-			goto bad
-		}
-		if v != 0 {
-			goto bad
-		}
-		ctxt.Andptr[0] = byte(3<<6 | reg[a.Reg]<<0 | r<<3)
-		ctxt.Andptr = ctxt.Andptr[1:]
-		return
-	}
-
-	if a.Type != obj.TYPE_MEM {
-		goto bad
-	}
-
-	if a.Index != REG_NONE && a.Index != REG_TLS {
-		base = int(a.Reg)
-		switch a.Name {
-		case obj.NAME_EXTERN,
-			obj.NAME_STATIC:
-			base = REG_NONE
-			v = vaddr(ctxt, p, a, &rel)
-
-		case obj.NAME_AUTO,
-			obj.NAME_PARAM:
-			base = REG_SP
-		}
-
-		if base == REG_NONE {
-			ctxt.Andptr[0] = byte(0<<6 | 4<<0 | r<<3)
-			ctxt.Andptr = ctxt.Andptr[1:]
-			asmidx(ctxt, int(a.Scale), int(a.Index), base)
-			goto putrelv
-		}
-
-		if v == 0 && rel.Siz == 0 && base != REG_BP {
-			ctxt.Andptr[0] = byte(0<<6 | 4<<0 | r<<3)
-			ctxt.Andptr = ctxt.Andptr[1:]
-			asmidx(ctxt, int(a.Scale), int(a.Index), base)
-			return
-		}
-
-		if v >= -128 && v < 128 && rel.Siz == 0 {
-			ctxt.Andptr[0] = byte(1<<6 | 4<<0 | r<<3)
-			ctxt.Andptr = ctxt.Andptr[1:]
-			asmidx(ctxt, int(a.Scale), int(a.Index), base)
-			ctxt.Andptr[0] = byte(v)
-			ctxt.Andptr = ctxt.Andptr[1:]
-			return
-		}
-
-		ctxt.Andptr[0] = byte(2<<6 | 4<<0 | r<<3)
-		ctxt.Andptr = ctxt.Andptr[1:]
-		asmidx(ctxt, int(a.Scale), int(a.Index), base)
-		goto putrelv
-	}
-
-	base = int(a.Reg)
-	switch a.Name {
-	case obj.NAME_STATIC,
-		obj.NAME_EXTERN:
-		base = REG_NONE
-		v = vaddr(ctxt, p, a, &rel)
-
-	case obj.NAME_AUTO,
-		obj.NAME_PARAM:
-		base = REG_SP
-	}
-
-	if base == REG_TLS {
-		v = vaddr(ctxt, p, a, &rel)
-	}
-
-	if base == REG_NONE || (REG_CS <= base && base <= REG_GS) || base == REG_TLS {
-		ctxt.Andptr[0] = byte(0<<6 | 5<<0 | r<<3)
-		ctxt.Andptr = ctxt.Andptr[1:]
-		goto putrelv
-	}
-
-	if base == REG_SP {
-		if v == 0 && rel.Siz == 0 {
-			ctxt.Andptr[0] = byte(0<<6 | 4<<0 | r<<3)
-			ctxt.Andptr = ctxt.Andptr[1:]
-			asmidx(ctxt, int(a.Scale), REG_NONE, base)
-			return
-		}
-
-		if v >= -128 && v < 128 && rel.Siz == 0 {
-			ctxt.Andptr[0] = byte(1<<6 | 4<<0 | r<<3)
-			ctxt.Andptr = ctxt.Andptr[1:]
-			asmidx(ctxt, int(a.Scale), REG_NONE, base)
-			ctxt.Andptr[0] = byte(v)
-			ctxt.Andptr = ctxt.Andptr[1:]
-			return
-		}
-
-		ctxt.Andptr[0] = byte(2<<6 | 4<<0 | r<<3)
-		ctxt.Andptr = ctxt.Andptr[1:]
-		asmidx(ctxt, int(a.Scale), REG_NONE, base)
-		goto putrelv
-	}
-
-	if REG_AX <= base && base <= REG_DI {
-		if a.Index == REG_TLS {
-			rel = obj.Reloc{}
-			rel.Type = obj.R_TLS_IE
-			rel.Siz = 4
-			rel.Sym = nil
-			rel.Add = int64(v)
-			v = 0
-		}
-
-		if v == 0 && rel.Siz == 0 && base != REG_BP {
-			ctxt.Andptr[0] = byte(0<<6 | reg[base]<<0 | r<<3)
-			ctxt.Andptr = ctxt.Andptr[1:]
-			return
-		}
-
-		if v >= -128 && v < 128 && rel.Siz == 0 {
-			ctxt.Andptr[0] = byte(1<<6 | reg[base]<<0 | r<<3)
-			ctxt.Andptr[1] = byte(v)
-			ctxt.Andptr = ctxt.Andptr[2:]
-			return
-		}
-
-		ctxt.Andptr[0] = byte(2<<6 | reg[base]<<0 | r<<3)
-		ctxt.Andptr = ctxt.Andptr[1:]
-		goto putrelv
-	}
-
-	goto bad
-
-putrelv:
-	if rel.Siz != 0 {
-		var r *obj.Reloc
-
-		if rel.Siz != 4 {
-			ctxt.Diag("bad rel")
-			goto bad
-		}
-
-		r = obj.Addrel(ctxt.Cursym)
-		*r = rel
-		r.Off = int32(ctxt.Curp.Pc + int64(-cap(ctxt.Andptr)+cap(ctxt.And[:])))
-	}
-
-	put4(ctxt, v)
-	return
-
-bad:
-	ctxt.Diag("asmand: bad address %v", obj.Dconv(p, a))
-	return
-}
-
-const (
-	E = 0xff
-)
-
-var ymovtab = []uint8{
-	/* push */
-	APUSHL,
-	Ycs,
-	Ynone,
-	0,
-	0x0e,
-	E,
-	0,
-	0,
-	APUSHL,
-	Yss,
-	Ynone,
-	0,
-	0x16,
-	E,
-	0,
-	0,
-	APUSHL,
-	Yds,
-	Ynone,
-	0,
-	0x1e,
-	E,
-	0,
-	0,
-	APUSHL,
-	Yes,
-	Ynone,
-	0,
-	0x06,
-	E,
-	0,
-	0,
-	APUSHL,
-	Yfs,
-	Ynone,
-	0,
-	0x0f,
-	0xa0,
-	E,
-	0,
-	APUSHL,
-	Ygs,
-	Ynone,
-	0,
-	0x0f,
-	0xa8,
-	E,
-	0,
-	APUSHW,
-	Ycs,
-	Ynone,
-	0,
-	Pe,
-	0x0e,
-	E,
-	0,
-	APUSHW,
-	Yss,
-	Ynone,
-	0,
-	Pe,
-	0x16,
-	E,
-	0,
-	APUSHW,
-	Yds,
-	Ynone,
-	0,
-	Pe,
-	0x1e,
-	E,
-	0,
-	APUSHW,
-	Yes,
-	Ynone,
-	0,
-	Pe,
-	0x06,
-	E,
-	0,
-	APUSHW,
-	Yfs,
-	Ynone,
-	0,
-	Pe,
-	0x0f,
-	0xa0,
-	E,
-	APUSHW,
-	Ygs,
-	Ynone,
-	0,
-	Pe,
-	0x0f,
-	0xa8,
-	E,
-
-	/* pop */
-	APOPL,
-	Ynone,
-	Yds,
-	0,
-	0x1f,
-	E,
-	0,
-	0,
-	APOPL,
-	Ynone,
-	Yes,
-	0,
-	0x07,
-	E,
-	0,
-	0,
-	APOPL,
-	Ynone,
-	Yss,
-	0,
-	0x17,
-	E,
-	0,
-	0,
-	APOPL,
-	Ynone,
-	Yfs,
-	0,
-	0x0f,
-	0xa1,
-	E,
-	0,
-	APOPL,
-	Ynone,
-	Ygs,
-	0,
-	0x0f,
-	0xa9,
-	E,
-	0,
-	APOPW,
-	Ynone,
-	Yds,
-	0,
-	Pe,
-	0x1f,
-	E,
-	0,
-	APOPW,
-	Ynone,
-	Yes,
-	0,
-	Pe,
-	0x07,
-	E,
-	0,
-	APOPW,
-	Ynone,
-	Yss,
-	0,
-	Pe,
-	0x17,
-	E,
-	0,
-	APOPW,
-	Ynone,
-	Yfs,
-	0,
-	Pe,
-	0x0f,
-	0xa1,
-	E,
-	APOPW,
-	Ynone,
-	Ygs,
-	0,
-	Pe,
-	0x0f,
-	0xa9,
-	E,
-
-	/* mov seg */
-	AMOVW,
-	Yes,
-	Yml,
-	1,
-	0x8c,
-	0,
-	0,
-	0,
-	AMOVW,
-	Ycs,
-	Yml,
-	1,
-	0x8c,
-	1,
-	0,
-	0,
-	AMOVW,
-	Yss,
-	Yml,
-	1,
-	0x8c,
-	2,
-	0,
-	0,
-	AMOVW,
-	Yds,
-	Yml,
-	1,
-	0x8c,
-	3,
-	0,
-	0,
-	AMOVW,
-	Yfs,
-	Yml,
-	1,
-	0x8c,
-	4,
-	0,
-	0,
-	AMOVW,
-	Ygs,
-	Yml,
-	1,
-	0x8c,
-	5,
-	0,
-	0,
-	AMOVW,
-	Yml,
-	Yes,
-	2,
-	0x8e,
-	0,
-	0,
-	0,
-	AMOVW,
-	Yml,
-	Ycs,
-	2,
-	0x8e,
-	1,
-	0,
-	0,
-	AMOVW,
-	Yml,
-	Yss,
-	2,
-	0x8e,
-	2,
-	0,
-	0,
-	AMOVW,
-	Yml,
-	Yds,
-	2,
-	0x8e,
-	3,
-	0,
-	0,
-	AMOVW,
-	Yml,
-	Yfs,
-	2,
-	0x8e,
-	4,
-	0,
-	0,
-	AMOVW,
-	Yml,
-	Ygs,
-	2,
-	0x8e,
-	5,
-	0,
-	0,
-
-	/* mov cr */
-	AMOVL,
-	Ycr0,
-	Yml,
-	3,
-	0x0f,
-	0x20,
-	0,
-	0,
-	AMOVL,
-	Ycr2,
-	Yml,
-	3,
-	0x0f,
-	0x20,
-	2,
-	0,
-	AMOVL,
-	Ycr3,
-	Yml,
-	3,
-	0x0f,
-	0x20,
-	3,
-	0,
-	AMOVL,
-	Ycr4,
-	Yml,
-	3,
-	0x0f,
-	0x20,
-	4,
-	0,
-	AMOVL,
-	Yml,
-	Ycr0,
-	4,
-	0x0f,
-	0x22,
-	0,
-	0,
-	AMOVL,
-	Yml,
-	Ycr2,
-	4,
-	0x0f,
-	0x22,
-	2,
-	0,
-	AMOVL,
-	Yml,
-	Ycr3,
-	4,
-	0x0f,
-	0x22,
-	3,
-	0,
-	AMOVL,
-	Yml,
-	Ycr4,
-	4,
-	0x0f,
-	0x22,
-	4,
-	0,
-
-	/* mov dr */
-	AMOVL,
-	Ydr0,
-	Yml,
-	3,
-	0x0f,
-	0x21,
-	0,
-	0,
-	AMOVL,
-	Ydr6,
-	Yml,
-	3,
-	0x0f,
-	0x21,
-	6,
-	0,
-	AMOVL,
-	Ydr7,
-	Yml,
-	3,
-	0x0f,
-	0x21,
-	7,
-	0,
-	AMOVL,
-	Yml,
-	Ydr0,
-	4,
-	0x0f,
-	0x23,
-	0,
-	0,
-	AMOVL,
-	Yml,
-	Ydr6,
-	4,
-	0x0f,
-	0x23,
-	6,
-	0,
-	AMOVL,
-	Yml,
-	Ydr7,
-	4,
-	0x0f,
-	0x23,
-	7,
-	0,
-
-	/* mov tr */
-	AMOVL,
-	Ytr6,
-	Yml,
-	3,
-	0x0f,
-	0x24,
-	6,
-	0,
-	AMOVL,
-	Ytr7,
-	Yml,
-	3,
-	0x0f,
-	0x24,
-	7,
-	0,
-	AMOVL,
-	Yml,
-	Ytr6,
-	4,
-	0x0f,
-	0x26,
-	6,
-	E,
-	AMOVL,
-	Yml,
-	Ytr7,
-	4,
-	0x0f,
-	0x26,
-	7,
-	E,
-
-	/* lgdt, sgdt, lidt, sidt */
-	AMOVL,
-	Ym,
-	Ygdtr,
-	4,
-	0x0f,
-	0x01,
-	2,
-	0,
-	AMOVL,
-	Ygdtr,
-	Ym,
-	3,
-	0x0f,
-	0x01,
-	0,
-	0,
-	AMOVL,
-	Ym,
-	Yidtr,
-	4,
-	0x0f,
-	0x01,
-	3,
-	0,
-	AMOVL,
-	Yidtr,
-	Ym,
-	3,
-	0x0f,
-	0x01,
-	1,
-	0,
-
-	/* lldt, sldt */
-	AMOVW,
-	Yml,
-	Yldtr,
-	4,
-	0x0f,
-	0x00,
-	2,
-	0,
-	AMOVW,
-	Yldtr,
-	Yml,
-	3,
-	0x0f,
-	0x00,
-	0,
-	0,
-
-	/* lmsw, smsw */
-	AMOVW,
-	Yml,
-	Ymsw,
-	4,
-	0x0f,
-	0x01,
-	6,
-	0,
-	AMOVW,
-	Ymsw,
-	Yml,
-	3,
-	0x0f,
-	0x01,
-	4,
-	0,
-
-	/* ltr, str */
-	AMOVW,
-	Yml,
-	Ytask,
-	4,
-	0x0f,
-	0x00,
-	3,
-	0,
-	AMOVW,
-	Ytask,
-	Yml,
-	3,
-	0x0f,
-	0x00,
-	1,
-	0,
-
-	/* load full pointer */
-	AMOVL,
-	Yml,
-	Ycol,
-	5,
-	0,
-	0,
-	0,
-	0,
-	AMOVW,
-	Yml,
-	Ycol,
-	5,
-	Pe,
-	0,
-	0,
-	0,
-
-	/* double shift */
-	ASHLL,
-	Ycol,
-	Yml,
-	6,
-	0xa4,
-	0xa5,
-	0,
-	0,
-	ASHRL,
-	Ycol,
-	Yml,
-	6,
-	0xac,
-	0xad,
-	0,
-	0,
-
-	/* extra imul */
-	AIMULW,
-	Yml,
-	Yrl,
-	7,
-	Pq,
-	0xaf,
-	0,
-	0,
-	AIMULL,
-	Yml,
-	Yrl,
-	7,
-	Pm,
-	0xaf,
-	0,
-	0,
-
-	/* load TLS base pointer */
-	AMOVL,
-	Ytls,
-	Yrl,
-	8,
-	0,
-	0,
-	0,
-	0,
-	0,
-}
-
-// byteswapreg returns a byte-addressable register (AX, BX, CX, DX)
-// which is not referenced in a.
-// If a is empty, it returns BX to account for MULB-like instructions
-// that might use DX and AX.
-func byteswapreg(ctxt *obj.Link, a *obj.Addr) int {
-	var cana int
-	var canb int
-	var canc int
-	var cand int
-
-	cand = 1
-	canc = cand
-	canb = canc
-	cana = canb
-
-	if a.Type == obj.TYPE_NONE {
-		cand = 0
-		cana = cand
-	}
-
-	if a.Type == obj.TYPE_REG || ((a.Type == obj.TYPE_MEM || a.Type == obj.TYPE_ADDR) && a.Name == obj.NAME_NONE) {
-		switch a.Reg {
-		case REG_NONE:
-			cand = 0
-			cana = cand
-
-		case REG_AX,
-			REG_AL,
-			REG_AH:
-			cana = 0
-
-		case REG_BX,
-			REG_BL,
-			REG_BH:
-			canb = 0
-
-		case REG_CX,
-			REG_CL,
-			REG_CH:
-			canc = 0
-
-		case REG_DX,
-			REG_DL,
-			REG_DH:
-			cand = 0
-		}
-	}
-
-	if a.Type == obj.TYPE_MEM || a.Type == obj.TYPE_ADDR {
-		switch a.Index {
-		case REG_AX:
-			cana = 0
-
-		case REG_BX:
-			canb = 0
-
-		case REG_CX:
-			canc = 0
-
-		case REG_DX:
-			cand = 0
-		}
-	}
-
-	if cana != 0 {
-		return REG_AX
-	}
-	if canb != 0 {
-		return REG_BX
-	}
-	if canc != 0 {
-		return REG_CX
-	}
-	if cand != 0 {
-		return REG_DX
-	}
-
-	ctxt.Diag("impossible byte register")
-	log.Fatalf("bad code")
-	return 0
-}
-
-func subreg(p *obj.Prog, from int, to int) {
-	if false { /* debug['Q'] */
-		fmt.Printf("\n%v\ts/%v/%v/\n", p, Rconv(from), Rconv(to))
-	}
-
-	if int(p.From.Reg) == from {
-		p.From.Reg = int16(to)
-		p.Ft = 0
-	}
-
-	if int(p.To.Reg) == from {
-		p.To.Reg = int16(to)
-		p.Tt = 0
-	}
-
-	if int(p.From.Index) == from {
-		p.From.Index = int16(to)
-		p.Ft = 0
-	}
-
-	if int(p.To.Index) == from {
-		p.To.Index = int16(to)
-		p.Tt = 0
-	}
-
-	if false { /* debug['Q'] */
-		fmt.Printf("%v\n", p)
-	}
-}
-
-func mediaop(ctxt *obj.Link, o *Optab, op int, osize int, z int) int {
-	switch op {
-	case Pm,
-		Pe,
-		Pf2,
-		Pf3:
-		if osize != 1 {
-			if op != Pm {
-				ctxt.Andptr[0] = byte(op)
-				ctxt.Andptr = ctxt.Andptr[1:]
-			}
-			ctxt.Andptr[0] = Pm
-			ctxt.Andptr = ctxt.Andptr[1:]
-			z++
-			op = int(o.op[z])
-			break
-		}
-		fallthrough
-
-	default:
-		if -cap(ctxt.Andptr) == -cap(ctxt.And) || ctxt.And[-cap(ctxt.Andptr)+cap(ctxt.And[:])-1] != Pm {
-			ctxt.Andptr[0] = Pm
-			ctxt.Andptr = ctxt.Andptr[1:]
-		}
-	}
-
-	ctxt.Andptr[0] = byte(op)
-	ctxt.Andptr = ctxt.Andptr[1:]
-	return z
-}
-
-func doasm(ctxt *obj.Link, p *obj.Prog) {
-	var o *Optab
-	var q *obj.Prog
-	var pp obj.Prog
-	var t []byte
-	var z int
-	var op int
-	var ft int
-	var tt int
-	var breg int
-	var v int32
-	var pre int32
-	var rel obj.Reloc
-	var r *obj.Reloc
-	var a *obj.Addr
-	var yt ytab
-
-	ctxt.Curp = p // TODO
-
-	pre = int32(prefixof(ctxt, &p.From))
-
-	if pre != 0 {
-		ctxt.Andptr[0] = byte(pre)
-		ctxt.Andptr = ctxt.Andptr[1:]
-	}
-	pre = int32(prefixof(ctxt, &p.To))
-	if pre != 0 {
-		ctxt.Andptr[0] = byte(pre)
-		ctxt.Andptr = ctxt.Andptr[1:]
-	}
-
-	if p.Ft == 0 {
-		p.Ft = uint8(oclass(ctxt, p, &p.From))
-	}
-	if p.Tt == 0 {
-		p.Tt = uint8(oclass(ctxt, p, &p.To))
-	}
-
-	ft = int(p.Ft) * Ymax
-	tt = int(p.Tt) * Ymax
-	o = opindex[p.As]
-
-	z = 0
-	for _, yt = range o.ytab {
-		if ycover[ft+int(yt.from)] != 0 && ycover[tt+int(yt.to)] != 0 {
-			goto found
-		}
-		z += int(yt.zoffset)
-	}
-	goto domov
-
-found:
-	switch o.prefix {
-	case Pq: /* 16 bit escape and opcode escape */
-		ctxt.Andptr[0] = Pe
-		ctxt.Andptr = ctxt.Andptr[1:]
-
-		ctxt.Andptr[0] = Pm
-		ctxt.Andptr = ctxt.Andptr[1:]
-
-	case Pf2, /* xmm opcode escape */
-		Pf3:
-		ctxt.Andptr[0] = byte(o.prefix)
-		ctxt.Andptr = ctxt.Andptr[1:]
-
-		ctxt.Andptr[0] = Pm
-		ctxt.Andptr = ctxt.Andptr[1:]
-
-	case Pm: /* opcode escape */
-		ctxt.Andptr[0] = Pm
-		ctxt.Andptr = ctxt.Andptr[1:]
-
-	case Pe: /* 16 bit escape */
-		ctxt.Andptr[0] = Pe
-		ctxt.Andptr = ctxt.Andptr[1:]
-
-	case Pb: /* botch */
-		break
-	}
-
-	op = int(o.op[z])
-	switch yt.zcase {
-	default:
-		ctxt.Diag("asmins: unknown z %d %v", yt.zcase, p)
-		return
-
-	case Zpseudo:
-		break
-
-	case Zlit:
-		for ; ; z++ {
-			op = int(o.op[z])
-			if op == 0 {
-				break
-			}
-			ctxt.Andptr[0] = byte(op)
-			ctxt.Andptr = ctxt.Andptr[1:]
-		}
-
-	case Zlitm_r:
-		for ; ; z++ {
-			op = int(o.op[z])
-			if op == 0 {
-				break
-			}
-			ctxt.Andptr[0] = byte(op)
-			ctxt.Andptr = ctxt.Andptr[1:]
-		}
-		asmand(ctxt, p, &p.From, reg[p.To.Reg])
-
-	case Zm_r:
-		ctxt.Andptr[0] = byte(op)
-		ctxt.Andptr = ctxt.Andptr[1:]
-		asmand(ctxt, p, &p.From, reg[p.To.Reg])
-
-	case Zm2_r:
-		ctxt.Andptr[0] = byte(op)
-		ctxt.Andptr = ctxt.Andptr[1:]
-		ctxt.Andptr[0] = byte(o.op[z+1])
-		ctxt.Andptr = ctxt.Andptr[1:]
-		asmand(ctxt, p, &p.From, reg[p.To.Reg])
-
-	case Zm_r_xm:
-		mediaop(ctxt, o, op, int(yt.zoffset), z)
-		asmand(ctxt, p, &p.From, reg[p.To.Reg])
-
-	case Zm_r_i_xm:
-		mediaop(ctxt, o, op, int(yt.zoffset), z)
-		asmand(ctxt, p, &p.From, reg[p.To.Reg])
-		ctxt.Andptr[0] = byte(p.To.Offset)
-		ctxt.Andptr = ctxt.Andptr[1:]
-
-	case Zibm_r:
-		for {
-			tmp2 := z
-			z++
-			op = int(o.op[tmp2])
-			if op == 0 {
-				break
-			}
-			ctxt.Andptr[0] = byte(op)
-			ctxt.Andptr = ctxt.Andptr[1:]
-		}
-		asmand(ctxt, p, &p.From, reg[p.To.Reg])
-		ctxt.Andptr[0] = byte(p.To.Offset)
-		ctxt.Andptr = ctxt.Andptr[1:]
-
-	case Zaut_r:
-		ctxt.Andptr[0] = 0x8d
-		ctxt.Andptr = ctxt.Andptr[1:] /* leal */
-		if p.From.Type != obj.TYPE_ADDR {
-			ctxt.Diag("asmins: Zaut sb type ADDR")
-		}
-		p.From.Type = obj.TYPE_MEM
-		p.Ft = 0
-		asmand(ctxt, p, &p.From, reg[p.To.Reg])
-		p.From.Type = obj.TYPE_ADDR
-		p.Ft = 0
-
-	case Zm_o:
-		ctxt.Andptr[0] = byte(op)
-		ctxt.Andptr = ctxt.Andptr[1:]
-		asmand(ctxt, p, &p.From, int(o.op[z+1]))
-
-	case Zr_m:
-		ctxt.Andptr[0] = byte(op)
-		ctxt.Andptr = ctxt.Andptr[1:]
-		asmand(ctxt, p, &p.To, reg[p.From.Reg])
-
-	case Zr_m_xm:
-		mediaop(ctxt, o, op, int(yt.zoffset), z)
-		asmand(ctxt, p, &p.To, reg[p.From.Reg])
-
-	case Zr_m_i_xm:
-		mediaop(ctxt, o, op, int(yt.zoffset), z)
-		asmand(ctxt, p, &p.To, reg[p.From.Reg])
-		ctxt.Andptr[0] = byte(p.From.Offset)
-		ctxt.Andptr = ctxt.Andptr[1:]
-
-	case Zcallindreg:
-		r = obj.Addrel(ctxt.Cursym)
-		r.Off = int32(p.Pc)
-		r.Type = obj.R_CALLIND
-		r.Siz = 0
-		fallthrough
-
-		// fallthrough
-	case Zo_m:
-		ctxt.Andptr[0] = byte(op)
-		ctxt.Andptr = ctxt.Andptr[1:]
-
-		asmand(ctxt, p, &p.To, int(o.op[z+1]))
-
-	case Zm_ibo:
-		ctxt.Andptr[0] = byte(op)
-		ctxt.Andptr = ctxt.Andptr[1:]
-		asmand(ctxt, p, &p.From, int(o.op[z+1]))
-		ctxt.Andptr[0] = byte(vaddr(ctxt, p, &p.To, nil))
-		ctxt.Andptr = ctxt.Andptr[1:]
-
-	case Zibo_m:
-		ctxt.Andptr[0] = byte(op)
-		ctxt.Andptr = ctxt.Andptr[1:]
-		asmand(ctxt, p, &p.To, int(o.op[z+1]))
-		ctxt.Andptr[0] = byte(vaddr(ctxt, p, &p.From, nil))
-		ctxt.Andptr = ctxt.Andptr[1:]
-
-	case Z_ib,
-		Zib_:
-		if yt.zcase == Zib_ {
-			a = &p.From
-		} else {
-			a = &p.To
-		}
-		v = vaddr(ctxt, p, a, nil)
-		ctxt.Andptr[0] = byte(op)
-		ctxt.Andptr = ctxt.Andptr[1:]
-		ctxt.Andptr[0] = byte(v)
-		ctxt.Andptr = ctxt.Andptr[1:]
-
-	case Zib_rp:
-		ctxt.Andptr[0] = byte(op + reg[p.To.Reg])
-		ctxt.Andptr = ctxt.Andptr[1:]
-		ctxt.Andptr[0] = byte(vaddr(ctxt, p, &p.From, nil))
-		ctxt.Andptr = ctxt.Andptr[1:]
-
-	case Zil_rp:
-		ctxt.Andptr[0] = byte(op + reg[p.To.Reg])
-		ctxt.Andptr = ctxt.Andptr[1:]
-		if o.prefix == Pe {
-			v = vaddr(ctxt, p, &p.From, nil)
-			ctxt.Andptr[0] = byte(v)
-			ctxt.Andptr = ctxt.Andptr[1:]
-			ctxt.Andptr[0] = byte(v >> 8)
-			ctxt.Andptr = ctxt.Andptr[1:]
-		} else {
-			relput4(ctxt, p, &p.From)
-		}
-
-	case Zib_rr:
-		ctxt.Andptr[0] = byte(op)
-		ctxt.Andptr = ctxt.Andptr[1:]
-		asmand(ctxt, p, &p.To, reg[p.To.Reg])
-		ctxt.Andptr[0] = byte(vaddr(ctxt, p, &p.From, nil))
-		ctxt.Andptr = ctxt.Andptr[1:]
-
-	case Z_il,
-		Zil_:
-		if yt.zcase == Zil_ {
-			a = &p.From
-		} else {
-			a = &p.To
-		}
-		ctxt.Andptr[0] = byte(op)
-		ctxt.Andptr = ctxt.Andptr[1:]
-		if o.prefix == Pe {
-			v = vaddr(ctxt, p, a, nil)
-			ctxt.Andptr[0] = byte(v)
-			ctxt.Andptr = ctxt.Andptr[1:]
-			ctxt.Andptr[0] = byte(v >> 8)
-			ctxt.Andptr = ctxt.Andptr[1:]
-		} else {
-			relput4(ctxt, p, a)
-		}
-
-	case Zm_ilo,
-		Zilo_m:
-		ctxt.Andptr[0] = byte(op)
-		ctxt.Andptr = ctxt.Andptr[1:]
-		if yt.zcase == Zilo_m {
-			a = &p.From
-			asmand(ctxt, p, &p.To, int(o.op[z+1]))
-		} else {
-			a = &p.To
-			asmand(ctxt, p, &p.From, int(o.op[z+1]))
-		}
-
-		if o.prefix == Pe {
-			v = vaddr(ctxt, p, a, nil)
-			ctxt.Andptr[0] = byte(v)
-			ctxt.Andptr = ctxt.Andptr[1:]
-			ctxt.Andptr[0] = byte(v >> 8)
-			ctxt.Andptr = ctxt.Andptr[1:]
-		} else {
-			relput4(ctxt, p, a)
-		}
-
-	case Zil_rr:
-		ctxt.Andptr[0] = byte(op)
-		ctxt.Andptr = ctxt.Andptr[1:]
-		asmand(ctxt, p, &p.To, reg[p.To.Reg])
-		if o.prefix == Pe {
-			v = vaddr(ctxt, p, &p.From, nil)
-			ctxt.Andptr[0] = byte(v)
-			ctxt.Andptr = ctxt.Andptr[1:]
-			ctxt.Andptr[0] = byte(v >> 8)
-			ctxt.Andptr = ctxt.Andptr[1:]
-		} else {
-			relput4(ctxt, p, &p.From)
-		}
-
-	case Z_rp:
-		ctxt.Andptr[0] = byte(op + reg[p.To.Reg])
-		ctxt.Andptr = ctxt.Andptr[1:]
-
-	case Zrp_:
-		ctxt.Andptr[0] = byte(op + reg[p.From.Reg])
-		ctxt.Andptr = ctxt.Andptr[1:]
-
-	case Zclr:
-		ctxt.Andptr[0] = byte(op)
-		ctxt.Andptr = ctxt.Andptr[1:]
-		asmand(ctxt, p, &p.To, reg[p.To.Reg])
-
-	case Zcall:
-		if p.To.Sym == nil {
-			ctxt.Diag("call without target")
-			log.Fatalf("bad code")
-		}
-
-		ctxt.Andptr[0] = byte(op)
-		ctxt.Andptr = ctxt.Andptr[1:]
-		r = obj.Addrel(ctxt.Cursym)
-		r.Off = int32(p.Pc + int64(-cap(ctxt.Andptr)+cap(ctxt.And[:])))
-		r.Type = obj.R_CALL
-		r.Siz = 4
-		r.Sym = p.To.Sym
-		r.Add = p.To.Offset
-		put4(ctxt, 0)
-
-	case Zbr,
-		Zjmp,
-		Zloop:
-		if p.To.Sym != nil {
-			if yt.zcase != Zjmp {
-				ctxt.Diag("branch to ATEXT")
-				log.Fatalf("bad code")
-			}
-
-			ctxt.Andptr[0] = byte(o.op[z+1])
-			ctxt.Andptr = ctxt.Andptr[1:]
-			r = obj.Addrel(ctxt.Cursym)
-			r.Off = int32(p.Pc + int64(-cap(ctxt.Andptr)+cap(ctxt.And[:])))
-			r.Sym = p.To.Sym
-			r.Type = obj.R_PCREL
-			r.Siz = 4
-			put4(ctxt, 0)
-			break
-		}
-
-		// Assumes q is in this function.
-		// Fill in backward jump now.
-		q = p.Pcond
-
-		if q == nil {
-			ctxt.Diag("jmp/branch/loop without target")
-			log.Fatalf("bad code")
-		}
-
-		if p.Back&1 != 0 {
-			v = int32(q.Pc - (p.Pc + 2))
-			if v >= -128 {
-				if p.As == AJCXZW {
-					ctxt.Andptr[0] = 0x67
-					ctxt.Andptr = ctxt.Andptr[1:]
-				}
-				ctxt.Andptr[0] = byte(op)
-				ctxt.Andptr = ctxt.Andptr[1:]
-				ctxt.Andptr[0] = byte(v)
-				ctxt.Andptr = ctxt.Andptr[1:]
-			} else if yt.zcase == Zloop {
-				ctxt.Diag("loop too far: %v", p)
-			} else {
-				v -= 5 - 2
-				if yt.zcase == Zbr {
-					ctxt.Andptr[0] = 0x0f
-					ctxt.Andptr = ctxt.Andptr[1:]
-					v--
-				}
-
-				ctxt.Andptr[0] = byte(o.op[z+1])
-				ctxt.Andptr = ctxt.Andptr[1:]
-				ctxt.Andptr[0] = byte(v)
-				ctxt.Andptr = ctxt.Andptr[1:]
-				ctxt.Andptr[0] = byte(v >> 8)
-				ctxt.Andptr = ctxt.Andptr[1:]
-				ctxt.Andptr[0] = byte(v >> 16)
-				ctxt.Andptr = ctxt.Andptr[1:]
-				ctxt.Andptr[0] = byte(v >> 24)
-				ctxt.Andptr = ctxt.Andptr[1:]
-			}
-
-			break
-		}
-
-		// Annotate target; will fill in later.
-		p.Forwd = q.Comefrom
-
-		q.Comefrom = p
-		if p.Back&2 != 0 { // short
-			if p.As == AJCXZW {
-				ctxt.Andptr[0] = 0x67
-				ctxt.Andptr = ctxt.Andptr[1:]
-			}
-			ctxt.Andptr[0] = byte(op)
-			ctxt.Andptr = ctxt.Andptr[1:]
-			ctxt.Andptr[0] = 0
-			ctxt.Andptr = ctxt.Andptr[1:]
-		} else if yt.zcase == Zloop {
-			ctxt.Diag("loop too far: %v", p)
-		} else {
-			if yt.zcase == Zbr {
-				ctxt.Andptr[0] = 0x0f
-				ctxt.Andptr = ctxt.Andptr[1:]
-			}
-			ctxt.Andptr[0] = byte(o.op[z+1])
-			ctxt.Andptr = ctxt.Andptr[1:]
-			ctxt.Andptr[0] = 0
-			ctxt.Andptr = ctxt.Andptr[1:]
-			ctxt.Andptr[0] = 0
-			ctxt.Andptr = ctxt.Andptr[1:]
-			ctxt.Andptr[0] = 0
-			ctxt.Andptr = ctxt.Andptr[1:]
-			ctxt.Andptr[0] = 0
-			ctxt.Andptr = ctxt.Andptr[1:]
-		}
-
-	case Zcallcon,
-		Zjmpcon:
-		if yt.zcase == Zcallcon {
-			ctxt.Andptr[0] = byte(op)
-			ctxt.Andptr = ctxt.Andptr[1:]
-		} else {
-			ctxt.Andptr[0] = byte(o.op[z+1])
-			ctxt.Andptr = ctxt.Andptr[1:]
-		}
-		r = obj.Addrel(ctxt.Cursym)
-		r.Off = int32(p.Pc + int64(-cap(ctxt.Andptr)+cap(ctxt.And[:])))
-		r.Type = obj.R_PCREL
-		r.Siz = 4
-		r.Add = p.To.Offset
-		put4(ctxt, 0)
-
-	case Zcallind:
-		ctxt.Andptr[0] = byte(op)
-		ctxt.Andptr = ctxt.Andptr[1:]
-		ctxt.Andptr[0] = byte(o.op[z+1])
-		ctxt.Andptr = ctxt.Andptr[1:]
-		r = obj.Addrel(ctxt.Cursym)
-		r.Off = int32(p.Pc + int64(-cap(ctxt.Andptr)+cap(ctxt.And[:])))
-		r.Type = obj.R_ADDR
-		r.Siz = 4
-		r.Add = p.To.Offset
-		r.Sym = p.To.Sym
-		put4(ctxt, 0)
-
-	case Zbyte:
-		v = vaddr(ctxt, p, &p.From, &rel)
-		if rel.Siz != 0 {
-			rel.Siz = uint8(op)
-			r = obj.Addrel(ctxt.Cursym)
-			*r = rel
-			r.Off = int32(p.Pc + int64(-cap(ctxt.Andptr)+cap(ctxt.And[:])))
-		}
-
-		ctxt.Andptr[0] = byte(v)
-		ctxt.Andptr = ctxt.Andptr[1:]
-		if op > 1 {
-			ctxt.Andptr[0] = byte(v >> 8)
-			ctxt.Andptr = ctxt.Andptr[1:]
-			if op > 2 {
-				ctxt.Andptr[0] = byte(v >> 16)
-				ctxt.Andptr = ctxt.Andptr[1:]
-				ctxt.Andptr[0] = byte(v >> 24)
-				ctxt.Andptr = ctxt.Andptr[1:]
-			}
-		}
-
-	case Zmov:
-		goto domov
-	}
-
-	return
-
-domov:
-	for t = []byte(ymovtab); t[0] != 0; t = t[8:] {
-		if p.As == int16(t[0]) {
-			if ycover[ft+int(t[1])] != 0 {
-				if ycover[tt+int(t[2])] != 0 {
-					goto mfound
-				}
-			}
-		}
-	}
-
-	/*
-	 * here, the assembly has failed.
-	 * if its a byte instruction that has
-	 * unaddressable registers, try to
-	 * exchange registers and reissue the
-	 * instruction with the operands renamed.
-	 */
-bad:
-	pp = *p
-
-	z = int(p.From.Reg)
-	if p.From.Type == obj.TYPE_REG && z >= REG_BP && z <= REG_DI {
-		breg = byteswapreg(ctxt, &p.To)
-		if breg != REG_AX {
-			ctxt.Andptr[0] = 0x87
-			ctxt.Andptr = ctxt.Andptr[1:] /* xchg lhs,bx */
-			asmand(ctxt, p, &p.From, reg[breg])
-			subreg(&pp, z, breg)
-			doasm(ctxt, &pp)
-			ctxt.Andptr[0] = 0x87
-			ctxt.Andptr = ctxt.Andptr[1:] /* xchg lhs,bx */
-			asmand(ctxt, p, &p.From, reg[breg])
-		} else {
-			ctxt.Andptr[0] = byte(0x90 + reg[z])
-			ctxt.Andptr = ctxt.Andptr[1:] /* xchg lsh,ax */
-			subreg(&pp, z, REG_AX)
-			doasm(ctxt, &pp)
-			ctxt.Andptr[0] = byte(0x90 + reg[z])
-			ctxt.Andptr = ctxt.Andptr[1:] /* xchg lsh,ax */
-		}
-
-		return
-	}
-
-	z = int(p.To.Reg)
-	if p.To.Type == obj.TYPE_REG && z >= REG_BP && z <= REG_DI {
-		breg = byteswapreg(ctxt, &p.From)
-		if breg != REG_AX {
-			ctxt.Andptr[0] = 0x87
-			ctxt.Andptr = ctxt.Andptr[1:] /* xchg rhs,bx */
-			asmand(ctxt, p, &p.To, reg[breg])
-			subreg(&pp, z, breg)
-			doasm(ctxt, &pp)
-			ctxt.Andptr[0] = 0x87
-			ctxt.Andptr = ctxt.Andptr[1:] /* xchg rhs,bx */
-			asmand(ctxt, p, &p.To, reg[breg])
-		} else {
-			ctxt.Andptr[0] = byte(0x90 + reg[z])
-			ctxt.Andptr = ctxt.Andptr[1:] /* xchg rsh,ax */
-			subreg(&pp, z, REG_AX)
-			doasm(ctxt, &pp)
-			ctxt.Andptr[0] = byte(0x90 + reg[z])
-			ctxt.Andptr = ctxt.Andptr[1:] /* xchg rsh,ax */
-		}
-
-		return
-	}
-
-	ctxt.Diag("doasm: notfound t2=%d from=%d to=%d %v", yt.zcase, p.Ft, p.Tt, p)
-	return
-
-mfound:
-	switch t[3] {
-	default:
-		ctxt.Diag("asmins: unknown mov %d %v", t[3], p)
-
-	case 0: /* lit */
-		for z = 4; t[z] != E; z++ {
-			ctxt.Andptr[0] = t[z]
-			ctxt.Andptr = ctxt.Andptr[1:]
-		}
-
-	case 1: /* r,m */
-		ctxt.Andptr[0] = t[4]
-		ctxt.Andptr = ctxt.Andptr[1:]
-
-		asmand(ctxt, p, &p.To, int(t[5]))
-
-	case 2: /* m,r */
-		ctxt.Andptr[0] = t[4]
-		ctxt.Andptr = ctxt.Andptr[1:]
-
-		asmand(ctxt, p, &p.From, int(t[5]))
-
-	case 3: /* r,m - 2op */
-		ctxt.Andptr[0] = t[4]
-		ctxt.Andptr = ctxt.Andptr[1:]
-
-		ctxt.Andptr[0] = t[5]
-		ctxt.Andptr = ctxt.Andptr[1:]
-		asmand(ctxt, p, &p.To, int(t[6]))
-
-	case 4: /* m,r - 2op */
-		ctxt.Andptr[0] = t[4]
-		ctxt.Andptr = ctxt.Andptr[1:]
-
-		ctxt.Andptr[0] = t[5]
-		ctxt.Andptr = ctxt.Andptr[1:]
-		asmand(ctxt, p, &p.From, int(t[6]))
-
-	case 5: /* load full pointer, trash heap */
-		if t[4] != 0 {
-			ctxt.Andptr[0] = t[4]
-			ctxt.Andptr = ctxt.Andptr[1:]
-		}
-		switch p.To.Index {
-		default:
-			goto bad
-
-		case REG_DS:
-			ctxt.Andptr[0] = 0xc5
-			ctxt.Andptr = ctxt.Andptr[1:]
-
-		case REG_SS:
-			ctxt.Andptr[0] = 0x0f
-			ctxt.Andptr = ctxt.Andptr[1:]
-			ctxt.Andptr[0] = 0xb2
-			ctxt.Andptr = ctxt.Andptr[1:]
-
-		case REG_ES:
-			ctxt.Andptr[0] = 0xc4
-			ctxt.Andptr = ctxt.Andptr[1:]
-
-		case REG_FS:
-			ctxt.Andptr[0] = 0x0f
-			ctxt.Andptr = ctxt.Andptr[1:]
-			ctxt.Andptr[0] = 0xb4
-			ctxt.Andptr = ctxt.Andptr[1:]
-
-		case REG_GS:
-			ctxt.Andptr[0] = 0x0f
-			ctxt.Andptr = ctxt.Andptr[1:]
-			ctxt.Andptr[0] = 0xb5
-			ctxt.Andptr = ctxt.Andptr[1:]
-		}
-
-		asmand(ctxt, p, &p.From, reg[p.To.Reg])
-
-	case 6: /* double shift */
-		switch p.From.Type {
-		default:
-			goto bad
-
-		case obj.TYPE_CONST:
-			ctxt.Andptr[0] = 0x0f
-			ctxt.Andptr = ctxt.Andptr[1:]
-			ctxt.Andptr[0] = t[4]
-			ctxt.Andptr = ctxt.Andptr[1:]
-			asmand(ctxt, p, &p.To, reg[p.From.Index])
-			ctxt.Andptr[0] = byte(p.From.Offset)
-			ctxt.Andptr = ctxt.Andptr[1:]
-
-		case obj.TYPE_REG:
-			switch p.From.Reg {
-			default:
-				goto bad
-
-			case REG_CL,
-				REG_CX:
-				ctxt.Andptr[0] = 0x0f
-				ctxt.Andptr = ctxt.Andptr[1:]
-				ctxt.Andptr[0] = t[5]
-				ctxt.Andptr = ctxt.Andptr[1:]
-				asmand(ctxt, p, &p.To, reg[p.From.Index])
-			}
-		}
-
-	case 7: /* imul rm,r */
-		if t[4] == Pq {
-			ctxt.Andptr[0] = Pe
-			ctxt.Andptr = ctxt.Andptr[1:]
-			ctxt.Andptr[0] = Pm
-			ctxt.Andptr = ctxt.Andptr[1:]
-		} else {
-			ctxt.Andptr[0] = t[4]
-			ctxt.Andptr = ctxt.Andptr[1:]
-		}
-		ctxt.Andptr[0] = t[5]
-		ctxt.Andptr = ctxt.Andptr[1:]
-		asmand(ctxt, p, &p.From, reg[p.To.Reg])
-
-		// NOTE: The systems listed here are the ones that use the "TLS initial exec" model,
-	// where you load the TLS base register into a register and then index off that
-	// register to access the actual TLS variables. Systems that allow direct TLS access
-	// are handled in prefixof above and should not be listed here.
-	case 8: /* mov tls, r */
-		switch ctxt.Headtype {
-		default:
-			log.Fatalf("unknown TLS base location for %s", obj.Headstr(ctxt.Headtype))
-
-			// ELF TLS base is 0(GS).
-		case obj.Hlinux,
-			obj.Hnacl:
-			pp.From = p.From
-
-			pp.From.Type = obj.TYPE_MEM
-			pp.From.Reg = REG_GS
-			pp.From.Offset = 0
-			pp.From.Index = REG_NONE
-			pp.From.Scale = 0
-			ctxt.Andptr[0] = 0x65
-			ctxt.Andptr = ctxt.Andptr[1:] // GS
-			ctxt.Andptr[0] = 0x8B
-			ctxt.Andptr = ctxt.Andptr[1:]
-			asmand(ctxt, p, &pp.From, reg[p.To.Reg])
-
-		case obj.Hplan9:
-			if ctxt.Plan9privates == nil {
-				ctxt.Plan9privates = obj.Linklookup(ctxt, "_privates", 0)
-			}
-			pp.From = obj.Addr{}
-			pp.From.Type = obj.TYPE_MEM
-			pp.From.Name = obj.NAME_EXTERN
-			pp.From.Sym = ctxt.Plan9privates
-			pp.From.Offset = 0
-			pp.From.Index = REG_NONE
-			ctxt.Andptr[0] = 0x8B
-			ctxt.Andptr = ctxt.Andptr[1:]
-			asmand(ctxt, p, &pp.From, reg[p.To.Reg])
-
-			// Windows TLS base is always 0x14(FS).
-		case obj.Hwindows:
-			pp.From = p.From
-
-			pp.From.Type = obj.TYPE_MEM
-			pp.From.Reg = REG_FS
-			pp.From.Offset = 0x14
-			pp.From.Index = REG_NONE
-			pp.From.Scale = 0
-			ctxt.Andptr[0] = 0x64
-			ctxt.Andptr = ctxt.Andptr[1:] // FS
-			ctxt.Andptr[0] = 0x8B
-			ctxt.Andptr = ctxt.Andptr[1:]
-			asmand(ctxt, p, &pp.From, reg[p.To.Reg])
-		}
-	}
-}
-
-var naclret = []uint8{
-	0x5d, // POPL BP
-	// 0x8b, 0x7d, 0x00, // MOVL (BP), DI - catch return to invalid address, for debugging
-	0x83,
-	0xe5,
-	0xe0, // ANDL $~31, BP
-	0xff,
-	0xe5, // JMP BP
-}
-
-func asmins(ctxt *obj.Link, p *obj.Prog) {
-	var r *obj.Reloc
-
-	ctxt.Andptr = ctxt.And[:]
-
-	if p.As == obj.AUSEFIELD {
-		r = obj.Addrel(ctxt.Cursym)
-		r.Off = 0
-		r.Sym = p.From.Sym
-		r.Type = obj.R_USEFIELD
-		r.Siz = 0
-		return
-	}
-
-	if ctxt.Headtype == obj.Hnacl {
-		switch p.As {
-		case obj.ARET:
-			copy(ctxt.Andptr, naclret)
-			ctxt.Andptr = ctxt.Andptr[len(naclret):]
-			return
-
-		case obj.ACALL,
-			obj.AJMP:
-			if p.To.Type == obj.TYPE_REG && REG_AX <= p.To.Reg && p.To.Reg <= REG_DI {
-				ctxt.Andptr[0] = 0x83
-				ctxt.Andptr = ctxt.Andptr[1:]
-				ctxt.Andptr[0] = byte(0xe0 | (p.To.Reg - REG_AX))
-				ctxt.Andptr = ctxt.Andptr[1:]
-				ctxt.Andptr[0] = 0xe0
-				ctxt.Andptr = ctxt.Andptr[1:]
-			}
-
-		case AINT:
-			ctxt.Andptr[0] = 0xf4
-			ctxt.Andptr = ctxt.Andptr[1:]
-			return
-		}
-	}
-
-	doasm(ctxt, p)
-	if -cap(ctxt.Andptr) > -cap(ctxt.And[len(ctxt.And):]) {
-		fmt.Printf("and[] is too short - %d byte instruction\n", -cap(ctxt.Andptr)+cap(ctxt.And[:]))
-		log.Fatalf("bad code")
-	}
-}
diff --git a/src/cmd/internal/obj/i386/list8.go b/src/cmd/internal/obj/i386/list8.go
deleted file mode 100644
index 3aef35b..0000000
--- a/src/cmd/internal/obj/i386/list8.go
+++ /dev/null
@@ -1,164 +0,0 @@
-// Inferno utils/8c/list.c
-// http://code.google.com/p/inferno-os/source/browse/utils/8c/list.c
-//
-//	Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
-//	Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
-//	Portions Copyright © 1997-1999 Vita Nuova Limited
-//	Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
-//	Portions Copyright © 2004,2006 Bruce Ellis
-//	Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
-//	Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
-//	Portions Copyright © 2009 The Go Authors.  All rights reserved.
-//
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files (the "Software"), to deal
-// in the Software without restriction, including without limitation the rights
-// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-// copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-// THE SOFTWARE.
-
-package i386
-
-import (
-	"cmd/internal/obj"
-	"fmt"
-)
-
-const (
-	STRINGSZ = 1000
-)
-
-var bigP *obj.Prog
-
-func Pconv(p *obj.Prog) string {
-	var str string
-	var fp string
-
-	switch p.As {
-	case obj.ADATA:
-		str = fmt.Sprintf("%.5d (%v)\t%v\t%v/%d,%v",
-			p.Pc, p.Line(), Aconv(int(p.As)), obj.Dconv(p, &p.From), p.From3.Offset, obj.Dconv(p, &p.To))
-
-	case obj.ATEXT:
-		if p.From3.Offset != 0 {
-			str = fmt.Sprintf("%.5d (%v)\t%v\t%v,%d,%v",
-				p.Pc, p.Line(), Aconv(int(p.As)), obj.Dconv(p, &p.From), p.From3.Offset, obj.Dconv(p, &p.To))
-			break
-		}
-
-		str = fmt.Sprintf("%.5d (%v)\t%v\t%v,%v",
-			p.Pc, p.Line(), Aconv(int(p.As)), obj.Dconv(p, &p.From), obj.Dconv(p, &p.To))
-
-	default:
-		str = fmt.Sprintf("%.5d (%v)\t%v\t%v,%v",
-			p.Pc, p.Line(), Aconv(int(p.As)), obj.Dconv(p, &p.From), obj.Dconv(p, &p.To))
-
-		// TODO(rsc): This special case is for SHRQ $32, AX:DX, which encodes as
-		//	SHRQ $32(DX*0), AX
-		// Remove.
-		if (p.From.Type == obj.TYPE_REG || p.From.Type == obj.TYPE_CONST) && p.From.Index != 0 {
-			str += fmt.Sprintf(":%v", Rconv(int(p.From.Index)))
-		}
-	}
-
-	fp += str
-	return fp
-}
-
-func Aconv(i int) string {
-	return Anames[i]
-}
-
-var Register = []string{
-	"AL", /* [REG_AL] */
-	"CL",
-	"DL",
-	"BL",
-	"AH",
-	"CH",
-	"DH",
-	"BH",
-	"AX", /* [REG_AX] */
-	"CX",
-	"DX",
-	"BX",
-	"SP",
-	"BP",
-	"SI",
-	"DI",
-	"F0", /* [REG_F0] */
-	"F1",
-	"F2",
-	"F3",
-	"F4",
-	"F5",
-	"F6",
-	"F7",
-	"CS", /* [REG_CS] */
-	"SS",
-	"DS",
-	"ES",
-	"FS",
-	"GS",
-	"GDTR", /* [REG_GDTR] */
-	"IDTR", /* [REG_IDTR] */
-	"LDTR", /* [REG_LDTR] */
-	"MSW",  /* [REG_MSW] */
-	"TASK", /* [REG_TASK] */
-	"CR0",  /* [REG_CR] */
-	"CR1",
-	"CR2",
-	"CR3",
-	"CR4",
-	"CR5",
-	"CR6",
-	"CR7",
-	"DR0", /* [REG_DR] */
-	"DR1",
-	"DR2",
-	"DR3",
-	"DR4",
-	"DR5",
-	"DR6",
-	"DR7",
-	"TR0", /* [REG_TR] */
-	"TR1",
-	"TR2",
-	"TR3",
-	"TR4",
-	"TR5",
-	"TR6",
-	"TR7",
-	"X0", /* [REG_X0] */
-	"X1",
-	"X2",
-	"X3",
-	"X4",
-	"X5",
-	"X6",
-	"X7",
-	"TLS",    /* [REG_TLS] */
-	"MAXREG", /* [MAXREG] */
-}
-
-func init() {
-	obj.RegisterRegister(obj.RBase386, obj.RBase386+len(Register), Rconv)
-}
-
-func Rconv(r int) string {
-	if r >= REG_AL && r-REG_AL < len(Register) {
-		return fmt.Sprintf("%s", Register[r-REG_AL])
-	}
-	return fmt.Sprintf("Rgok(%d)", r-obj.RBase386)
-}
diff --git a/src/cmd/internal/obj/i386/obj8.go b/src/cmd/internal/obj/i386/obj8.go
deleted file mode 100644
index 44d27c2..0000000
--- a/src/cmd/internal/obj/i386/obj8.go
+++ /dev/null
@@ -1,925 +0,0 @@
-// Inferno utils/8l/pass.c
-// http://code.google.com/p/inferno-os/source/browse/utils/8l/pass.c
-//
-//	Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
-//	Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
-//	Portions Copyright © 1997-1999 Vita Nuova Limited
-//	Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
-//	Portions Copyright © 2004,2006 Bruce Ellis
-//	Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
-//	Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
-//	Portions Copyright © 2009 The Go Authors.  All rights reserved.
-//
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files (the "Software"), to deal
-// in the Software without restriction, including without limitation the rights
-// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-// copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-// THE SOFTWARE.
-
-package i386
-
-import (
-	"cmd/internal/obj"
-	"encoding/binary"
-	"fmt"
-	"log"
-	"math"
-)
-
-func canuselocaltls(ctxt *obj.Link) bool {
-	switch ctxt.Headtype {
-	case obj.Hlinux,
-		obj.Hnacl,
-		obj.Hplan9,
-		obj.Hwindows:
-		return false
-	}
-
-	return true
-}
-
-func progedit(ctxt *obj.Link, p *obj.Prog) {
-	var literal string
-	var s *obj.LSym
-	var q *obj.Prog
-
-	// See obj6.c for discussion of TLS.
-	if canuselocaltls(ctxt) {
-		// Reduce TLS initial exec model to TLS local exec model.
-		// Sequences like
-		//	MOVL TLS, BX
-		//	... off(BX)(TLS*1) ...
-		// become
-		//	NOP
-		//	... off(TLS) ...
-		if p.As == AMOVL && p.From.Type == obj.TYPE_REG && p.From.Reg == REG_TLS && p.To.Type == obj.TYPE_REG && REG_AX <= p.To.Reg && p.To.Reg <= REG_DI {
-			p.As = obj.ANOP
-			p.From.Type = obj.TYPE_NONE
-			p.To.Type = obj.TYPE_NONE
-		}
-
-		if p.From.Type == obj.TYPE_MEM && p.From.Index == REG_TLS && REG_AX <= p.From.Reg && p.From.Reg <= REG_DI {
-			p.From.Type = obj.TYPE_MEM
-			p.From.Reg = REG_TLS
-			p.From.Scale = 0
-			p.From.Index = REG_NONE
-		}
-
-		if p.To.Type == obj.TYPE_MEM && p.To.Index == REG_TLS && REG_AX <= p.To.Reg && p.To.Reg <= REG_DI {
-			p.To.Type = obj.TYPE_MEM
-			p.To.Reg = REG_TLS
-			p.To.Scale = 0
-			p.To.Index = REG_NONE
-		}
-	} else {
-		// As a courtesy to the C compilers, rewrite TLS local exec load as TLS initial exec load.
-		// The instruction
-		//	MOVL off(TLS), BX
-		// becomes the sequence
-		//	MOVL TLS, BX
-		//	MOVL off(BX)(TLS*1), BX
-		// This allows the C compilers to emit references to m and g using the direct off(TLS) form.
-		if p.As == AMOVL && p.From.Type == obj.TYPE_MEM && p.From.Reg == REG_TLS && p.To.Type == obj.TYPE_REG && REG_AX <= p.To.Reg && p.To.Reg <= REG_DI {
-			q = obj.Appendp(ctxt, p)
-			q.As = p.As
-			q.From.Type = obj.TYPE_MEM
-			q.From.Reg = p.To.Reg
-			q.From.Index = REG_TLS
-			q.From.Scale = 2 // TODO: use 1
-			q.To = p.To
-			p.From.Type = obj.TYPE_REG
-			p.From.Reg = REG_TLS
-			p.From.Index = REG_NONE
-			p.From.Offset = 0
-		}
-	}
-
-	// TODO: Remove.
-	if ctxt.Headtype == obj.Hplan9 {
-		if p.From.Scale == 1 && p.From.Index == REG_TLS {
-			p.From.Scale = 2
-		}
-		if p.To.Scale == 1 && p.To.Index == REG_TLS {
-			p.To.Scale = 2
-		}
-	}
-
-	// Rewrite CALL/JMP/RET to symbol as TYPE_BRANCH.
-	switch p.As {
-	case obj.ACALL,
-		obj.AJMP,
-		obj.ARET:
-		if p.To.Type == obj.TYPE_MEM && (p.To.Name == obj.NAME_EXTERN || p.To.Name == obj.NAME_STATIC) && p.To.Sym != nil {
-			p.To.Type = obj.TYPE_BRANCH
-		}
-	}
-
-	// Rewrite float constants to values stored in memory.
-	switch p.As {
-	// Convert AMOVSS $(0), Xx to AXORPS Xx, Xx
-	case AMOVSS:
-		if p.From.Type == obj.TYPE_FCONST {
-			if p.From.U.Dval == 0 {
-				if p.To.Type == obj.TYPE_REG && REG_X0 <= p.To.Reg && p.To.Reg <= REG_X7 {
-					p.As = AXORPS
-					p.From = p.To
-					break
-				}
-			}
-		}
-		fallthrough
-
-		// fallthrough
-
-	case AFMOVF,
-		AFADDF,
-		AFSUBF,
-		AFSUBRF,
-		AFMULF,
-		AFDIVF,
-		AFDIVRF,
-		AFCOMF,
-		AFCOMFP,
-		AADDSS,
-		ASUBSS,
-		AMULSS,
-		ADIVSS,
-		ACOMISS,
-		AUCOMISS:
-		if p.From.Type == obj.TYPE_FCONST {
-			var i32 uint32
-			var f32 float32
-			f32 = float32(p.From.U.Dval)
-			i32 = math.Float32bits(f32)
-			literal = fmt.Sprintf("$f32.%08x", i32)
-			s = obj.Linklookup(ctxt, literal, 0)
-			if s.Type == 0 {
-				s.Type = obj.SRODATA
-				obj.Adduint32(ctxt, s, i32)
-				s.Reachable = 0
-			}
-
-			p.From.Type = obj.TYPE_MEM
-			p.From.Name = obj.NAME_EXTERN
-			p.From.Sym = s
-			p.From.Offset = 0
-		}
-
-		// Convert AMOVSD $(0), Xx to AXORPS Xx, Xx
-	case AMOVSD:
-		if p.From.Type == obj.TYPE_FCONST {
-			if p.From.U.Dval == 0 {
-				if p.To.Type == obj.TYPE_REG && REG_X0 <= p.To.Reg && p.To.Reg <= REG_X7 {
-					p.As = AXORPS
-					p.From = p.To
-					break
-				}
-			}
-		}
-		fallthrough
-
-		// fallthrough
-
-	case AFMOVD,
-		AFADDD,
-		AFSUBD,
-		AFSUBRD,
-		AFMULD,
-		AFDIVD,
-		AFDIVRD,
-		AFCOMD,
-		AFCOMDP,
-		AADDSD,
-		ASUBSD,
-		AMULSD,
-		ADIVSD,
-		ACOMISD,
-		AUCOMISD:
-		if p.From.Type == obj.TYPE_FCONST {
-			var i64 uint64
-			i64 = math.Float64bits(p.From.U.Dval)
-			literal = fmt.Sprintf("$f64.%016x", i64)
-			s = obj.Linklookup(ctxt, literal, 0)
-			if s.Type == 0 {
-				s.Type = obj.SRODATA
-				obj.Adduint64(ctxt, s, i64)
-				s.Reachable = 0
-			}
-
-			p.From.Type = obj.TYPE_MEM
-			p.From.Name = obj.NAME_EXTERN
-			p.From.Sym = s
-			p.From.Offset = 0
-		}
-	}
-}
-
-func preprocess(ctxt *obj.Link, cursym *obj.LSym) {
-	var p *obj.Prog
-	var q *obj.Prog
-	var p1 *obj.Prog
-	var p2 *obj.Prog
-	var autoffset int32
-	var deltasp int32
-	var a int
-
-	if ctxt.Symmorestack[0] == nil {
-		ctxt.Symmorestack[0] = obj.Linklookup(ctxt, "runtime.morestack", 0)
-		ctxt.Symmorestack[1] = obj.Linklookup(ctxt, "runtime.morestack_noctxt", 0)
-	}
-
-	if ctxt.Headtype == obj.Hplan9 && ctxt.Plan9privates == nil {
-		ctxt.Plan9privates = obj.Linklookup(ctxt, "_privates", 0)
-	}
-
-	ctxt.Cursym = cursym
-
-	if cursym.Text == nil || cursym.Text.Link == nil {
-		return
-	}
-
-	p = cursym.Text
-	autoffset = int32(p.To.Offset)
-	if autoffset < 0 {
-		autoffset = 0
-	}
-
-	cursym.Locals = autoffset
-	cursym.Args = p.To.U.Argsize
-
-	q = nil
-
-	if p.From3.Offset&obj.NOSPLIT == 0 || (p.From3.Offset&obj.WRAPPER != 0) {
-		p = obj.Appendp(ctxt, p)
-		p = load_g_cx(ctxt, p) // load g into CX
-	}
-
-	if cursym.Text.From3.Offset&obj.NOSPLIT == 0 {
-		p = stacksplit(ctxt, p, autoffset, cursym.Text.From3.Offset&obj.NEEDCTXT == 0, &q) // emit split check
-	}
-
-	if autoffset != 0 {
-		p = obj.Appendp(ctxt, p)
-		p.As = AADJSP
-		p.From.Type = obj.TYPE_CONST
-		p.From.Offset = int64(autoffset)
-		p.Spadj = autoffset
-	} else {
-		// zero-byte stack adjustment.
-		// Insert a fake non-zero adjustment so that stkcheck can
-		// recognize the end of the stack-splitting prolog.
-		p = obj.Appendp(ctxt, p)
-
-		p.As = obj.ANOP
-		p.Spadj = int32(-ctxt.Arch.Ptrsize)
-		p = obj.Appendp(ctxt, p)
-		p.As = obj.ANOP
-		p.Spadj = int32(ctxt.Arch.Ptrsize)
-	}
-
-	if q != nil {
-		q.Pcond = p
-	}
-	deltasp = autoffset
-
-	if cursym.Text.From3.Offset&obj.WRAPPER != 0 {
-		// if(g->panic != nil && g->panic->argp == FP) g->panic->argp = bottom-of-frame
-		//
-		//	MOVL g_panic(CX), BX
-		//	TESTL BX, BX
-		//	JEQ end
-		//	LEAL (autoffset+4)(SP), DI
-		//	CMPL panic_argp(BX), DI
-		//	JNE end
-		//	MOVL SP, panic_argp(BX)
-		// end:
-		//	NOP
-		//
-		// The NOP is needed to give the jumps somewhere to land.
-		// It is a liblink NOP, not an x86 NOP: it encodes to 0 instruction bytes.
-
-		p = obj.Appendp(ctxt, p)
-
-		p.As = AMOVL
-		p.From.Type = obj.TYPE_MEM
-		p.From.Reg = REG_CX
-		p.From.Offset = 4 * int64(ctxt.Arch.Ptrsize) // G.panic
-		p.To.Type = obj.TYPE_REG
-		p.To.Reg = REG_BX
-
-		p = obj.Appendp(ctxt, p)
-		p.As = ATESTL
-		p.From.Type = obj.TYPE_REG
-		p.From.Reg = REG_BX
-		p.To.Type = obj.TYPE_REG
-		p.To.Reg = REG_BX
-
-		p = obj.Appendp(ctxt, p)
-		p.As = AJEQ
-		p.To.Type = obj.TYPE_BRANCH
-		p1 = p
-
-		p = obj.Appendp(ctxt, p)
-		p.As = ALEAL
-		p.From.Type = obj.TYPE_MEM
-		p.From.Reg = REG_SP
-		p.From.Offset = int64(autoffset) + 4
-		p.To.Type = obj.TYPE_REG
-		p.To.Reg = REG_DI
-
-		p = obj.Appendp(ctxt, p)
-		p.As = ACMPL
-		p.From.Type = obj.TYPE_MEM
-		p.From.Reg = REG_BX
-		p.From.Offset = 0 // Panic.argp
-		p.To.Type = obj.TYPE_REG
-		p.To.Reg = REG_DI
-
-		p = obj.Appendp(ctxt, p)
-		p.As = AJNE
-		p.To.Type = obj.TYPE_BRANCH
-		p2 = p
-
-		p = obj.Appendp(ctxt, p)
-		p.As = AMOVL
-		p.From.Type = obj.TYPE_REG
-		p.From.Reg = REG_SP
-		p.To.Type = obj.TYPE_MEM
-		p.To.Reg = REG_BX
-		p.To.Offset = 0 // Panic.argp
-
-		p = obj.Appendp(ctxt, p)
-
-		p.As = obj.ANOP
-		p1.Pcond = p
-		p2.Pcond = p
-	}
-
-	if ctxt.Debugzerostack != 0 && autoffset != 0 && cursym.Text.From3.Offset&obj.NOSPLIT == 0 {
-		// 8l -Z means zero the stack frame on entry.
-		// This slows down function calls but can help avoid
-		// false positives in garbage collection.
-		p = obj.Appendp(ctxt, p)
-
-		p.As = AMOVL
-		p.From.Type = obj.TYPE_REG
-		p.From.Reg = REG_SP
-		p.To.Type = obj.TYPE_REG
-		p.To.Reg = REG_DI
-
-		p = obj.Appendp(ctxt, p)
-		p.As = AMOVL
-		p.From.Type = obj.TYPE_CONST
-		p.From.Offset = int64(autoffset) / 4
-		p.To.Type = obj.TYPE_REG
-		p.To.Reg = REG_CX
-
-		p = obj.Appendp(ctxt, p)
-		p.As = AMOVL
-		p.From.Type = obj.TYPE_CONST
-		p.From.Offset = 0
-		p.To.Type = obj.TYPE_REG
-		p.To.Reg = REG_AX
-
-		p = obj.Appendp(ctxt, p)
-		p.As = AREP
-
-		p = obj.Appendp(ctxt, p)
-		p.As = ASTOSL
-	}
-
-	for ; p != nil; p = p.Link {
-		a = int(p.From.Name)
-		if a == obj.NAME_AUTO {
-			p.From.Offset += int64(deltasp)
-		}
-		if a == obj.NAME_PARAM {
-			p.From.Offset += int64(deltasp) + 4
-		}
-		a = int(p.To.Name)
-		if a == obj.NAME_AUTO {
-			p.To.Offset += int64(deltasp)
-		}
-		if a == obj.NAME_PARAM {
-			p.To.Offset += int64(deltasp) + 4
-		}
-
-		switch p.As {
-		default:
-			continue
-
-		case APUSHL,
-			APUSHFL:
-			deltasp += 4
-			p.Spadj = 4
-			continue
-
-		case APUSHW,
-			APUSHFW:
-			deltasp += 2
-			p.Spadj = 2
-			continue
-
-		case APOPL,
-			APOPFL:
-			deltasp -= 4
-			p.Spadj = -4
-			continue
-
-		case APOPW,
-			APOPFW:
-			deltasp -= 2
-			p.Spadj = -2
-			continue
-
-		case obj.ARET:
-			break
-		}
-
-		if autoffset != deltasp {
-			ctxt.Diag("unbalanced PUSH/POP")
-		}
-
-		if autoffset != 0 {
-			p.As = AADJSP
-			p.From.Type = obj.TYPE_CONST
-			p.From.Offset = int64(-autoffset)
-			p.Spadj = -autoffset
-			p = obj.Appendp(ctxt, p)
-			p.As = obj.ARET
-
-			// If there are instructions following
-			// this ARET, they come from a branch
-			// with the same stackframe, so undo
-			// the cleanup.
-			p.Spadj = +autoffset
-		}
-
-		if p.To.Sym != nil { // retjmp
-			p.As = obj.AJMP
-		}
-	}
-}
-
-// Append code to p to load g into cx.
-// Overwrites p with the first instruction (no first appendp).
-// Overwriting p is unusual but it lets use this in both the
-// prologue (caller must call appendp first) and in the epilogue.
-// Returns last new instruction.
-func load_g_cx(ctxt *obj.Link, p *obj.Prog) *obj.Prog {
-	var next *obj.Prog
-
-	p.As = AMOVL
-	p.From.Type = obj.TYPE_MEM
-	p.From.Reg = REG_TLS
-	p.From.Offset = 0
-	p.To.Type = obj.TYPE_REG
-	p.To.Reg = REG_CX
-
-	next = p.Link
-	progedit(ctxt, p)
-	for p.Link != next {
-		p = p.Link
-	}
-
-	if p.From.Index == REG_TLS {
-		p.From.Scale = 2
-	}
-
-	return p
-}
-
-// Append code to p to check for stack split.
-// Appends to (does not overwrite) p.
-// Assumes g is in CX.
-// Returns last new instruction.
-// On return, *jmpok is the instruction that should jump
-// to the stack frame allocation if no split is needed.
-func stacksplit(ctxt *obj.Link, p *obj.Prog, framesize int32, noctxt bool, jmpok **obj.Prog) *obj.Prog {
-	var q *obj.Prog
-	var q1 *obj.Prog
-
-	if ctxt.Debugstack != 0 {
-		// 8l -K means check not only for stack
-		// overflow but stack underflow.
-		// On underflow, INT 3 (breakpoint).
-		// Underflow itself is rare but this also
-		// catches out-of-sync stack guard info.
-		p = obj.Appendp(ctxt, p)
-
-		p.As = ACMPL
-		p.From.Type = obj.TYPE_MEM
-		p.From.Reg = REG_CX
-		p.From.Offset = 4
-		p.To.Type = obj.TYPE_REG
-		p.To.Reg = REG_SP
-
-		p = obj.Appendp(ctxt, p)
-		p.As = AJCC
-		p.To.Type = obj.TYPE_BRANCH
-		p.To.Offset = 4
-		q1 = p
-
-		p = obj.Appendp(ctxt, p)
-		p.As = AINT
-		p.From.Type = obj.TYPE_CONST
-		p.From.Offset = 3
-
-		p = obj.Appendp(ctxt, p)
-		p.As = obj.ANOP
-		q1.Pcond = p
-	}
-
-	q1 = nil
-
-	if framesize <= obj.StackSmall {
-		// small stack: SP <= stackguard
-		//	CMPL SP, stackguard
-		p = obj.Appendp(ctxt, p)
-
-		p.As = ACMPL
-		p.From.Type = obj.TYPE_REG
-		p.From.Reg = REG_SP
-		p.To.Type = obj.TYPE_MEM
-		p.To.Reg = REG_CX
-		p.To.Offset = 2 * int64(ctxt.Arch.Ptrsize) // G.stackguard0
-		if ctxt.Cursym.Cfunc != 0 {
-			p.To.Offset = 3 * int64(ctxt.Arch.Ptrsize) // G.stackguard1
-		}
-	} else if framesize <= obj.StackBig {
-		// large stack: SP-framesize <= stackguard-StackSmall
-		//	LEAL -(framesize-StackSmall)(SP), AX
-		//	CMPL AX, stackguard
-		p = obj.Appendp(ctxt, p)
-
-		p.As = ALEAL
-		p.From.Type = obj.TYPE_MEM
-		p.From.Reg = REG_SP
-		p.From.Offset = -(int64(framesize) - obj.StackSmall)
-		p.To.Type = obj.TYPE_REG
-		p.To.Reg = REG_AX
-
-		p = obj.Appendp(ctxt, p)
-		p.As = ACMPL
-		p.From.Type = obj.TYPE_REG
-		p.From.Reg = REG_AX
-		p.To.Type = obj.TYPE_MEM
-		p.To.Reg = REG_CX
-		p.To.Offset = 2 * int64(ctxt.Arch.Ptrsize) // G.stackguard0
-		if ctxt.Cursym.Cfunc != 0 {
-			p.To.Offset = 3 * int64(ctxt.Arch.Ptrsize) // G.stackguard1
-		}
-	} else {
-		// Such a large stack we need to protect against wraparound
-		// if SP is close to zero.
-		//	SP-stackguard+StackGuard <= framesize + (StackGuard-StackSmall)
-		// The +StackGuard on both sides is required to keep the left side positive:
-		// SP is allowed to be slightly below stackguard. See stack.h.
-		//
-		// Preemption sets stackguard to StackPreempt, a very large value.
-		// That breaks the math above, so we have to check for that explicitly.
-		//	MOVL	stackguard, CX
-		//	CMPL	CX, $StackPreempt
-		//	JEQ	label-of-call-to-morestack
-		//	LEAL	StackGuard(SP), AX
-		//	SUBL	stackguard, AX
-		//	CMPL	AX, $(framesize+(StackGuard-StackSmall))
-		p = obj.Appendp(ctxt, p)
-
-		p.As = AMOVL
-		p.From.Type = obj.TYPE_MEM
-		p.From.Reg = REG_CX
-		p.From.Offset = 0
-		p.From.Offset = 2 * int64(ctxt.Arch.Ptrsize) // G.stackguard0
-		if ctxt.Cursym.Cfunc != 0 {
-			p.From.Offset = 3 * int64(ctxt.Arch.Ptrsize) // G.stackguard1
-		}
-		p.To.Type = obj.TYPE_REG
-		p.To.Reg = REG_SI
-
-		p = obj.Appendp(ctxt, p)
-		p.As = ACMPL
-		p.From.Type = obj.TYPE_REG
-		p.From.Reg = REG_SI
-		p.To.Type = obj.TYPE_CONST
-		p.To.Offset = int64(uint32(obj.StackPreempt & (1<<32 - 1)))
-
-		p = obj.Appendp(ctxt, p)
-		p.As = AJEQ
-		p.To.Type = obj.TYPE_BRANCH
-		q1 = p
-
-		p = obj.Appendp(ctxt, p)
-		p.As = ALEAL
-		p.From.Type = obj.TYPE_MEM
-		p.From.Reg = REG_SP
-		p.From.Offset = obj.StackGuard
-		p.To.Type = obj.TYPE_REG
-		p.To.Reg = REG_AX
-
-		p = obj.Appendp(ctxt, p)
-		p.As = ASUBL
-		p.From.Type = obj.TYPE_REG
-		p.From.Reg = REG_SI
-		p.From.Offset = 0
-		p.To.Type = obj.TYPE_REG
-		p.To.Reg = REG_AX
-
-		p = obj.Appendp(ctxt, p)
-		p.As = ACMPL
-		p.From.Type = obj.TYPE_REG
-		p.From.Reg = REG_AX
-		p.To.Type = obj.TYPE_CONST
-		p.To.Offset = int64(framesize) + (obj.StackGuard - obj.StackSmall)
-	}
-
-	// common
-	p = obj.Appendp(ctxt, p)
-
-	p.As = AJHI
-	p.To.Type = obj.TYPE_BRANCH
-	p.To.Offset = 4
-	q = p
-
-	p = obj.Appendp(ctxt, p)
-	p.As = obj.ACALL
-	p.To.Type = obj.TYPE_BRANCH
-	if ctxt.Cursym.Cfunc != 0 {
-		p.To.Sym = obj.Linklookup(ctxt, "runtime.morestackc", 0)
-	} else {
-		p.To.Sym = ctxt.Symmorestack[bool2int(noctxt)]
-	}
-
-	p = obj.Appendp(ctxt, p)
-	p.As = obj.AJMP
-	p.To.Type = obj.TYPE_BRANCH
-	p.Pcond = ctxt.Cursym.Text.Link
-
-	if q != nil {
-		q.Pcond = p.Link
-	}
-	if q1 != nil {
-		q1.Pcond = q.Link
-	}
-
-	*jmpok = q
-	return p
-}
-
-func follow(ctxt *obj.Link, s *obj.LSym) {
-	var firstp *obj.Prog
-	var lastp *obj.Prog
-
-	ctxt.Cursym = s
-
-	firstp = ctxt.NewProg()
-	lastp = firstp
-	xfol(ctxt, s.Text, &lastp)
-	lastp.Link = nil
-	s.Text = firstp.Link
-}
-
-func nofollow(a int) bool {
-	switch a {
-	case obj.AJMP,
-		obj.ARET,
-		AIRETL,
-		AIRETW,
-		obj.AUNDEF:
-		return true
-	}
-
-	return false
-}
-
-func pushpop(a int) bool {
-	switch a {
-	case APUSHL,
-		APUSHFL,
-		APUSHW,
-		APUSHFW,
-		APOPL,
-		APOPFL,
-		APOPW,
-		APOPFW:
-		return true
-	}
-
-	return false
-}
-
-func relinv(a int) int {
-	switch a {
-	case AJEQ:
-		return AJNE
-	case AJNE:
-		return AJEQ
-	case AJLE:
-		return AJGT
-	case AJLS:
-		return AJHI
-	case AJLT:
-		return AJGE
-	case AJMI:
-		return AJPL
-	case AJGE:
-		return AJLT
-	case AJPL:
-		return AJMI
-	case AJGT:
-		return AJLE
-	case AJHI:
-		return AJLS
-	case AJCS:
-		return AJCC
-	case AJCC:
-		return AJCS
-	case AJPS:
-		return AJPC
-	case AJPC:
-		return AJPS
-	case AJOS:
-		return AJOC
-	case AJOC:
-		return AJOS
-	}
-
-	log.Fatalf("unknown relation: %s", Anames[a])
-	return 0
-}
-
-func xfol(ctxt *obj.Link, p *obj.Prog, last **obj.Prog) {
-	var q *obj.Prog
-	var i int
-	var a int
-
-loop:
-	if p == nil {
-		return
-	}
-	if p.As == obj.AJMP {
-		q = p.Pcond
-		if q != nil && q.As != obj.ATEXT {
-			/* mark instruction as done and continue layout at target of jump */
-			p.Mark = 1
-
-			p = q
-			if p.Mark == 0 {
-				goto loop
-			}
-		}
-	}
-
-	if p.Mark != 0 {
-		/*
-		 * p goes here, but already used it elsewhere.
-		 * copy up to 4 instructions or else branch to other copy.
-		 */
-		i = 0
-		q = p
-		for ; i < 4; (func() { i++; q = q.Link })() {
-			if q == nil {
-				break
-			}
-			if q == *last {
-				break
-			}
-			a = int(q.As)
-			if a == obj.ANOP {
-				i--
-				continue
-			}
-
-			if nofollow(a) || pushpop(a) {
-				break // NOTE(rsc): arm does goto copy
-			}
-			if q.Pcond == nil || q.Pcond.Mark != 0 {
-				continue
-			}
-			if a == obj.ACALL || a == ALOOP {
-				continue
-			}
-			for {
-				if p.As == obj.ANOP {
-					p = p.Link
-					continue
-				}
-
-				q = obj.Copyp(ctxt, p)
-				p = p.Link
-				q.Mark = 1
-				(*last).Link = q
-				*last = q
-				if int(q.As) != a || q.Pcond == nil || q.Pcond.Mark != 0 {
-					continue
-				}
-
-				q.As = int16(relinv(int(q.As)))
-				p = q.Pcond
-				q.Pcond = q.Link
-				q.Link = p
-				xfol(ctxt, q.Link, last)
-				p = q.Link
-				if p.Mark != 0 {
-					return
-				}
-				goto loop
-				/* */
-			}
-		}
-		q = ctxt.NewProg()
-		q.As = obj.AJMP
-		q.Lineno = p.Lineno
-		q.To.Type = obj.TYPE_BRANCH
-		q.To.Offset = p.Pc
-		q.Pcond = p
-		p = q
-	}
-
-	/* emit p */
-	p.Mark = 1
-
-	(*last).Link = p
-	*last = p
-	a = int(p.As)
-
-	/* continue loop with what comes after p */
-	if nofollow(a) {
-		return
-	}
-	if p.Pcond != nil && a != obj.ACALL {
-		/*
-		 * some kind of conditional branch.
-		 * recurse to follow one path.
-		 * continue loop on the other.
-		 */
-		q = obj.Brchain(ctxt, p.Pcond)
-		if q != nil {
-			p.Pcond = q
-		}
-		q = obj.Brchain(ctxt, p.Link)
-		if q != nil {
-			p.Link = q
-		}
-		if p.From.Type == obj.TYPE_CONST {
-			if p.From.Offset == 1 {
-				/*
-				 * expect conditional jump to be taken.
-				 * rewrite so that's the fall-through case.
-				 */
-				p.As = int16(relinv(a))
-
-				q = p.Link
-				p.Link = p.Pcond
-				p.Pcond = q
-			}
-		} else {
-			q = p.Link
-			if q.Mark != 0 {
-				if a != ALOOP {
-					p.As = int16(relinv(a))
-					p.Link = p.Pcond
-					p.Pcond = q
-				}
-			}
-		}
-
-		xfol(ctxt, p.Link, last)
-		if p.Pcond.Mark != 0 {
-			return
-		}
-		p = p.Pcond
-		goto loop
-	}
-
-	p = p.Link
-	goto loop
-}
-
-var Link386 = obj.LinkArch{
-	Rconv:      Rconv,
-	ByteOrder:  binary.LittleEndian,
-	Pconv:      Pconv,
-	Name:       "386",
-	Thechar:    '8',
-	Endian:     obj.LittleEndian,
-	Preprocess: preprocess,
-	Assemble:   span8,
-	Follow:     follow,
-	Progedit:   progedit,
-	Minlc:      1,
-	Ptrsize:    4,
-	Regsize:    4,
-}
diff --git a/src/cmd/internal/obj/line_test.go b/src/cmd/internal/obj/line_test.go
new file mode 100644
index 0000000..dde5d64
--- /dev/null
+++ b/src/cmd/internal/obj/line_test.go
@@ -0,0 +1,51 @@
+// Copyright 2015 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 obj
+
+import (
+	"fmt"
+	"testing"
+)
+
+func TestLineHist(t *testing.T) {
+	ctxt := new(Link)
+	ctxt.Hash = make(map[SymVer]*LSym)
+
+	Linklinehist(ctxt, 1, "a.c", 0)
+	Linklinehist(ctxt, 3, "a.h", 0)
+	Linklinehist(ctxt, 5, "<pop>", 0)
+	Linklinehist(ctxt, 7, "linedir", 2)
+	Linklinehist(ctxt, 9, "<pop>", 0)
+	Linklinehist(ctxt, 11, "b.c", 0)
+	Linklinehist(ctxt, 13, "<pop>", 0)
+
+	var expect = []string{
+		0:  "??:0",
+		1:  "a.c:1",
+		2:  "a.c:2",
+		3:  "a.h:1",
+		4:  "a.h:2",
+		5:  "a.c:3",
+		6:  "a.c:4",
+		7:  "linedir:2",
+		8:  "linedir:3",
+		9:  "??:0",
+		10: "??:0",
+		11: "b.c:1",
+		12: "b.c:2",
+		13: "??:0",
+		14: "??:0",
+	}
+
+	for i, want := range expect {
+		var f *LSym
+		var l int32
+		linkgetline(ctxt, int32(i), &f, &l)
+		have := fmt.Sprintf("%s:%d", f.Name, l)
+		if have != want {
+			t.Errorf("linkgetline(%d) = %q, want %q", i, have, want)
+		}
+	}
+}
diff --git a/src/cmd/internal/obj/link.go b/src/cmd/internal/obj/link.go
index 9900729..92fd7c4 100644
--- a/src/cmd/internal/obj/link.go
+++ b/src/cmd/internal/obj/link.go
@@ -32,264 +32,6 @@
 
 import "encoding/binary"
 
-type Addr struct {
-	Type   int16
-	Reg    int16
-	Reg2   int16 // RHS of register pair. AX:DX (386)
-	Index  int16
-	Scale  int16 // Sometimes holds a register.
-	Name   int8
-	Offset int64
-	Sym    *LSym
-	U      struct {
-		Sval    string
-		Dval    float64
-		Branch  *Prog
-		Argsize int32
-		Bits    uint64
-	}
-	Gotype *LSym
-	Class  int8
-	Etype  uint8
-	Node   interface{}
-	Width  int64
-}
-
-type Prog struct {
-	Ctxt     *Link
-	Pc       int64
-	Lineno   int32
-	Link     *Prog
-	As       int16
-	Scond    uint8
-	From     Addr
-	Reg      int16
-	From3    Addr
-	To       Addr
-	Opt      interface{}
-	Forwd    *Prog
-	Pcond    *Prog
-	Comefrom *Prog
-	Pcrel    *Prog
-	Spadj    int32
-	Mark     uint16
-	Optab    uint16
-	Back     uint8
-	Ft       uint8
-	Tt       uint8
-	Isize    uint8
-	Printed  uint8
-	Width    int8
-	Mode     int8
-}
-
-type LSym struct {
-	Name        string
-	Extname     string
-	Type        int16
-	Version     int16
-	Dupok       uint8
-	Cfunc       uint8
-	External    uint8
-	Nosplit     uint8
-	Reachable   uint8
-	Cgoexport   uint8
-	Special     uint8
-	Stkcheck    uint8
-	Hide        uint8
-	Leaf        uint8
-	Fnptr       uint8
-	Localentry  uint8
-	Seenglobl   uint8
-	Onlist      uint8
-	Printed     uint8
-	Symid       int16
-	Dynid       int32
-	Sig         int32
-	Plt         int32
-	Got         int32
-	Align       int32
-	Elfsym      int32
-	Args        int32
-	Locals      int32
-	Value       int64
-	Size        int64
-	Hash        *LSym
-	Allsym      *LSym
-	Next        *LSym
-	Sub         *LSym
-	Outer       *LSym
-	Gotype      *LSym
-	Reachparent *LSym
-	Queue       *LSym
-	File        string
-	Dynimplib   string
-	Dynimpvers  string
-	Sect        *struct{}
-	Autom       *Auto
-	Text        *Prog
-	Etext       *Prog
-	Pcln        *Pcln
-	P           []byte
-	R           []Reloc
-}
-
-type Reloc struct {
-	Off     int32
-	Siz     uint8
-	Done    uint8
-	Type    int32
-	Variant int32
-	Add     int64
-	Xadd    int64
-	Sym     *LSym
-	Xsym    *LSym
-}
-
-type Auto struct {
-	Asym    *LSym
-	Link    *Auto
-	Aoffset int32
-	Name    int16
-	Gotype  *LSym
-}
-
-type Hist struct {
-	Link    *Hist
-	Name    string
-	Line    int32
-	Offset  int32
-	Printed uint8
-}
-
-type Link struct {
-	Thechar            int32
-	Thestring          string
-	Goarm              int32
-	Headtype           int
-	Arch               *LinkArch
-	Ignore             func(string) int32
-	Debugasm           int32
-	Debugline          int32
-	Debughist          int32
-	Debugread          int32
-	Debugvlog          int32
-	Debugstack         int32
-	Debugzerostack     int32
-	Debugdivmod        int32
-	Debugfloat         int32
-	Debugpcln          int32
-	Flag_shared        int32
-	Iself              int32
-	Bso                *Biobuf
-	Pathname           string
-	Windows            int32
-	Trimpath           string
-	Goroot             string
-	Goroot_final       string
-	Enforce_data_order int32
-	Hash               [LINKHASH]*LSym
-	Allsym             *LSym
-	Nsymbol            int32
-	Hist               *Hist
-	Ehist              *Hist
-	Plist              *Plist
-	Plast              *Plist
-	Sym_div            *LSym
-	Sym_divu           *LSym
-	Sym_mod            *LSym
-	Sym_modu           *LSym
-	Symmorestack       [2]*LSym
-	Tlsg               *LSym
-	Plan9privates      *LSym
-	Curp               *Prog
-	Printp             *Prog
-	Blitrl             *Prog
-	Elitrl             *Prog
-	Rexflag            int
-	Rep                int
-	Repn               int
-	Lock               int
-	Asmode             int
-	Andptr             []byte
-	And                [100]uint8
-	Instoffset         int64
-	Autosize           int32
-	Armsize            int32
-	Pc                 int64
-	Libdir             []string
-	Library            []Library
-	Tlsoffset          int
-	Diag               func(string, ...interface{})
-	Mode               int
-	Curauto            *Auto
-	Curhist            *Auto
-	Cursym             *LSym
-	Version            int
-	Textp              *LSym
-	Etextp             *LSym
-	Histdepth          int32
-	Nhistfile          int32
-	Filesyms           *LSym
-}
-
-type Plist struct {
-	Name    *LSym
-	Firstpc *Prog
-	Recur   int
-	Link    *Plist
-}
-
-type LinkArch struct {
-	Pconv      func(*Prog) string
-	Rconv      func(int) string
-	ByteOrder  binary.ByteOrder
-	Name       string
-	Thechar    int
-	Endian     int32
-	Preprocess func(*Link, *LSym)
-	Assemble   func(*Link, *LSym)
-	Follow     func(*Link, *LSym)
-	Progedit   func(*Link, *Prog)
-	Minlc      int
-	Ptrsize    int
-	Regsize    int
-}
-
-type Library struct {
-	Objref string
-	Srcref string
-	File   string
-	Pkg    string
-}
-
-type Pcln struct {
-	Pcsp        Pcdata
-	Pcfile      Pcdata
-	Pcline      Pcdata
-	Pcdata      []Pcdata
-	Funcdata    []*LSym
-	Funcdataoff []int64
-	File        []*LSym
-	Lastfile    *LSym
-	Lastindex   int
-}
-
-type Pcdata struct {
-	P []byte
-}
-
-type Pciter struct {
-	d       Pcdata
-	p       []byte
-	pc      uint32
-	nextpc  uint32
-	pcscale uint32
-	value   int32
-	start   int
-	done    int
-}
-
 // An Addr is an argument to an instruction.
 // The general forms and their encodings are:
 //
@@ -334,13 +76,13 @@
 //		Floating point constant value.
 //		Encoding:
 //			type = TYPE_FCONST
-//			u.dval = floating point value
+//			val = floating point value
 //
 //	$<string literal, up to 8 chars>
 //		String literal value (raw bytes used for DATA instruction).
 //		Encoding:
 //			type = TYPE_SCONST
-//			u.sval = string
+//			val = string
 //
 //	<register name>
 //		Any register: integer, floating point, control, segment, and so on.
@@ -352,7 +94,7 @@
 //	x(PC)
 //		Encoding:
 //			type = TYPE_BRANCH
-//			u.branch = Prog* reference OR ELSE offset = target pc (branch takes priority)
+//			val = Prog* reference OR ELSE offset = target pc (branch takes priority)
 //
 //	$±x-±y
 //		Final argument to TEXT, specifying local frame size x and argument size y.
@@ -364,7 +106,7 @@
 //		Encoding:
 //			type = TYPE_TEXTSIZE
 //			offset = x
-//			u.argsize = y
+//			val = int32(y)
 //
 //	reg<<shift, reg>>shift, reg->shift, reg@>shift
 //		Shifted register value, for ARM.
@@ -390,8 +132,40 @@
 //			offset = bit mask of registers in list; R0 is low bit.
 //
 //	reg, reg
-//		TYPE_REGREG2, to be removed.
+//		Register pair for ARM.
+//		TYPE_REGREG2
 //
+//	(reg+reg)
+//		Register pair for PPC64.
+//		Encoding:
+//			type = TYPE_MEM
+//			reg = first register
+//			index = second register
+//			scale = 1
+//
+type Addr struct {
+	Type   int16
+	Reg    int16
+	Reg2   int16 // RHS of register pair. AX:DX (386)
+	Index  int16
+	Scale  int16 // Sometimes holds a register.
+	Name   int8
+	Class  int8
+	Etype  uint8
+	Offset int64
+	Width  int64
+	Sym    *LSym
+	Gotype *LSym
+
+	// argument value:
+	//	for TYPE_SCONST, a string
+	//	for TYPE_FCONST, a float64
+	//	for TYPE_BRANCH, a *Prog (optional)
+	//	for TYPE_TEXTSIZE, an int32 (optional)
+	Val interface{}
+
+	Node interface{} // for use by compiler
+}
 
 const (
 	NAME_NONE = 0 + iota
@@ -402,8 +176,11 @@
 )
 
 const (
-	TYPE_NONE   = 0
-	TYPE_BRANCH = 5 + iota - 1
+	TYPE_NONE = 0
+)
+
+const (
+	TYPE_BRANCH = 5 + iota
 	TYPE_TEXTSIZE
 	TYPE_MEM
 	TYPE_CONST
@@ -420,11 +197,56 @@
 
 // TODO(rsc): Describe prog.
 // TODO(rsc): Describe TEXT/GLOBL flag in from3, DATA width in from3.
+type Prog struct {
+	Ctxt     *Link
+	Link     *Prog
+	From     Addr
+	From3    Addr
+	To       Addr
+	To2      Addr
+	Opt      interface{}
+	Forwd    *Prog
+	Pcond    *Prog
+	Comefrom *Prog
+	Pcrel    *Prog
+	Pc       int64
+	Lineno   int32
+	Spadj    int32
+	As       int16
+	Reg      int16
+	Mark     uint16
+	Optab    uint16
+	Scond    uint8
+	Back     uint8
+	Ft       uint8
+	F3t      uint8
+	Tt       uint8
+	Isize    uint8
+	Printed  uint8
+	Width    int8
+	Mode     int8
+
+	Info ProgInfo
+}
+
+// ProgInfo holds information about the instruction for use
+// by clients such as the compiler. The exact meaning of this
+// data is up to the client and is not interpreted by the cmd/internal/obj/... packages.
+type ProgInfo struct {
+	Flags    uint32 // flag bits
+	Reguse   uint64 // registers implicitly used by this instruction
+	Regset   uint64 // registers implicitly set by this instruction
+	Regindex uint64 // registers used by addressing mode
+}
 
 // Prog.as opcodes.
 // These are the portable opcodes, common to all architectures.
 // Each architecture defines many more arch-specific opcodes,
 // with values starting at A_ARCHSPECIFIC.
+// Each architecture adds an offset to this so each machine has
+// distinct space for its instructions. The offset is a power of
+// two so it can be masked to return to origin zero.
+// See the definitions of ABase386 etc.
 const (
 	AXXX = 0 + iota
 	ACALL
@@ -448,7 +270,66 @@
 	A_ARCHSPECIFIC
 )
 
-// prevent incompatible type signatures between liblink and 8l on Plan 9
+type LSym struct {
+	Name        string
+	Extname     string
+	Type        int16
+	Version     int16
+	Dupok       uint8
+	Cfunc       uint8
+	External    uint8
+	Nosplit     uint8
+	Reachable   uint8
+	Cgoexport   uint8
+	Special     uint8
+	Stkcheck    uint8
+	Hide        uint8
+	Leaf        uint8
+	Fnptr       uint8
+	Localentry  uint8
+	Seenglobl   uint8
+	Onlist      uint8
+	Printed     uint8
+	Symid       int16
+	Dynid       int32
+	Plt         int32
+	Got         int32
+	Align       int32
+	Elfsym      int32
+	Args        int32
+	Locals      int32
+	Value       int64
+	Size        int64
+	Allsym      *LSym
+	Next        *LSym
+	Sub         *LSym
+	Outer       *LSym
+	Gotype      *LSym
+	Reachparent *LSym
+	Queue       *LSym
+	File        string
+	Dynimplib   string
+	Dynimpvers  string
+	Sect        *struct{}
+	Autom       *Auto
+	Text        *Prog
+	Etext       *Prog
+	Pcln        *Pcln
+	P           []byte
+	R           []Reloc
+}
+
+type Pcln struct {
+	Pcsp        Pcdata
+	Pcfile      Pcdata
+	Pcline      Pcdata
+	Pcdata      []Pcdata
+	Funcdata    []*LSym
+	Funcdataoff []int64
+	File        []*LSym
+	Lastfile    *LSym
+	Lastindex   int
+}
 
 // LSym.type
 const (
@@ -492,6 +373,18 @@
 	SHIDDEN = 1 << 9
 )
 
+type Reloc struct {
+	Off     int32
+	Siz     uint8
+	Done    uint8
+	Type    int32
+	Variant int32
+	Add     int64
+	Xadd    int64
+	Sym     *LSym
+	Xsym    *LSym
+}
+
 // Reloc.type
 const (
 	R_ADDR = 1 + iota
@@ -499,6 +392,7 @@
 	R_SIZE
 	R_CALL
 	R_CALLARM
+	R_CALLARM64
 	R_CALLIND
 	R_CALLPOWER
 	R_CONST
@@ -525,18 +419,36 @@
 	RV_TYPE_MASK      = RV_CHECK_OVERFLOW - 1
 )
 
+type Auto struct {
+	Asym    *LSym
+	Link    *Auto
+	Aoffset int32
+	Name    int16
+	Gotype  *LSym
+}
+
 // Auto.name
 const (
 	A_AUTO = 1 + iota
 	A_PARAM
 )
 
-const (
-	LINKHASH = 100003
-)
+type Pcdata struct {
+	P []byte
+}
 
 // Pcdata iterator.
 //	for(pciterinit(ctxt, &it, &pcd); !it.done; pciternext(&it)) { it.value holds in [it.pc, it.nextpc) }
+type Pciter struct {
+	d       Pcdata
+	p       []byte
+	pc      uint32
+	nextpc  uint32
+	pcscale uint32
+	value   int32
+	start   int
+	done    int
+}
 
 // symbol version, incremented each time a file is loaded.
 // version==1 is reserved for savehist.
@@ -546,13 +458,103 @@
 
 // Link holds the context for writing object code from a compiler
 // to be linker input or for reading that input into the linker.
+type Link struct {
+	Thechar            int32
+	Thestring          string
+	Goarm              int32
+	Headtype           int
+	Arch               *LinkArch
+	Ignore             func(string) int32
+	Debugasm           int32
+	Debugline          int32
+	Debughist          int32
+	Debugread          int32
+	Debugvlog          int32
+	Debugstack         int32
+	Debugzerostack     int32
+	Debugdivmod        int32
+	Debugfloat         int32
+	Debugpcln          int32
+	Flag_shared        int32
+	Iself              int32
+	Bso                *Biobuf
+	Pathname           string
+	Windows            int32
+	Trimpath           string
+	Goroot             string
+	Goroot_final       string
+	Enforce_data_order int32
+	Hash               map[SymVer]*LSym
+	Allsym             *LSym
+	Nsymbol            int32
+	LineHist           LineHist
+	Imports            []string
+	Plist              *Plist
+	Plast              *Plist
+	Sym_div            *LSym
+	Sym_divu           *LSym
+	Sym_mod            *LSym
+	Sym_modu           *LSym
+	Symmorestack       [2]*LSym
+	Tlsg               *LSym
+	Plan9privates      *LSym
+	Curp               *Prog
+	Printp             *Prog
+	Blitrl             *Prog
+	Elitrl             *Prog
+	Rexflag            int
+	Rep                int
+	Repn               int
+	Lock               int
+	Asmode             int
+	Andptr             []byte
+	And                [100]uint8
+	Instoffset         int64
+	Autosize           int32
+	Armsize            int32
+	Pc                 int64
+	Libdir             []string
+	Library            []Library
+	Tlsoffset          int
+	Diag               func(string, ...interface{})
+	Mode               int
+	Curauto            *Auto
+	Curhist            *Auto
+	Cursym             *LSym
+	Version            int
+	Textp              *LSym
+	Etextp             *LSym
+	Histdepth          int32
+	Nhistfile          int32
+	Filesyms           *LSym
+}
 
-const (
-	LittleEndian = 0x04030201
-	BigEndian    = 0x01020304
-)
+type SymVer struct {
+	Name    string
+	Version int
+}
+
+type Library struct {
+	Objref string
+	Srcref string
+	File   string
+	Pkg    string
+}
 
 // LinkArch is the definition of a single architecture.
+type LinkArch struct {
+	ByteOrder  binary.ByteOrder
+	Name       string
+	Thechar    int
+	Preprocess func(*Link, *LSym)
+	Assemble   func(*Link, *LSym)
+	Follow     func(*Link, *LSym)
+	Progedit   func(*Link, *Prog)
+	UnaryDst   map[int]bool // Instruction takes one operand, a destination.
+	Minlc      int
+	Ptrsize    int
+	Regsize    int
+}
 
 /* executable header types */
 const (
@@ -576,30 +578,27 @@
 	LinkExternal
 )
 
-// asm5.c
-
-// asm6.c
-
-// asm8.c
-
-// asm9.c
-
-// data.c
-
-// go.c
-
-// ld.c
-
-// list[5689].c
-
-// obj.c
-
-// objfile.c
-
-// pass.c
-
-// pcln.c
-
-// sym.c
-
 var linkbasepointer int
+
+type Plist struct {
+	Name    *LSym
+	Firstpc *Prog
+	Recur   int
+	Link    *Plist
+}
+
+/*
+ * start a new Prog list.
+ */
+func Linknewplist(ctxt *Link) *Plist {
+	pl := new(Plist)
+	*pl = Plist{}
+	if ctxt.Plist == nil {
+		ctxt.Plist = pl
+	} else {
+		ctxt.Plast.Link = pl
+	}
+	ctxt.Plast = pl
+
+	return pl
+}
diff --git a/src/cmd/internal/obj/mgc0.go b/src/cmd/internal/obj/mgc0.go
index 7dfd991..2407dea 100644
--- a/src/cmd/internal/obj/mgc0.go
+++ b/src/cmd/internal/obj/mgc0.go
@@ -29,7 +29,10 @@
 	BitsPointer     = 2
 	BitsMask        = 3
 	PointersPerByte = 8 / BitsPerPointer
-	InsData         = 1 + iota - 7
+)
+
+const (
+	InsData = 1 + iota
 	InsArray
 	InsArrayEnd
 	InsEnd
diff --git a/src/cmd/internal/obj/obj.go b/src/cmd/internal/obj/obj.go
index 05902e2..39db239 100644
--- a/src/cmd/internal/obj/obj.go
+++ b/src/cmd/internal/obj/obj.go
@@ -7,98 +7,110 @@
 import (
 	"fmt"
 	"path/filepath"
+	"sort"
 	"strings"
 )
 
-const (
-	HISTSZ = 10
-	NSYM   = 50
-)
+// A LineHist records the history of the file input stack, which maps the virtual line number,
+// an incrementing count of lines processed in any input file and typically named lineno,
+// to a stack of file:line pairs showing the path of inclusions that led to that position.
+// The first line directive (//line in Go, #line in assembly) is treated as pushing
+// a new entry on the stack, so that errors can report both the actual and translated
+// line number.
+//
+// In typical use, the virtual lineno begins at 1, and file line numbers also begin at 1,
+// but the only requirements placed upon the numbers by this code are:
+//	- calls to Push, Update, and Pop must be monotonically increasing in lineno
+//	- except as specified by those methods, virtual and file line number increase
+//	  together, so that given (only) calls Push(10, "x.go", 1) and Pop(15),
+//	  virtual line 12 corresponds to x.go line 3.
+type LineHist struct {
+	Top            *LineStack  // current top of stack
+	Ranges         []LineRange // ranges for lookup
+	Dir            string      // directory to qualify relative paths
+	TrimPathPrefix string      // remove leading TrimPath from recorded file names
+	GOROOT         string      // current GOROOT
+	GOROOT_FINAL   string      // target GOROOT
+}
 
-func Linklinefmt(ctxt *Link, lno0 int, showAll, showFullPath bool) string {
-	var a [HISTSZ]struct {
-		incl *Hist
-		idel int32
-		line *Hist
-		ldel int32
+// A LineStack is an entry in the recorded line history.
+// Although the history at any given line number is a stack,
+// the record for all line processed forms a tree, with common
+// stack prefixes acting as parents.
+type LineStack struct {
+	Parent    *LineStack // parent in inclusion stack
+	Lineno    int        // virtual line number where this entry takes effect
+	File      string     // file name used to open source file, for error messages
+	AbsFile   string     // absolute file name, for pcln tables
+	FileLine  int        // line number in file at Lineno
+	Directive bool
+	Sym       *LSym // for linkgetline - TODO(rsc): remove
+}
+
+func (stk *LineStack) fileLineAt(lineno int) int {
+	return stk.FileLine + lineno - stk.Lineno
+}
+
+// The span of valid linenos in the recorded line history can be broken
+// into a set of ranges, each with a particular stack.
+// A LineRange records one such range.
+type LineRange struct {
+	Start int        // starting lineno
+	Stack *LineStack // top of stack for this range
+}
+
+// startRange starts a new range with the given top of stack.
+func (h *LineHist) startRange(lineno int, top *LineStack) {
+	h.Top = top
+	h.Ranges = append(h.Ranges, LineRange{top.Lineno, top})
+}
+
+// setFile sets stk.File = file and also derives stk.AbsFile.
+func (h *LineHist) setFile(stk *LineStack, file string) {
+	// Note: The exclusion of stk.Directive may be wrong but matches what we've done before.
+	// The check for < avoids putting a path prefix on "<autogenerated>".
+	abs := file
+	if h.Dir != "" && !filepath.IsAbs(file) && !strings.HasPrefix(file, "<") && !stk.Directive {
+		abs = filepath.Join(h.Dir, file)
 	}
-	lno := int32(lno0)
-	lno1 := lno
-	var d int32
-	n := 0
-	for h := ctxt.Hist; h != nil; h = h.Link {
-		if h.Offset < 0 {
-			continue
-		}
-		if lno < h.Line {
-			break
-		}
-		if h.Name != "<pop>" {
-			if h.Offset > 0 {
-				// #line directive
-				if n > 0 && n < int(HISTSZ) {
-					a[n-1].line = h
-					a[n-1].ldel = h.Line - h.Offset + 1
-				}
-			} else {
-				// beginning of file
-				if n < int(HISTSZ) {
-					a[n].incl = h
-					a[n].idel = h.Line
-					a[n].line = nil
-				}
-				n++
-			}
-			continue
-		}
-		n--
-		if n > 0 && n < int(HISTSZ) {
-			d = h.Line - a[n].incl.Line
-			a[n-1].ldel += d
-			a[n-1].idel += d
-		}
-	}
-	if n > int(HISTSZ) {
-		n = int(HISTSZ)
-	}
-	var fp string
-	for i := n - 1; i >= 0; i-- {
-		if i != n-1 {
-			if !showAll {
-				break
-			}
-			fp += " "
-		}
-		if ctxt.Debugline != 0 || showFullPath {
-			fp += fmt.Sprintf("%s/", ctxt.Pathname)
-		}
-		if a[i].line != nil {
-			fp += fmt.Sprintf("%s:%d[%s:%d]", a[i].line.Name, lno-a[i].ldel+1, a[i].incl.Name, lno-a[i].idel+1)
+
+	// Remove leading TrimPathPrefix, or else rewrite $GOROOT to $GOROOT_FINAL.
+	if h.TrimPathPrefix != "" && hasPathPrefix(abs, h.TrimPathPrefix) {
+		if abs == h.TrimPathPrefix {
+			abs = ""
 		} else {
-			fp += fmt.Sprintf("%s:%d", a[i].incl.Name, lno-a[i].idel+1)
+			abs = abs[len(h.TrimPathPrefix)+1:]
 		}
-		lno = a[i].incl.Line - 1 // now print out start of this file
+	} else if h.GOROOT_FINAL != "" && h.GOROOT_FINAL != h.GOROOT && hasPathPrefix(abs, h.GOROOT) {
+		abs = h.GOROOT_FINAL + abs[len(h.GOROOT):]
 	}
-	if n == 0 {
-		fp += fmt.Sprintf("<unknown line number %d %d %d %s>", lno1, ctxt.Hist.Offset, ctxt.Hist.Line, ctxt.Hist.Name)
+	if abs == "" {
+		abs = "??"
 	}
-	return fp
+	abs = filepath.Clean(abs)
+	stk.AbsFile = abs
+
+	if file == "" {
+		file = "??"
+	}
+	stk.File = file
 }
 
 // Does s have t as a path prefix?
 // That is, does s == t or does s begin with t followed by a slash?
-// For portability, we allow ASCII case folding, so that haspathprefix("a/b/c", "A/B") is true.
-// Similarly, we allow slash folding, so that haspathprefix("a/b/c", "a\\b") is true.
-func haspathprefix(s string, t string) bool {
+// For portability, we allow ASCII case folding, so that hasPathPrefix("a/b/c", "A/B") is true.
+// Similarly, we allow slash folding, so that hasPathPrefix("a/b/c", "a\\b") is true.
+// We do not allow full Unicode case folding, for fear of causing more confusion
+// or harm than good. (For an example of the kinds of things that can go wrong,
+// see http://article.gmane.org/gmane.linux.kernel/1853266.)
+func hasPathPrefix(s string, t string) bool {
 	if len(t) > len(s) {
 		return false
 	}
 	var i int
-	var cs int
-	var ct int
 	for i = 0; i < len(t); i++ {
-		cs = int(s[i])
-		ct = int(t[i])
+		cs := int(s[i])
+		ct := int(t[i])
 		if 'A' <= cs && cs <= 'Z' {
 			cs += 'a' - 'A'
 		}
@@ -118,180 +130,187 @@
 	return i >= len(s) || s[i] == '/' || s[i] == '\\'
 }
 
+// Push records that at that lineno a new file with the given name was pushed onto the input stack.
+func (h *LineHist) Push(lineno int, file string) {
+	stk := &LineStack{
+		Parent:   h.Top,
+		Lineno:   lineno,
+		FileLine: 1,
+	}
+	h.setFile(stk, file)
+	h.startRange(lineno, stk)
+}
+
+// Pop records that at lineno the current file was popped from the input stack.
+func (h *LineHist) Pop(lineno int) {
+	top := h.Top
+	if top == nil {
+		return
+	}
+	if top.Directive && top.Parent != nil { // pop #line level too
+		top = top.Parent
+	}
+	next := top.Parent
+	if next == nil {
+		h.Top = nil
+		h.Ranges = append(h.Ranges, LineRange{lineno, nil})
+		return
+	}
+
+	// Popping included file. Update parent offset to account for
+	// the virtual line number range taken by the included file.
+	// Cannot modify the LineStack directly, or else lookups
+	// for the earlier line numbers will get the wrong answers,
+	// so make a new one.
+	stk := new(LineStack)
+	*stk = *next
+	stk.Lineno = lineno
+	stk.FileLine = next.fileLineAt(top.Lineno)
+	h.startRange(lineno, stk)
+}
+
+// Update records that at lineno the file name and line number were changed using
+// a line directive (//line in Go, #line in assembly).
+func (h *LineHist) Update(lineno int, file string, line int) {
+	top := h.Top
+	if top == nil {
+		return // shouldn't happen
+	}
+	var stk *LineStack
+	if top.Directive {
+		// Update existing entry, except make copy to avoid changing earlier history.
+		stk = new(LineStack)
+		*stk = *top
+	} else {
+		// Push new entry.
+		stk = &LineStack{
+			Parent:    top,
+			Directive: true,
+		}
+	}
+	stk.Lineno = lineno
+	if stk.File != file {
+		h.setFile(stk, file) // only retain string if needed
+	}
+	stk.FileLine = line
+	h.startRange(lineno, stk)
+}
+
+// AddImport adds a package to the list of imported packages.
+func (ctxt *Link) AddImport(pkg string) {
+	ctxt.Imports = append(ctxt.Imports, pkg)
+}
+
+// At returns the input stack in effect at lineno.
+func (h *LineHist) At(lineno int) *LineStack {
+	i := sort.Search(len(h.Ranges), func(i int) bool {
+		return h.Ranges[i].Start > lineno
+	})
+	// Found first entry beyond lineno.
+	if i == 0 {
+		return nil
+	}
+	return h.Ranges[i-1].Stack
+}
+
+// LineString returns a string giving the file and line number
+// corresponding to lineno, for use in error messages.
+func (h *LineHist) LineString(lineno int) string {
+	stk := h.At(lineno)
+	if stk == nil {
+		return "<unknown line number>"
+	}
+
+	text := fmt.Sprintf("%s:%d", stk.File, stk.fileLineAt(lineno))
+	if stk.Directive && stk.Parent != nil {
+		stk = stk.Parent
+		text += fmt.Sprintf("[%s:%d]", stk.File, stk.fileLineAt(lineno))
+	}
+	const showFullStack = false // was used by old C compilers
+	if showFullStack {
+		for stk.Parent != nil {
+			lineno = stk.Lineno - 1
+			stk = stk.Parent
+			text += fmt.Sprintf(" %s:%d", stk.File, stk.fileLineAt(lineno))
+			if stk.Directive && stk.Parent != nil {
+				stk = stk.Parent
+				text += fmt.Sprintf("[%s:%d]", stk.File, stk.fileLineAt(lineno))
+			}
+		}
+	}
+	return text
+}
+
+// TODO(rsc): Replace call sites with use of ctxt.LineHist.
+// Note that all call sites use showAll=false, showFullPath=false.
+func Linklinefmt(ctxt *Link, lineno int, showAll, showFullPath bool) string {
+	return ctxt.LineHist.LineString(lineno)
+}
+
+// FileLine returns the file name and line number
+// at the top of the stack for the given lineno.
+func (h *LineHist) FileLine(lineno int) (file string, line int) {
+	stk := h.At(lineno)
+	if stk == nil {
+		return "??", 0
+	}
+	return stk.File, stk.fileLineAt(lineno)
+}
+
+// AbsFileLine returns the absolute file name and line number
+// at the top of the stack for the given lineno.
+func (h *LineHist) AbsFileLine(lineno int) (file string, line int) {
+	stk := h.At(lineno)
+	if stk == nil {
+		return "??", 0
+	}
+	return stk.AbsFile, stk.fileLineAt(lineno)
+}
+
 // This is a simplified copy of linklinefmt above.
 // It doesn't allow printing the full stack, and it returns the file name and line number separately.
 // TODO: Unify with linklinefmt somehow.
-func linkgetline(ctxt *Link, line int32, f **LSym, l *int32) {
-	var a [HISTSZ]struct {
-		incl *Hist
-		idel int32
-		line *Hist
-		ldel int32
-	}
-	var d int32
-	lno := int32(line)
-	n := 0
-	for h := ctxt.Hist; h != nil; h = h.Link {
-		if h.Offset < 0 {
-			continue
-		}
-		if lno < h.Line {
-			break
-		}
-		if h.Name != "<pop>" {
-			if h.Offset > 0 {
-				// #line directive
-				if n > 0 && n < HISTSZ {
-					a[n-1].line = h
-					a[n-1].ldel = h.Line - h.Offset + 1
-				}
-			} else {
-				// beginning of file
-				if n < HISTSZ {
-					a[n].incl = h
-					a[n].idel = h.Line
-					a[n].line = nil
-				}
-				n++
-			}
-			continue
-		}
-		n--
-		if n > 0 && n < HISTSZ {
-			d = h.Line - a[n].incl.Line
-			a[n-1].ldel += d
-			a[n-1].idel += d
-		}
-	}
-	if n > HISTSZ {
-		n = HISTSZ
-	}
-	if n <= 0 {
+func linkgetline(ctxt *Link, lineno int32, f **LSym, l *int32) {
+	stk := ctxt.LineHist.At(int(lineno))
+	if stk == nil || stk.AbsFile == "" {
 		*f = Linklookup(ctxt, "??", HistVersion)
 		*l = 0
 		return
 	}
-	n--
-	var dlno int32
-	var file string
-	if a[n].line != nil {
-		file = a[n].line.Name
-		dlno = a[n].ldel - 1
-	} else {
-		file = a[n].incl.Name
-		dlno = a[n].idel - 1
+	if stk.Sym == nil {
+		stk.Sym = Linklookup(ctxt, stk.AbsFile, HistVersion)
 	}
-	var buf string
-	if filepath.IsAbs(file) || strings.HasPrefix(file, "<") {
-		buf = fmt.Sprintf("%s", file)
-	} else {
-		buf = fmt.Sprintf("%s/%s", ctxt.Pathname, file)
-	}
-	// Remove leading ctxt->trimpath, or else rewrite $GOROOT to $GOROOT_FINAL.
-	if ctxt.Trimpath != "" && haspathprefix(buf, ctxt.Trimpath) {
-		if len(buf) == len(ctxt.Trimpath) {
-			buf = "??"
-		} else {
-			buf1 := fmt.Sprintf("%s", buf[len(ctxt.Trimpath)+1:])
-			if buf1[0] == '\x00' {
-				buf1 = "??"
-			}
-			buf = buf1
-		}
-	} else if ctxt.Goroot_final != "" && haspathprefix(buf, ctxt.Goroot) {
-		buf1 := fmt.Sprintf("%s%s", ctxt.Goroot_final, buf[len(ctxt.Goroot):])
-		buf = buf1
-	}
-	lno -= dlno
-	*f = Linklookup(ctxt, buf, HistVersion)
-	*l = lno
-}
-
-func Linklinehist(ctxt *Link, lineno int, f string, offset int) {
-	if false { // debug['f']
-		if f != "" {
-			if offset != 0 {
-				fmt.Printf("%4d: %s (#line %d)\n", lineno, f, offset)
-			} else {
-				fmt.Printf("%4d: %s\n", lineno, f)
-			}
-		} else {
-			fmt.Printf("%4d: <pop>\n", lineno)
-		}
-	}
-
-	h := new(Hist)
-	*h = Hist{}
-	h.Name = f
-	h.Line = int32(lineno)
-	h.Offset = int32(offset)
-	h.Link = nil
-	if ctxt.Ehist == nil {
-		ctxt.Hist = h
-		ctxt.Ehist = h
-		return
-	}
-
-	ctxt.Ehist.Link = h
-	ctxt.Ehist = h
+	*f = stk.Sym
+	*l = int32(stk.fileLineAt(int(lineno)))
 }
 
 func Linkprfile(ctxt *Link, line int) {
-	l := int32(line)
-	var i int
-	var a [HISTSZ]Hist
-	var d int32
-	n := 0
-	for h := ctxt.Hist; h != nil; h = h.Link {
-		if l < h.Line {
-			break
-		}
-		if h.Name != "<pop>" {
-			if h.Offset == 0 {
-				if n >= 0 && n < HISTSZ {
-					a[n] = *h
-				}
-				n++
-				continue
-			}
-			if n > 0 && n < HISTSZ {
-				if a[n-1].Offset == 0 {
-					a[n] = *h
-					n++
-				} else {
-					a[n-1] = *h
-				}
-			}
-			continue
-		}
-		n--
-		if n >= 0 && n < HISTSZ {
-			d = h.Line - a[n].Line
-			for i = 0; i < n; i++ {
-				a[i].Line += d
-			}
-		}
-	}
-	if n > HISTSZ {
-		n = HISTSZ
-	}
-	for i := 0; i < n; i++ {
-		fmt.Printf("%s:%d ", a[i].Name, int(l-a[i].Line+a[i].Offset+1))
-	}
+	fmt.Printf("%s ", ctxt.LineHist.LineString(line))
 }
 
-/*
- * start a new Prog list.
- */
-func Linknewplist(ctxt *Link) *Plist {
-	pl := new(Plist)
-	*pl = Plist{}
-	if ctxt.Plist == nil {
-		ctxt.Plist = pl
-	} else {
-		ctxt.Plast.Link = pl
-	}
-	ctxt.Plast = pl
+// Linklinehist pushes, amends, or pops an entry on the line history stack.
+// If f != "<pop>" and n == 0, the call pushes the start of a new file named f at lineno.
+// If f != "<pop>" and n > 0, the call amends the top of the stack to record that lineno
+// now corresponds to f at line n.
+// If f == "<pop>", the call pops the topmost entry from the stack, picking up
+// the parent file at the line following the one where the corresponding push occurred.
+//
+// If n < 0, linklinehist records f as a package required by the current compilation
+// (nothing to do with line numbers).
+//
+// TODO(rsc): Replace uses with direct calls to ctxt.Hist methods.
+func Linklinehist(ctxt *Link, lineno int, f string, n int) {
+	switch {
+	case n < 0:
+		ctxt.AddImport(f)
 
-	return pl
+	case f == "<pop>":
+		ctxt.LineHist.Pop(lineno)
+
+	case n == 0:
+		ctxt.LineHist.Push(lineno, f)
+
+	default:
+		ctxt.LineHist.Update(lineno, f, n)
+	}
 }
diff --git a/src/cmd/internal/obj/objfile.go b/src/cmd/internal/obj/objfile.go
index 6e76a39..1f68578 100644
--- a/src/cmd/internal/obj/objfile.go
+++ b/src/cmd/internal/obj/objfile.go
@@ -2,6 +2,102 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
+// Writing of Go object files.
+//
+// Originally, Go object files were Plan 9 object files, but no longer.
+// Now they are more like standard object files, in that each symbol is defined
+// by an associated memory image (bytes) and a list of relocations to apply
+// during linking. We do not (yet?) use a standard file format, however.
+// For now, the format is chosen to be as simple as possible to read and write.
+// It may change for reasons of efficiency, or we may even switch to a
+// standard file format if there are compelling benefits to doing so.
+// See golang.org/s/go13linker for more background.
+//
+// The file format is:
+//
+//	- magic header: "\x00\x00go13ld"
+//	- byte 1 - version number
+//	- sequence of strings giving dependencies (imported packages)
+//	- empty string (marks end of sequence)
+//	- sequence of defined symbols
+//	- byte 0xff (marks end of sequence)
+//	- magic footer: "\xff\xffgo13ld"
+//
+// All integers are stored in a zigzag varint format.
+// See golang.org/s/go12symtab for a definition.
+//
+// Data blocks and strings are both stored as an integer
+// followed by that many bytes.
+//
+// A symbol reference is a string name followed by a version.
+// An empty name corresponds to a nil LSym* pointer.
+//
+// Each symbol is laid out as the following fields (taken from LSym*):
+//
+//	- byte 0xfe (sanity check for synchronization)
+//	- type [int]
+//	- name [string]
+//	- version [int]
+//	- flags [int]
+//		1 dupok
+//	- size [int]
+//	- gotype [symbol reference]
+//	- p [data block]
+//	- nr [int]
+//	- r [nr relocations, sorted by off]
+//
+// If type == STEXT, there are a few more fields:
+//
+//	- args [int]
+//	- locals [int]
+//	- nosplit [int]
+//	- flags [int]
+//		1 leaf
+//		2 C function
+//	- nlocal [int]
+//	- local [nlocal automatics]
+//	- pcln [pcln table]
+//
+// Each relocation has the encoding:
+//
+//	- off [int]
+//	- siz [int]
+//	- type [int]
+//	- add [int]
+//	- xadd [int]
+//	- sym [symbol reference]
+//	- xsym [symbol reference]
+//
+// Each local has the encoding:
+//
+//	- asym [symbol reference]
+//	- offset [int]
+//	- type [int]
+//	- gotype [symbol reference]
+//
+// The pcln table has the encoding:
+//
+//	- pcsp [data block]
+//	- pcfile [data block]
+//	- pcline [data block]
+//	- npcdata [int]
+//	- pcdata [npcdata data blocks]
+//	- nfuncdata [int]
+//	- funcdata [nfuncdata symbol references]
+//	- funcdatasym [nfuncdata ints]
+//	- nfile [int]
+//	- file [nfile symbol references]
+//
+// The file layout and meaning of type integers are architecture-independent.
+//
+// TODO(rsc): The file format is good for a first pass but needs work.
+//	- There are SymID in the object file that should really just be strings.
+//	- The actual symbol memory images are interlaced with the symbol
+//	  metadata. They should be separated, to reduce the I/O required to
+//	  load just the metadata.
+//	- The symbol references should be shortened, either with a symbol
+//	  table or by using a simple backward index to an earlier mentioned symbol.
+
 package obj
 
 import (
@@ -26,12 +122,12 @@
 	// Build list of symbols, and assign instructions to lists.
 	// Ignore ctxt->plist boundaries. There are no guarantees there,
 	// and the C compilers and assemblers just use one big list.
-	text := (*LSym)(nil)
+	var text *LSym
 
-	curtext := (*LSym)(nil)
-	data := (*LSym)(nil)
-	etext := (*LSym)(nil)
-	edata := (*LSym)(nil)
+	var curtext *LSym
+	var data *LSym
+	var etext *LSym
+	var edata *LSym
 	for pl := ctxt.Plist; pl != nil; pl = pl.Link {
 		for p = pl.Firstpc; p != nil; p = plink {
 			if ctxt.Debugasm != 0 && ctxt.Debugvlog != 0 {
@@ -210,10 +306,8 @@
 	Bputc(b, 1) // version
 
 	// Emit autolib.
-	for h := ctxt.Hist; h != nil; h = h.Link {
-		if h.Offset < 0 {
-			wrstring(b, h.Name)
-		}
+	for _, pkg := range ctxt.Imports {
+		wrstring(b, pkg)
 	}
 	wrstring(b, "")
 
diff --git a/src/cmd/internal/obj/pass.go b/src/cmd/internal/obj/pass.go
index 50d21e9..a74b35f 100644
--- a/src/cmd/internal/obj/pass.go
+++ b/src/cmd/internal/obj/pass.go
@@ -90,13 +90,12 @@
 			return
 		}
 
-		if a.Reg != 0 || a.Scale != 0 || a.Name != 0 || a.Sym != nil || a.U.Bits != 0 {
+		if a.Reg != 0 || a.Scale != 0 || a.Name != 0 || a.Sym != nil || a.Val != nil {
 			break
 		}
 		return
 
-	case TYPE_FCONST,
-		TYPE_SCONST:
+	case TYPE_FCONST, TYPE_SCONST:
 		if a.Reg != 0 || a.Index != 0 || a.Scale != 0 || a.Name != 0 || a.Offset != 0 || a.Sym != nil {
 			break
 		}
@@ -111,7 +110,7 @@
 		return
 
 	case TYPE_ADDR:
-		if a.U.Bits != 0 {
+		if a.Val != nil {
 			break
 		}
 		if a.Reg == 0 && a.Index == 0 && a.Scale == 0 && a.Name == 0 && a.Sym == nil {
@@ -120,13 +119,13 @@
 		return
 
 	case TYPE_SHIFT:
-		if a.Index != 0 || a.Scale != 0 || a.Name != 0 || a.Sym != nil || a.U.Bits != 0 {
+		if a.Index != 0 || a.Scale != 0 || a.Name != 0 || a.Sym != nil || a.Val != nil {
 			break
 		}
 		return
 
 	case TYPE_REGREG:
-		if a.Index != 0 || a.Scale != 0 || a.Name != 0 || a.Sym != nil || a.U.Bits != 0 {
+		if a.Index != 0 || a.Scale != 0 || a.Name != 0 || a.Sym != nil || a.Val != nil {
 			break
 		}
 		return
@@ -140,7 +139,7 @@
 	// Expect sym and name to be set, nothing else.
 	// Technically more is allowed, but this is only used for *name(SB).
 	case TYPE_INDIR:
-		if a.Reg != 0 || a.Index != 0 || a.Scale != 0 || a.Name == 0 || a.Offset != 0 || a.Sym == nil || a.U.Bits != 0 {
+		if a.Reg != 0 || a.Index != 0 || a.Scale != 0 || a.Name == 0 || a.Offset != 0 || a.Sym == nil || a.Val != nil {
 			break
 		}
 		return
@@ -167,10 +166,9 @@
 		if p.To.Type != TYPE_BRANCH {
 			continue
 		}
-		if p.To.U.Branch != nil {
-			// TODO: Remove to.u.branch in favor of p->pcond.
-			p.Pcond = p.To.U.Branch
-
+		if p.To.Val != nil {
+			// TODO: Remove To.Val.(*Prog) in favor of p->pcond.
+			p.Pcond = p.To.Val.(*Prog)
 			continue
 		}
 
@@ -198,7 +196,7 @@
 			p.To.Type = TYPE_NONE
 		}
 
-		p.To.U.Branch = q
+		p.To.Val = q
 		p.Pcond = q
 	}
 
diff --git a/src/cmd/internal/obj/ppc64/9.out.go b/src/cmd/internal/obj/ppc64/9.out.go
index 3030455..208dfa3 100644
--- a/src/cmd/internal/obj/ppc64/9.out.go
+++ b/src/cmd/internal/obj/ppc64/9.out.go
@@ -31,7 +31,7 @@
 
 import "cmd/internal/obj"
 
-// auto generated by go tool dist
+//go:generate go run ../stringer.go -i $GOFILE -o anames.go -p ppc64
 
 /*
  * powerpc 64
@@ -39,11 +39,10 @@
 const (
 	NSNAME = 8
 	NSYM   = 50
-	NREG   = 32
-	NFREG  = 32
+	NREG   = 32 /* number of general registers */
+	NFREG  = 32 /* number of floating point registers */
 )
 
-// avoid conflict with ucontext.h. sigh.
 const (
 	REG_R0 = obj.RBasePPC64 + iota
 	REG_R1
@@ -77,7 +76,8 @@
 	REG_R29
 	REG_R30
 	REG_R31
-	REG_F0 = obj.RBasePPC64 + 32 + iota - 32
+
+	REG_F0
 	REG_F1
 	REG_F2
 	REG_F3
@@ -109,8 +109,8 @@
 	REG_F29
 	REG_F30
 	REG_F31
-	REG_SPECIAL = obj.RBasePPC64 + 64
-	REG_CR0     = obj.RBasePPC64 + 64 + iota - 65
+
+	REG_CR0
 	REG_CR1
 	REG_CR2
 	REG_CR3
@@ -118,37 +118,43 @@
 	REG_CR5
 	REG_CR6
 	REG_CR7
-	REG_MSR = obj.RBasePPC64 + 72 + iota - 73
+
+	REG_MSR
 	REG_FPSCR
 	REG_CR
-	REG_SPR0 = obj.RBasePPC64 + 1024
-	REG_DCR0 = obj.RBasePPC64 + 2048
-	REG_XER  = REG_SPR0 + 1
-	REG_LR   = REG_SPR0 + 8
-	REG_CTR  = REG_SPR0 + 9
-	REGZERO  = REG_R0
+
+	REG_SPECIAL = REG_CR0
+
+	REG_SPR0 = obj.RBasePPC64 + 1024 // first of 1024 registers
+	REG_DCR0 = obj.RBasePPC64 + 2048 // first of 1024 registers
+
+	REG_XER = REG_SPR0 + 1
+	REG_LR  = REG_SPR0 + 8
+	REG_CTR = REG_SPR0 + 9
+
+	REGZERO  = REG_R0 /* set to zero */
 	REGSP    = REG_R1
 	REGSB    = REG_R2
 	REGRET   = REG_R3
-	REGARG   = -1
-	REGRT1   = REG_R3
-	REGRT2   = REG_R4
-	REGMIN   = REG_R7
-	REGCTXT  = REG_R11
-	REGTLS   = REG_R13
+	REGARG   = -1      /* -1 disables passing the first argument in register */
+	REGRT1   = REG_R3  /* reserved for runtime, duffzero and duffcopy */
+	REGRT2   = REG_R4  /* reserved for runtime, duffcopy */
+	REGMIN   = REG_R7  /* register variables allocated from here to REGMAX */
+	REGCTXT  = REG_R11 /* context for closures */
+	REGTLS   = REG_R13 /* C ABI TLS base pointer */
 	REGMAX   = REG_R27
-	REGEXT   = REG_R30
-	REGG     = REG_R30
-	REGTMP   = REG_R31
+	REGEXT   = REG_R30 /* external registers allocated from here down */
+	REGG     = REG_R30 /* G */
+	REGTMP   = REG_R31 /* used by the linker */
 	FREGRET  = REG_F0
-	FREGMIN  = REG_F17
-	FREGMAX  = REG_F26
-	FREGEXT  = REG_F26
-	FREGCVI  = REG_F27
-	FREGZERO = REG_F28
-	FREGHALF = REG_F29
-	FREGONE  = REG_F30
-	FREGTWO  = REG_F31
+	FREGMIN  = REG_F17 /* first register variable */
+	FREGMAX  = REG_F26 /* last register variable for 9g only */
+	FREGEXT  = REG_F26 /* first external register */
+	FREGCVI  = REG_F27 /* floating conversion constant */
+	FREGZERO = REG_F28 /* both float and double */
+	FREGHALF = REG_F29 /* double */
+	FREGONE  = REG_F30 /* double */
+	FREGTWO  = REG_F31 /* double */
 )
 
 /*
@@ -166,6 +172,7 @@
 )
 
 const (
+	/* mark flags */
 	LABEL   = 1 << 0
 	LEAF    = 1 << 1
 	FLOAT   = 1 << 2
@@ -183,19 +190,19 @@
 	C_REG
 	C_FREG
 	C_CREG
-	C_SPR
+	C_SPR /* special processor register */
 	C_ZCON
-	C_SCON
-	C_UCON
-	C_ADDCON
-	C_ANDCON
-	C_LCON
-	C_DCON
-	C_SACON
+	C_SCON   /* 16 bit signed */
+	C_UCON   /* 32 bit signed, low 16 bits 0 */
+	C_ADDCON /* -0x8000 <= v < 0 */
+	C_ANDCON /* 0 < v <= 0xFFFF */
+	C_LCON   /* other 32 */
+	C_DCON   /* other 64 (could subdivide further) */
+	C_SACON  /* $n(REG) where n <= int16 */
 	C_SECON
-	C_LACON
+	C_LACON /* $n(REG) where int16 < n <= int32 */
 	C_LECON
-	C_DACON
+	C_DACON /* $n(REG) where int32 < n */
 	C_SBRA
 	C_LBRA
 	C_SAUTO
@@ -214,11 +221,12 @@
 	C_GOK
 	C_ADDR
 	C_TEXTSIZE
-	C_NCLASS
+
+	C_NCLASS /* must be the last */
 )
 
 const (
-	AADD = obj.A_ARCHSPECIFIC + iota
+	AADD = obj.ABasePPC64 + obj.A_ARCHSPECIFIC + iota
 	AADDCC
 	AADDV
 	AADDVCC
@@ -414,6 +422,7 @@
 	ASYNC
 	AXOR
 	AXORCC
+
 	ADCBF
 	ADCBI
 	ADCBST
@@ -430,9 +439,13 @@
 	ATLBIEL
 	ATLBSYNC
 	ATW
+
 	ASYSCALL
 	AWORD
+
 	ARFCI
+
+	/* optional on 32-bit */
 	AFRES
 	AFRESCC
 	AFRSQRTE
@@ -443,9 +456,12 @@
 	AFSQRTCC
 	AFSQRTS
 	AFSQRTSCC
+
+	/* 64-bit */
+
 	ACNTLZD
 	ACNTLZDCC
-	ACMPW
+	ACMPW /* CMP with L=0 */
 	ACMPWU
 	ADIVD
 	ADIVDCC
@@ -457,6 +473,7 @@
 	ADIVDUV
 	AEXTSW
 	AEXTSWCC
+	/* AFCFIW; AFCFIWCC */
 	AFCFID
 	AFCFIDCC
 	AFCTID
@@ -498,6 +515,8 @@
 	ASRDCC
 	ASTDCCC
 	ATD
+
+	/* 64-bit pseudo operation */
 	ADWORD
 	AREMD
 	AREMDCC
@@ -507,8 +526,13 @@
 	AREMDUCC
 	AREMDUV
 	AREMDUVCC
+
+	/* more 64-bit operations */
 	AHRFID
+
 	ALAST
+
+	// aliases
 	ABR     = obj.AJMP
 	ABL     = obj.ACALL
 	ARETURN = obj.ARET
diff --git a/src/cmd/internal/obj/ppc64/anames.go b/src/cmd/internal/obj/ppc64/anames.go
new file mode 100644
index 0000000..09ed54c
--- /dev/null
+++ b/src/cmd/internal/obj/ppc64/anames.go
@@ -0,0 +1,300 @@
+// Generated by stringer -i 9.out.go -o anames.go -p ppc64
+// Do not edit.
+
+package ppc64
+
+import "cmd/internal/obj"
+
+var Anames = []string{
+	obj.A_ARCHSPECIFIC: "ADD",
+	"ADDCC",
+	"ADDV",
+	"ADDVCC",
+	"ADDC",
+	"ADDCCC",
+	"ADDCV",
+	"ADDCVCC",
+	"ADDME",
+	"ADDMECC",
+	"ADDMEVCC",
+	"ADDMEV",
+	"ADDE",
+	"ADDECC",
+	"ADDEVCC",
+	"ADDEV",
+	"ADDZE",
+	"ADDZECC",
+	"ADDZEVCC",
+	"ADDZEV",
+	"AND",
+	"ANDCC",
+	"ANDN",
+	"ANDNCC",
+	"BC",
+	"BCL",
+	"BEQ",
+	"BGE",
+	"BGT",
+	"BLE",
+	"BLT",
+	"BNE",
+	"BVC",
+	"BVS",
+	"CMP",
+	"CMPU",
+	"CNTLZW",
+	"CNTLZWCC",
+	"CRAND",
+	"CRANDN",
+	"CREQV",
+	"CRNAND",
+	"CRNOR",
+	"CROR",
+	"CRORN",
+	"CRXOR",
+	"DIVW",
+	"DIVWCC",
+	"DIVWVCC",
+	"DIVWV",
+	"DIVWU",
+	"DIVWUCC",
+	"DIVWUVCC",
+	"DIVWUV",
+	"EQV",
+	"EQVCC",
+	"EXTSB",
+	"EXTSBCC",
+	"EXTSH",
+	"EXTSHCC",
+	"FABS",
+	"FABSCC",
+	"FADD",
+	"FADDCC",
+	"FADDS",
+	"FADDSCC",
+	"FCMPO",
+	"FCMPU",
+	"FCTIW",
+	"FCTIWCC",
+	"FCTIWZ",
+	"FCTIWZCC",
+	"FDIV",
+	"FDIVCC",
+	"FDIVS",
+	"FDIVSCC",
+	"FMADD",
+	"FMADDCC",
+	"FMADDS",
+	"FMADDSCC",
+	"FMOVD",
+	"FMOVDCC",
+	"FMOVDU",
+	"FMOVS",
+	"FMOVSU",
+	"FMSUB",
+	"FMSUBCC",
+	"FMSUBS",
+	"FMSUBSCC",
+	"FMUL",
+	"FMULCC",
+	"FMULS",
+	"FMULSCC",
+	"FNABS",
+	"FNABSCC",
+	"FNEG",
+	"FNEGCC",
+	"FNMADD",
+	"FNMADDCC",
+	"FNMADDS",
+	"FNMADDSCC",
+	"FNMSUB",
+	"FNMSUBCC",
+	"FNMSUBS",
+	"FNMSUBSCC",
+	"FRSP",
+	"FRSPCC",
+	"FSUB",
+	"FSUBCC",
+	"FSUBS",
+	"FSUBSCC",
+	"MOVMW",
+	"LSW",
+	"LWAR",
+	"MOVWBR",
+	"MOVB",
+	"MOVBU",
+	"MOVBZ",
+	"MOVBZU",
+	"MOVH",
+	"MOVHBR",
+	"MOVHU",
+	"MOVHZ",
+	"MOVHZU",
+	"MOVW",
+	"MOVWU",
+	"MOVFL",
+	"MOVCRFS",
+	"MTFSB0",
+	"MTFSB0CC",
+	"MTFSB1",
+	"MTFSB1CC",
+	"MULHW",
+	"MULHWCC",
+	"MULHWU",
+	"MULHWUCC",
+	"MULLW",
+	"MULLWCC",
+	"MULLWVCC",
+	"MULLWV",
+	"NAND",
+	"NANDCC",
+	"NEG",
+	"NEGCC",
+	"NEGVCC",
+	"NEGV",
+	"NOR",
+	"NORCC",
+	"OR",
+	"ORCC",
+	"ORN",
+	"ORNCC",
+	"REM",
+	"REMCC",
+	"REMV",
+	"REMVCC",
+	"REMU",
+	"REMUCC",
+	"REMUV",
+	"REMUVCC",
+	"RFI",
+	"RLWMI",
+	"RLWMICC",
+	"RLWNM",
+	"RLWNMCC",
+	"SLW",
+	"SLWCC",
+	"SRW",
+	"SRAW",
+	"SRAWCC",
+	"SRWCC",
+	"STSW",
+	"STWCCC",
+	"SUB",
+	"SUBCC",
+	"SUBVCC",
+	"SUBC",
+	"SUBCCC",
+	"SUBCV",
+	"SUBCVCC",
+	"SUBME",
+	"SUBMECC",
+	"SUBMEVCC",
+	"SUBMEV",
+	"SUBV",
+	"SUBE",
+	"SUBECC",
+	"SUBEV",
+	"SUBEVCC",
+	"SUBZE",
+	"SUBZECC",
+	"SUBZEVCC",
+	"SUBZEV",
+	"SYNC",
+	"XOR",
+	"XORCC",
+	"DCBF",
+	"DCBI",
+	"DCBST",
+	"DCBT",
+	"DCBTST",
+	"DCBZ",
+	"ECIWX",
+	"ECOWX",
+	"EIEIO",
+	"ICBI",
+	"ISYNC",
+	"PTESYNC",
+	"TLBIE",
+	"TLBIEL",
+	"TLBSYNC",
+	"TW",
+	"SYSCALL",
+	"WORD",
+	"RFCI",
+	"FRES",
+	"FRESCC",
+	"FRSQRTE",
+	"FRSQRTECC",
+	"FSEL",
+	"FSELCC",
+	"FSQRT",
+	"FSQRTCC",
+	"FSQRTS",
+	"FSQRTSCC",
+	"CNTLZD",
+	"CNTLZDCC",
+	"CMPW",
+	"CMPWU",
+	"DIVD",
+	"DIVDCC",
+	"DIVDVCC",
+	"DIVDV",
+	"DIVDU",
+	"DIVDUCC",
+	"DIVDUVCC",
+	"DIVDUV",
+	"EXTSW",
+	"EXTSWCC",
+	"FCFID",
+	"FCFIDCC",
+	"FCTID",
+	"FCTIDCC",
+	"FCTIDZ",
+	"FCTIDZCC",
+	"LDAR",
+	"MOVD",
+	"MOVDU",
+	"MOVWZ",
+	"MOVWZU",
+	"MULHD",
+	"MULHDCC",
+	"MULHDU",
+	"MULHDUCC",
+	"MULLD",
+	"MULLDCC",
+	"MULLDVCC",
+	"MULLDV",
+	"RFID",
+	"RLDMI",
+	"RLDMICC",
+	"RLDC",
+	"RLDCCC",
+	"RLDCR",
+	"RLDCRCC",
+	"RLDCL",
+	"RLDCLCC",
+	"SLBIA",
+	"SLBIE",
+	"SLBMFEE",
+	"SLBMFEV",
+	"SLBMTE",
+	"SLD",
+	"SLDCC",
+	"SRD",
+	"SRAD",
+	"SRADCC",
+	"SRDCC",
+	"STDCCC",
+	"TD",
+	"DWORD",
+	"REMD",
+	"REMDCC",
+	"REMDV",
+	"REMDVCC",
+	"REMDU",
+	"REMDUCC",
+	"REMDUV",
+	"REMDUVCC",
+	"HRFID",
+	"LAST",
+}
diff --git a/src/cmd/internal/obj/ppc64/anames9.go b/src/cmd/internal/obj/ppc64/anames9.go
index 9d755de..b48e516 100644
--- a/src/cmd/internal/obj/ppc64/anames9.go
+++ b/src/cmd/internal/obj/ppc64/anames9.go
@@ -1,321 +1,5 @@
 package ppc64
 
-/*
- * this is the ranlib header
- */
-var Anames = []string{
-	"XXX",
-	"CALL",
-	"CHECKNIL",
-	"DATA",
-	"DUFFCOPY",
-	"DUFFZERO",
-	"END",
-	"FUNCDATA",
-	"GLOBL",
-	"JMP",
-	"NOP",
-	"PCDATA",
-	"RET",
-	"TEXT",
-	"TYPE",
-	"UNDEF",
-	"USEFIELD",
-	"VARDEF",
-	"VARKILL",
-	"ADD",
-	"ADDCC",
-	"ADDV",
-	"ADDVCC",
-	"ADDC",
-	"ADDCCC",
-	"ADDCV",
-	"ADDCVCC",
-	"ADDME",
-	"ADDMECC",
-	"ADDMEVCC",
-	"ADDMEV",
-	"ADDE",
-	"ADDECC",
-	"ADDEVCC",
-	"ADDEV",
-	"ADDZE",
-	"ADDZECC",
-	"ADDZEVCC",
-	"ADDZEV",
-	"AND",
-	"ANDCC",
-	"ANDN",
-	"ANDNCC",
-	"BC",
-	"BCL",
-	"BEQ",
-	"BGE",
-	"BGT",
-	"BLE",
-	"BLT",
-	"BNE",
-	"BVC",
-	"BVS",
-	"CMP",
-	"CMPU",
-	"CNTLZW",
-	"CNTLZWCC",
-	"CRAND",
-	"CRANDN",
-	"CREQV",
-	"CRNAND",
-	"CRNOR",
-	"CROR",
-	"CRORN",
-	"CRXOR",
-	"DIVW",
-	"DIVWCC",
-	"DIVWVCC",
-	"DIVWV",
-	"DIVWU",
-	"DIVWUCC",
-	"DIVWUVCC",
-	"DIVWUV",
-	"EQV",
-	"EQVCC",
-	"EXTSB",
-	"EXTSBCC",
-	"EXTSH",
-	"EXTSHCC",
-	"FABS",
-	"FABSCC",
-	"FADD",
-	"FADDCC",
-	"FADDS",
-	"FADDSCC",
-	"FCMPO",
-	"FCMPU",
-	"FCTIW",
-	"FCTIWCC",
-	"FCTIWZ",
-	"FCTIWZCC",
-	"FDIV",
-	"FDIVCC",
-	"FDIVS",
-	"FDIVSCC",
-	"FMADD",
-	"FMADDCC",
-	"FMADDS",
-	"FMADDSCC",
-	"FMOVD",
-	"FMOVDCC",
-	"FMOVDU",
-	"FMOVS",
-	"FMOVSU",
-	"FMSUB",
-	"FMSUBCC",
-	"FMSUBS",
-	"FMSUBSCC",
-	"FMUL",
-	"FMULCC",
-	"FMULS",
-	"FMULSCC",
-	"FNABS",
-	"FNABSCC",
-	"FNEG",
-	"FNEGCC",
-	"FNMADD",
-	"FNMADDCC",
-	"FNMADDS",
-	"FNMADDSCC",
-	"FNMSUB",
-	"FNMSUBCC",
-	"FNMSUBS",
-	"FNMSUBSCC",
-	"FRSP",
-	"FRSPCC",
-	"FSUB",
-	"FSUBCC",
-	"FSUBS",
-	"FSUBSCC",
-	"MOVMW",
-	"LSW",
-	"LWAR",
-	"MOVWBR",
-	"MOVB",
-	"MOVBU",
-	"MOVBZ",
-	"MOVBZU",
-	"MOVH",
-	"MOVHBR",
-	"MOVHU",
-	"MOVHZ",
-	"MOVHZU",
-	"MOVW",
-	"MOVWU",
-	"MOVFL",
-	"MOVCRFS",
-	"MTFSB0",
-	"MTFSB0CC",
-	"MTFSB1",
-	"MTFSB1CC",
-	"MULHW",
-	"MULHWCC",
-	"MULHWU",
-	"MULHWUCC",
-	"MULLW",
-	"MULLWCC",
-	"MULLWVCC",
-	"MULLWV",
-	"NAND",
-	"NANDCC",
-	"NEG",
-	"NEGCC",
-	"NEGVCC",
-	"NEGV",
-	"NOR",
-	"NORCC",
-	"OR",
-	"ORCC",
-	"ORN",
-	"ORNCC",
-	"REM",
-	"REMCC",
-	"REMV",
-	"REMVCC",
-	"REMU",
-	"REMUCC",
-	"REMUV",
-	"REMUVCC",
-	"RFI",
-	"RLWMI",
-	"RLWMICC",
-	"RLWNM",
-	"RLWNMCC",
-	"SLW",
-	"SLWCC",
-	"SRW",
-	"SRAW",
-	"SRAWCC",
-	"SRWCC",
-	"STSW",
-	"STWCCC",
-	"SUB",
-	"SUBCC",
-	"SUBVCC",
-	"SUBC",
-	"SUBCCC",
-	"SUBCV",
-	"SUBCVCC",
-	"SUBME",
-	"SUBMECC",
-	"SUBMEVCC",
-	"SUBMEV",
-	"SUBV",
-	"SUBE",
-	"SUBECC",
-	"SUBEV",
-	"SUBEVCC",
-	"SUBZE",
-	"SUBZECC",
-	"SUBZEVCC",
-	"SUBZEV",
-	"SYNC",
-	"XOR",
-	"XORCC",
-	"DCBF",
-	"DCBI",
-	"DCBST",
-	"DCBT",
-	"DCBTST",
-	"DCBZ",
-	"ECIWX",
-	"ECOWX",
-	"EIEIO",
-	"ICBI",
-	"ISYNC",
-	"PTESYNC",
-	"TLBIE",
-	"TLBIEL",
-	"TLBSYNC",
-	"TW",
-	"SYSCALL",
-	"WORD",
-	"RFCI",
-	"FRES",
-	"FRESCC",
-	"FRSQRTE",
-	"FRSQRTECC",
-	"FSEL",
-	"FSELCC",
-	"FSQRT",
-	"FSQRTCC",
-	"FSQRTS",
-	"FSQRTSCC",
-	"CNTLZD",
-	"CNTLZDCC",
-	"CMPW",
-	"CMPWU",
-	"DIVD",
-	"DIVDCC",
-	"DIVDVCC",
-	"DIVDV",
-	"DIVDU",
-	"DIVDUCC",
-	"DIVDUVCC",
-	"DIVDUV",
-	"EXTSW",
-	"EXTSWCC",
-	"FCFID",
-	"FCFIDCC",
-	"FCTID",
-	"FCTIDCC",
-	"FCTIDZ",
-	"FCTIDZCC",
-	"LDAR",
-	"MOVD",
-	"MOVDU",
-	"MOVWZ",
-	"MOVWZU",
-	"MULHD",
-	"MULHDCC",
-	"MULHDU",
-	"MULHDUCC",
-	"MULLD",
-	"MULLDCC",
-	"MULLDVCC",
-	"MULLDV",
-	"RFID",
-	"RLDMI",
-	"RLDMICC",
-	"RLDC",
-	"RLDCCC",
-	"RLDCR",
-	"RLDCRCC",
-	"RLDCL",
-	"RLDCLCC",
-	"SLBIA",
-	"SLBIE",
-	"SLBMFEE",
-	"SLBMFEV",
-	"SLBMTE",
-	"SLD",
-	"SLDCC",
-	"SRD",
-	"SRAD",
-	"SRADCC",
-	"SRDCC",
-	"STDCCC",
-	"TD",
-	"DWORD",
-	"REMD",
-	"REMDCC",
-	"REMDV",
-	"REMDVCC",
-	"REMDU",
-	"REMDUCC",
-	"REMDUV",
-	"REMDUVCC",
-	"HRFID",
-	"LAST",
-}
-
 var cnames9 = []string{
 	"NONE",
 	"REG",
diff --git a/src/cmd/internal/obj/ppc64/asm9.go b/src/cmd/internal/obj/ppc64/asm9.go
index 42969d0..0a92a29 100644
--- a/src/cmd/internal/obj/ppc64/asm9.go
+++ b/src/cmd/internal/obj/ppc64/asm9.go
@@ -31,6 +31,7 @@
 
 import (
 	"cmd/internal/obj"
+	"encoding/binary"
 	"fmt"
 	"log"
 	"sort"
@@ -401,36 +402,27 @@
 	stop  []Optab
 }
 
-var oprange [ALAST]Oprang
+var oprange [ALAST & obj.AMask]Oprang
 
 var xcmp [C_NCLASS][C_NCLASS]uint8
 
 func span9(ctxt *obj.Link, cursym *obj.LSym) {
-	var p *obj.Prog
-	var q *obj.Prog
-	var o *Optab
-	var m int
-	var bflag int
-	var c int64
-	var otxt int64
-	var out [6]uint32
-	var i int32
-	var bp []byte
-
-	p = cursym.Text
+	p := cursym.Text
 	if p == nil || p.Link == nil { // handle external functions and ELF section symbols
 		return
 	}
 	ctxt.Cursym = cursym
 	ctxt.Autosize = int32(p.To.Offset + 8)
 
-	if oprange[AANDN].start == nil {
+	if oprange[AANDN&obj.AMask].start == nil {
 		buildop(ctxt)
 	}
 
-	c = 0
+	c := int64(0)
 	p.Pc = c
 
+	var m int
+	var o *Optab
 	for p = p.Link; p != nil; p = p.Link {
 		ctxt.Curp = p
 		p.Pc = c
@@ -454,8 +446,10 @@
 	 * generate extra passes putting branches
 	 * around jmps to fix. this is rare.
 	 */
-	bflag = 1
+	bflag := 1
 
+	var otxt int64
+	var q *obj.Prog
 	for bflag != 0 {
 		if ctxt.Debugvlog != 0 {
 			fmt.Fprintf(ctxt.Bso, "%5.2f span1\n", obj.Cputime())
@@ -516,8 +510,10 @@
 
 	obj.Symgrow(ctxt, cursym, cursym.Size)
 
-	bp = cursym.P
-	for p = cursym.Text.Link; p != nil; p = p.Link {
+	bp := cursym.P
+	var i int32
+	var out [6]uint32
+	for p := cursym.Text.Link; p != nil; p = p.Link {
 		ctxt.Pc = p.Pc
 		ctxt.Curp = p
 		o = oplook(ctxt, p)
@@ -541,8 +537,6 @@
 }
 
 func aclass(ctxt *obj.Link, a *obj.Addr) int {
-	var s *obj.LSym
-
 	switch a.Type {
 	case obj.TYPE_NONE:
 		return C_NONE
@@ -610,7 +604,7 @@
 			}
 			return C_LAUTO
 
-		case obj.TYPE_NONE:
+		case obj.NAME_NONE:
 			ctxt.Instoffset = a.Offset
 			if ctxt.Instoffset == 0 {
 				return C_ZOREG
@@ -645,7 +639,7 @@
 
 		case obj.NAME_EXTERN,
 			obj.NAME_STATIC:
-			s = a.Sym
+			s := a.Sym
 			if s == nil {
 				break
 			}
@@ -719,18 +713,7 @@
 }
 
 func oplook(ctxt *obj.Link, p *obj.Prog) *Optab {
-	var a1 int
-	var a2 int
-	var a3 int
-	var a4 int
-	var r int
-	var c1 []byte
-	var c3 []byte
-	var c4 []byte
-	var o []Optab
-	var e []Optab
-
-	a1 = int(p.Optab)
+	a1 := int(p.Optab)
 	if a1 != 0 {
 		return &optab[a1-1:][0]
 	}
@@ -741,36 +724,36 @@
 	}
 
 	a1--
-	a3 = int(p.From3.Class)
+	a3 := int(p.From3.Class)
 	if a3 == 0 {
 		a3 = aclass(ctxt, &p.From3) + 1
 		p.From3.Class = int8(a3)
 	}
 
 	a3--
-	a4 = int(p.To.Class)
+	a4 := int(p.To.Class)
 	if a4 == 0 {
 		a4 = aclass(ctxt, &p.To) + 1
 		p.To.Class = int8(a4)
 	}
 
 	a4--
-	a2 = C_NONE
+	a2 := C_NONE
 	if p.Reg != 0 {
 		a2 = C_REG
 	}
 
 	//print("oplook %P %d %d %d %d\n", p, a1, a2, a3, a4);
-	r = int(p.As)
+	r0 := p.As & obj.AMask
 
-	o = oprange[r].start
+	o := oprange[r0].start
 	if o == nil {
-		o = oprange[r].stop /* just generate an error */
+		o = oprange[r0].stop /* just generate an error */
 	}
-	e = oprange[r].stop
-	c1 = xcmp[a1][:]
-	c3 = xcmp[a3][:]
-	c4 = xcmp[a4][:]
+	e := oprange[r0].stop
+	c1 := xcmp[a1][:]
+	c3 := xcmp[a3][:]
+	c4 := xcmp[a4][:]
 	for ; -cap(o) < -cap(e); o = o[1:] {
 		if int(o[0].a2) == a2 {
 			if c1[o[0].a1] != 0 {
@@ -784,7 +767,7 @@
 		}
 	}
 
-	ctxt.Diag("illegal combination %v %v %v %v %v", Aconv(int(p.As)), DRconv(a1), DRconv(a2), DRconv(a3), DRconv(a4))
+	ctxt.Diag("illegal combination %v %v %v %v %v", obj.Aconv(int(p.As)), DRconv(a1), DRconv(a2), DRconv(a3), DRconv(a4))
 	prasm(p)
 	if o == nil {
 		o = optab
@@ -880,13 +863,9 @@
 }
 
 func (x ocmp) Less(i, j int) bool {
-	var p1 *Optab
-	var p2 *Optab
-	var n int
-
-	p1 = &x[i]
-	p2 = &x[j]
-	n = int(p1.as) - int(p2.as)
+	p1 := &x[i]
+	p2 := &x[j]
+	n := int(p1.as) - int(p2.as)
 	if n != 0 {
 		return n < 0
 	}
@@ -908,13 +887,14 @@
 	}
 	return false
 }
+func opset(a, b0 int16) {
+	oprange[a&obj.AMask] = oprange[b0]
+}
 
 func buildop(ctxt *obj.Link) {
-	var i int
 	var n int
-	var r int
 
-	for i = 0; i < C_NCLASS; i++ {
+	for i := 0; i < C_NCLASS; i++ {
 		for n = 0; n < C_NCLASS; n++ {
 			if cmp(n, i) {
 				xcmp[i][n] = 1
@@ -924,355 +904,356 @@
 	for n = 0; optab[n].as != obj.AXXX; n++ {
 	}
 	sort.Sort(ocmp(optab[:n]))
-	for i = 0; i < n; i++ {
-		r = int(optab[i].as)
-		oprange[r].start = optab[i:]
-		for int(optab[i].as) == r {
+	for i := 0; i < n; i++ {
+		r := optab[i].as
+		r0 := r & obj.AMask
+		oprange[r0].start = optab[i:]
+		for optab[i].as == r {
 			i++
 		}
-		oprange[r].stop = optab[i:]
+		oprange[r0].stop = optab[i:]
 		i--
 
 		switch r {
 		default:
-			ctxt.Diag("unknown op in build: %v", Aconv(r))
+			ctxt.Diag("unknown op in build: %v", obj.Aconv(int(r)))
 			log.Fatalf("bad code")
 
 		case ADCBF: /* unary indexed: op (b+a); op (b) */
-			oprange[ADCBI] = oprange[r]
+			opset(ADCBI, r0)
 
-			oprange[ADCBST] = oprange[r]
-			oprange[ADCBT] = oprange[r]
-			oprange[ADCBTST] = oprange[r]
-			oprange[ADCBZ] = oprange[r]
-			oprange[AICBI] = oprange[r]
+			opset(ADCBST, r0)
+			opset(ADCBT, r0)
+			opset(ADCBTST, r0)
+			opset(ADCBZ, r0)
+			opset(AICBI, r0)
 
 		case AECOWX: /* indexed store: op s,(b+a); op s,(b) */
-			oprange[ASTWCCC] = oprange[r]
+			opset(ASTWCCC, r0)
 
-			oprange[ASTDCCC] = oprange[r]
+			opset(ASTDCCC, r0)
 
 		case AREM: /* macro */
-			oprange[AREMCC] = oprange[r]
+			opset(AREMCC, r0)
 
-			oprange[AREMV] = oprange[r]
-			oprange[AREMVCC] = oprange[r]
+			opset(AREMV, r0)
+			opset(AREMVCC, r0)
 
 		case AREMU:
-			oprange[AREMU] = oprange[r]
-			oprange[AREMUCC] = oprange[r]
-			oprange[AREMUV] = oprange[r]
-			oprange[AREMUVCC] = oprange[r]
+			opset(AREMU, r0)
+			opset(AREMUCC, r0)
+			opset(AREMUV, r0)
+			opset(AREMUVCC, r0)
 
 		case AREMD:
-			oprange[AREMDCC] = oprange[r]
-			oprange[AREMDV] = oprange[r]
-			oprange[AREMDVCC] = oprange[r]
+			opset(AREMDCC, r0)
+			opset(AREMDV, r0)
+			opset(AREMDVCC, r0)
 
 		case AREMDU:
-			oprange[AREMDU] = oprange[r]
-			oprange[AREMDUCC] = oprange[r]
-			oprange[AREMDUV] = oprange[r]
-			oprange[AREMDUVCC] = oprange[r]
+			opset(AREMDU, r0)
+			opset(AREMDUCC, r0)
+			opset(AREMDUV, r0)
+			opset(AREMDUVCC, r0)
 
 		case ADIVW: /* op Rb[,Ra],Rd */
-			oprange[AMULHW] = oprange[r]
+			opset(AMULHW, r0)
 
-			oprange[AMULHWCC] = oprange[r]
-			oprange[AMULHWU] = oprange[r]
-			oprange[AMULHWUCC] = oprange[r]
-			oprange[AMULLWCC] = oprange[r]
-			oprange[AMULLWVCC] = oprange[r]
-			oprange[AMULLWV] = oprange[r]
-			oprange[ADIVWCC] = oprange[r]
-			oprange[ADIVWV] = oprange[r]
-			oprange[ADIVWVCC] = oprange[r]
-			oprange[ADIVWU] = oprange[r]
-			oprange[ADIVWUCC] = oprange[r]
-			oprange[ADIVWUV] = oprange[r]
-			oprange[ADIVWUVCC] = oprange[r]
-			oprange[AADDCC] = oprange[r]
-			oprange[AADDCV] = oprange[r]
-			oprange[AADDCVCC] = oprange[r]
-			oprange[AADDV] = oprange[r]
-			oprange[AADDVCC] = oprange[r]
-			oprange[AADDE] = oprange[r]
-			oprange[AADDECC] = oprange[r]
-			oprange[AADDEV] = oprange[r]
-			oprange[AADDEVCC] = oprange[r]
-			oprange[ACRAND] = oprange[r]
-			oprange[ACRANDN] = oprange[r]
-			oprange[ACREQV] = oprange[r]
-			oprange[ACRNAND] = oprange[r]
-			oprange[ACRNOR] = oprange[r]
-			oprange[ACROR] = oprange[r]
-			oprange[ACRORN] = oprange[r]
-			oprange[ACRXOR] = oprange[r]
-			oprange[AMULHD] = oprange[r]
-			oprange[AMULHDCC] = oprange[r]
-			oprange[AMULHDU] = oprange[r]
-			oprange[AMULHDUCC] = oprange[r]
-			oprange[AMULLD] = oprange[r]
-			oprange[AMULLDCC] = oprange[r]
-			oprange[AMULLDVCC] = oprange[r]
-			oprange[AMULLDV] = oprange[r]
-			oprange[ADIVD] = oprange[r]
-			oprange[ADIVDCC] = oprange[r]
-			oprange[ADIVDVCC] = oprange[r]
-			oprange[ADIVDV] = oprange[r]
-			oprange[ADIVDU] = oprange[r]
-			oprange[ADIVDUCC] = oprange[r]
-			oprange[ADIVDUVCC] = oprange[r]
-			oprange[ADIVDUCC] = oprange[r]
+			opset(AMULHWCC, r0)
+			opset(AMULHWU, r0)
+			opset(AMULHWUCC, r0)
+			opset(AMULLWCC, r0)
+			opset(AMULLWVCC, r0)
+			opset(AMULLWV, r0)
+			opset(ADIVWCC, r0)
+			opset(ADIVWV, r0)
+			opset(ADIVWVCC, r0)
+			opset(ADIVWU, r0)
+			opset(ADIVWUCC, r0)
+			opset(ADIVWUV, r0)
+			opset(ADIVWUVCC, r0)
+			opset(AADDCC, r0)
+			opset(AADDCV, r0)
+			opset(AADDCVCC, r0)
+			opset(AADDV, r0)
+			opset(AADDVCC, r0)
+			opset(AADDE, r0)
+			opset(AADDECC, r0)
+			opset(AADDEV, r0)
+			opset(AADDEVCC, r0)
+			opset(ACRAND, r0)
+			opset(ACRANDN, r0)
+			opset(ACREQV, r0)
+			opset(ACRNAND, r0)
+			opset(ACRNOR, r0)
+			opset(ACROR, r0)
+			opset(ACRORN, r0)
+			opset(ACRXOR, r0)
+			opset(AMULHD, r0)
+			opset(AMULHDCC, r0)
+			opset(AMULHDU, r0)
+			opset(AMULHDUCC, r0)
+			opset(AMULLD, r0)
+			opset(AMULLDCC, r0)
+			opset(AMULLDVCC, r0)
+			opset(AMULLDV, r0)
+			opset(ADIVD, r0)
+			opset(ADIVDCC, r0)
+			opset(ADIVDVCC, r0)
+			opset(ADIVDV, r0)
+			opset(ADIVDU, r0)
+			opset(ADIVDUCC, r0)
+			opset(ADIVDUVCC, r0)
+			opset(ADIVDUCC, r0)
 
 		case AMOVBZ: /* lbz, stz, rlwm(r/r), lhz, lha, stz, and x variants */
-			oprange[AMOVH] = oprange[r]
+			opset(AMOVH, r0)
 
-			oprange[AMOVHZ] = oprange[r]
+			opset(AMOVHZ, r0)
 
 		case AMOVBZU: /* lbz[x]u, stb[x]u, lhz[x]u, lha[x]u, sth[u]x, ld[x]u, std[u]x */
-			oprange[AMOVHU] = oprange[r]
+			opset(AMOVHU, r0)
 
-			oprange[AMOVHZU] = oprange[r]
-			oprange[AMOVWU] = oprange[r]
-			oprange[AMOVWZU] = oprange[r]
-			oprange[AMOVDU] = oprange[r]
-			oprange[AMOVMW] = oprange[r]
+			opset(AMOVHZU, r0)
+			opset(AMOVWU, r0)
+			opset(AMOVWZU, r0)
+			opset(AMOVDU, r0)
+			opset(AMOVMW, r0)
 
 		case AAND: /* logical op Rb,Rs,Ra; no literal */
-			oprange[AANDN] = oprange[r]
+			opset(AANDN, r0)
 
-			oprange[AANDNCC] = oprange[r]
-			oprange[AEQV] = oprange[r]
-			oprange[AEQVCC] = oprange[r]
-			oprange[ANAND] = oprange[r]
-			oprange[ANANDCC] = oprange[r]
-			oprange[ANOR] = oprange[r]
-			oprange[ANORCC] = oprange[r]
-			oprange[AORCC] = oprange[r]
-			oprange[AORN] = oprange[r]
-			oprange[AORNCC] = oprange[r]
-			oprange[AXORCC] = oprange[r]
+			opset(AANDNCC, r0)
+			opset(AEQV, r0)
+			opset(AEQVCC, r0)
+			opset(ANAND, r0)
+			opset(ANANDCC, r0)
+			opset(ANOR, r0)
+			opset(ANORCC, r0)
+			opset(AORCC, r0)
+			opset(AORN, r0)
+			opset(AORNCC, r0)
+			opset(AXORCC, r0)
 
 		case AADDME: /* op Ra, Rd */
-			oprange[AADDMECC] = oprange[r]
+			opset(AADDMECC, r0)
 
-			oprange[AADDMEV] = oprange[r]
-			oprange[AADDMEVCC] = oprange[r]
-			oprange[AADDZE] = oprange[r]
-			oprange[AADDZECC] = oprange[r]
-			oprange[AADDZEV] = oprange[r]
-			oprange[AADDZEVCC] = oprange[r]
-			oprange[ASUBME] = oprange[r]
-			oprange[ASUBMECC] = oprange[r]
-			oprange[ASUBMEV] = oprange[r]
-			oprange[ASUBMEVCC] = oprange[r]
-			oprange[ASUBZE] = oprange[r]
-			oprange[ASUBZECC] = oprange[r]
-			oprange[ASUBZEV] = oprange[r]
-			oprange[ASUBZEVCC] = oprange[r]
+			opset(AADDMEV, r0)
+			opset(AADDMEVCC, r0)
+			opset(AADDZE, r0)
+			opset(AADDZECC, r0)
+			opset(AADDZEV, r0)
+			opset(AADDZEVCC, r0)
+			opset(ASUBME, r0)
+			opset(ASUBMECC, r0)
+			opset(ASUBMEV, r0)
+			opset(ASUBMEVCC, r0)
+			opset(ASUBZE, r0)
+			opset(ASUBZECC, r0)
+			opset(ASUBZEV, r0)
+			opset(ASUBZEVCC, r0)
 
 		case AADDC:
-			oprange[AADDCCC] = oprange[r]
+			opset(AADDCCC, r0)
 
 		case ABEQ:
-			oprange[ABGE] = oprange[r]
-			oprange[ABGT] = oprange[r]
-			oprange[ABLE] = oprange[r]
-			oprange[ABLT] = oprange[r]
-			oprange[ABNE] = oprange[r]
-			oprange[ABVC] = oprange[r]
-			oprange[ABVS] = oprange[r]
+			opset(ABGE, r0)
+			opset(ABGT, r0)
+			opset(ABLE, r0)
+			opset(ABLT, r0)
+			opset(ABNE, r0)
+			opset(ABVC, r0)
+			opset(ABVS, r0)
 
 		case ABR:
-			oprange[ABL] = oprange[r]
+			opset(ABL, r0)
 
 		case ABC:
-			oprange[ABCL] = oprange[r]
+			opset(ABCL, r0)
 
 		case AEXTSB: /* op Rs, Ra */
-			oprange[AEXTSBCC] = oprange[r]
+			opset(AEXTSBCC, r0)
 
-			oprange[AEXTSH] = oprange[r]
-			oprange[AEXTSHCC] = oprange[r]
-			oprange[ACNTLZW] = oprange[r]
-			oprange[ACNTLZWCC] = oprange[r]
-			oprange[ACNTLZD] = oprange[r]
-			oprange[AEXTSW] = oprange[r]
-			oprange[AEXTSWCC] = oprange[r]
-			oprange[ACNTLZDCC] = oprange[r]
+			opset(AEXTSH, r0)
+			opset(AEXTSHCC, r0)
+			opset(ACNTLZW, r0)
+			opset(ACNTLZWCC, r0)
+			opset(ACNTLZD, r0)
+			opset(AEXTSW, r0)
+			opset(AEXTSWCC, r0)
+			opset(ACNTLZDCC, r0)
 
 		case AFABS: /* fop [s,]d */
-			oprange[AFABSCC] = oprange[r]
+			opset(AFABSCC, r0)
 
-			oprange[AFNABS] = oprange[r]
-			oprange[AFNABSCC] = oprange[r]
-			oprange[AFNEG] = oprange[r]
-			oprange[AFNEGCC] = oprange[r]
-			oprange[AFRSP] = oprange[r]
-			oprange[AFRSPCC] = oprange[r]
-			oprange[AFCTIW] = oprange[r]
-			oprange[AFCTIWCC] = oprange[r]
-			oprange[AFCTIWZ] = oprange[r]
-			oprange[AFCTIWZCC] = oprange[r]
-			oprange[AFCTID] = oprange[r]
-			oprange[AFCTIDCC] = oprange[r]
-			oprange[AFCTIDZ] = oprange[r]
-			oprange[AFCTIDZCC] = oprange[r]
-			oprange[AFCFID] = oprange[r]
-			oprange[AFCFIDCC] = oprange[r]
-			oprange[AFRES] = oprange[r]
-			oprange[AFRESCC] = oprange[r]
-			oprange[AFRSQRTE] = oprange[r]
-			oprange[AFRSQRTECC] = oprange[r]
-			oprange[AFSQRT] = oprange[r]
-			oprange[AFSQRTCC] = oprange[r]
-			oprange[AFSQRTS] = oprange[r]
-			oprange[AFSQRTSCC] = oprange[r]
+			opset(AFNABS, r0)
+			opset(AFNABSCC, r0)
+			opset(AFNEG, r0)
+			opset(AFNEGCC, r0)
+			opset(AFRSP, r0)
+			opset(AFRSPCC, r0)
+			opset(AFCTIW, r0)
+			opset(AFCTIWCC, r0)
+			opset(AFCTIWZ, r0)
+			opset(AFCTIWZCC, r0)
+			opset(AFCTID, r0)
+			opset(AFCTIDCC, r0)
+			opset(AFCTIDZ, r0)
+			opset(AFCTIDZCC, r0)
+			opset(AFCFID, r0)
+			opset(AFCFIDCC, r0)
+			opset(AFRES, r0)
+			opset(AFRESCC, r0)
+			opset(AFRSQRTE, r0)
+			opset(AFRSQRTECC, r0)
+			opset(AFSQRT, r0)
+			opset(AFSQRTCC, r0)
+			opset(AFSQRTS, r0)
+			opset(AFSQRTSCC, r0)
 
 		case AFADD:
-			oprange[AFADDS] = oprange[r]
-			oprange[AFADDCC] = oprange[r]
-			oprange[AFADDSCC] = oprange[r]
-			oprange[AFDIV] = oprange[r]
-			oprange[AFDIVS] = oprange[r]
-			oprange[AFDIVCC] = oprange[r]
-			oprange[AFDIVSCC] = oprange[r]
-			oprange[AFSUB] = oprange[r]
-			oprange[AFSUBS] = oprange[r]
-			oprange[AFSUBCC] = oprange[r]
-			oprange[AFSUBSCC] = oprange[r]
+			opset(AFADDS, r0)
+			opset(AFADDCC, r0)
+			opset(AFADDSCC, r0)
+			opset(AFDIV, r0)
+			opset(AFDIVS, r0)
+			opset(AFDIVCC, r0)
+			opset(AFDIVSCC, r0)
+			opset(AFSUB, r0)
+			opset(AFSUBS, r0)
+			opset(AFSUBCC, r0)
+			opset(AFSUBSCC, r0)
 
 		case AFMADD:
-			oprange[AFMADDCC] = oprange[r]
-			oprange[AFMADDS] = oprange[r]
-			oprange[AFMADDSCC] = oprange[r]
-			oprange[AFMSUB] = oprange[r]
-			oprange[AFMSUBCC] = oprange[r]
-			oprange[AFMSUBS] = oprange[r]
-			oprange[AFMSUBSCC] = oprange[r]
-			oprange[AFNMADD] = oprange[r]
-			oprange[AFNMADDCC] = oprange[r]
-			oprange[AFNMADDS] = oprange[r]
-			oprange[AFNMADDSCC] = oprange[r]
-			oprange[AFNMSUB] = oprange[r]
-			oprange[AFNMSUBCC] = oprange[r]
-			oprange[AFNMSUBS] = oprange[r]
-			oprange[AFNMSUBSCC] = oprange[r]
-			oprange[AFSEL] = oprange[r]
-			oprange[AFSELCC] = oprange[r]
+			opset(AFMADDCC, r0)
+			opset(AFMADDS, r0)
+			opset(AFMADDSCC, r0)
+			opset(AFMSUB, r0)
+			opset(AFMSUBCC, r0)
+			opset(AFMSUBS, r0)
+			opset(AFMSUBSCC, r0)
+			opset(AFNMADD, r0)
+			opset(AFNMADDCC, r0)
+			opset(AFNMADDS, r0)
+			opset(AFNMADDSCC, r0)
+			opset(AFNMSUB, r0)
+			opset(AFNMSUBCC, r0)
+			opset(AFNMSUBS, r0)
+			opset(AFNMSUBSCC, r0)
+			opset(AFSEL, r0)
+			opset(AFSELCC, r0)
 
 		case AFMUL:
-			oprange[AFMULS] = oprange[r]
-			oprange[AFMULCC] = oprange[r]
-			oprange[AFMULSCC] = oprange[r]
+			opset(AFMULS, r0)
+			opset(AFMULCC, r0)
+			opset(AFMULSCC, r0)
 
 		case AFCMPO:
-			oprange[AFCMPU] = oprange[r]
+			opset(AFCMPU, r0)
 
 		case AMTFSB0:
-			oprange[AMTFSB0CC] = oprange[r]
-			oprange[AMTFSB1] = oprange[r]
-			oprange[AMTFSB1CC] = oprange[r]
+			opset(AMTFSB0CC, r0)
+			opset(AMTFSB1, r0)
+			opset(AMTFSB1CC, r0)
 
 		case ANEG: /* op [Ra,] Rd */
-			oprange[ANEGCC] = oprange[r]
+			opset(ANEGCC, r0)
 
-			oprange[ANEGV] = oprange[r]
-			oprange[ANEGVCC] = oprange[r]
+			opset(ANEGV, r0)
+			opset(ANEGVCC, r0)
 
 		case AOR: /* or/xor Rb,Rs,Ra; ori/xori $uimm,Rs,Ra; oris/xoris $uimm,Rs,Ra */
-			oprange[AXOR] = oprange[r]
+			opset(AXOR, r0)
 
 		case ASLW:
-			oprange[ASLWCC] = oprange[r]
-			oprange[ASRW] = oprange[r]
-			oprange[ASRWCC] = oprange[r]
+			opset(ASLWCC, r0)
+			opset(ASRW, r0)
+			opset(ASRWCC, r0)
 
 		case ASLD:
-			oprange[ASLDCC] = oprange[r]
-			oprange[ASRD] = oprange[r]
-			oprange[ASRDCC] = oprange[r]
+			opset(ASLDCC, r0)
+			opset(ASRD, r0)
+			opset(ASRDCC, r0)
 
 		case ASRAW: /* sraw Rb,Rs,Ra; srawi sh,Rs,Ra */
-			oprange[ASRAWCC] = oprange[r]
+			opset(ASRAWCC, r0)
 
 		case ASRAD: /* sraw Rb,Rs,Ra; srawi sh,Rs,Ra */
-			oprange[ASRADCC] = oprange[r]
+			opset(ASRADCC, r0)
 
 		case ASUB: /* SUB Ra,Rb,Rd => subf Rd,ra,rb */
-			oprange[ASUB] = oprange[r]
+			opset(ASUB, r0)
 
-			oprange[ASUBCC] = oprange[r]
-			oprange[ASUBV] = oprange[r]
-			oprange[ASUBVCC] = oprange[r]
-			oprange[ASUBCCC] = oprange[r]
-			oprange[ASUBCV] = oprange[r]
-			oprange[ASUBCVCC] = oprange[r]
-			oprange[ASUBE] = oprange[r]
-			oprange[ASUBECC] = oprange[r]
-			oprange[ASUBEV] = oprange[r]
-			oprange[ASUBEVCC] = oprange[r]
+			opset(ASUBCC, r0)
+			opset(ASUBV, r0)
+			opset(ASUBVCC, r0)
+			opset(ASUBCCC, r0)
+			opset(ASUBCV, r0)
+			opset(ASUBCVCC, r0)
+			opset(ASUBE, r0)
+			opset(ASUBECC, r0)
+			opset(ASUBEV, r0)
+			opset(ASUBEVCC, r0)
 
 		case ASYNC:
-			oprange[AISYNC] = oprange[r]
-			oprange[APTESYNC] = oprange[r]
-			oprange[ATLBSYNC] = oprange[r]
+			opset(AISYNC, r0)
+			opset(APTESYNC, r0)
+			opset(ATLBSYNC, r0)
 
 		case ARLWMI:
-			oprange[ARLWMICC] = oprange[r]
-			oprange[ARLWNM] = oprange[r]
-			oprange[ARLWNMCC] = oprange[r]
+			opset(ARLWMICC, r0)
+			opset(ARLWNM, r0)
+			opset(ARLWNMCC, r0)
 
 		case ARLDMI:
-			oprange[ARLDMICC] = oprange[r]
+			opset(ARLDMICC, r0)
 
 		case ARLDC:
-			oprange[ARLDCCC] = oprange[r]
+			opset(ARLDCCC, r0)
 
 		case ARLDCL:
-			oprange[ARLDCR] = oprange[r]
-			oprange[ARLDCLCC] = oprange[r]
-			oprange[ARLDCRCC] = oprange[r]
+			opset(ARLDCR, r0)
+			opset(ARLDCLCC, r0)
+			opset(ARLDCRCC, r0)
 
 		case AFMOVD:
-			oprange[AFMOVDCC] = oprange[r]
-			oprange[AFMOVDU] = oprange[r]
-			oprange[AFMOVS] = oprange[r]
-			oprange[AFMOVSU] = oprange[r]
+			opset(AFMOVDCC, r0)
+			opset(AFMOVDU, r0)
+			opset(AFMOVS, r0)
+			opset(AFMOVSU, r0)
 
 		case AECIWX:
-			oprange[ALWAR] = oprange[r]
-			oprange[ALDAR] = oprange[r]
+			opset(ALWAR, r0)
+			opset(ALDAR, r0)
 
 		case ASYSCALL: /* just the op; flow of control */
-			oprange[ARFI] = oprange[r]
+			opset(ARFI, r0)
 
-			oprange[ARFCI] = oprange[r]
-			oprange[ARFID] = oprange[r]
-			oprange[AHRFID] = oprange[r]
+			opset(ARFCI, r0)
+			opset(ARFID, r0)
+			opset(AHRFID, r0)
 
 		case AMOVHBR:
-			oprange[AMOVWBR] = oprange[r]
+			opset(AMOVWBR, r0)
 
 		case ASLBMFEE:
-			oprange[ASLBMFEV] = oprange[r]
+			opset(ASLBMFEV, r0)
 
 		case ATW:
-			oprange[ATD] = oprange[r]
+			opset(ATD, r0)
 
 		case ATLBIE:
-			oprange[ASLBIE] = oprange[r]
-			oprange[ATLBIEL] = oprange[r]
+			opset(ASLBIE, r0)
+			opset(ATLBIEL, r0)
 
 		case AEIEIO:
-			oprange[ASLBIA] = oprange[r]
+			opset(ASLBIA, r0)
 
 		case ACMP:
-			oprange[ACMPW] = oprange[r]
+			opset(ACMPW, r0)
 
 		case ACMPU:
-			oprange[ACMPWU] = oprange[r]
+			opset(ACMPWU, r0)
 
 		case AADD,
 			AANDCC, /* and. Rb,Rs,Ra; andi. $uimm,Rs,Ra; andis. $uimm,Rs,Ra */
@@ -1350,6 +1331,7 @@
 }
 
 const (
+	/* each rhs is OPVCC(_, _, _, _) */
 	OP_ADD    = 31<<26 | 266<<1 | 0<<10 | 0
 	OP_ADDI   = 14<<26 | 0<<1 | 0<<10 | 0
 	OP_ADDIS  = 15<<26 | 0<<1 | 0<<10 | 0
@@ -1392,9 +1374,7 @@
 
 // add R_ADDRPOWER relocation to symbol s for the two instructions o1 and o2.
 func addaddrreloc(ctxt *obj.Link, s *obj.LSym, o1 *uint32, o2 *uint32) {
-	var rel *obj.Reloc
-
-	rel = obj.Addrel(ctxt.Cursym)
+	rel := obj.Addrel(ctxt.Cursym)
 	rel.Off = int32(ctxt.Pc)
 	rel.Siz = 8
 	rel.Sym = s
@@ -1406,13 +1386,11 @@
  * 32-bit masks
  */
 func getmask(m []byte, v uint32) bool {
-	var i int
-
 	m[1] = 0
 	m[0] = m[1]
 	if v != ^uint32(0) && v&(1<<31) != 0 && v&1 != 0 { /* MB > ME */
 		if getmask(m, ^v) {
-			i = int(m[0])
+			i := int(m[0])
 			m[0] = m[1] + 1
 			m[1] = byte(i - 1)
 			return true
@@ -1421,7 +1399,7 @@
 		return false
 	}
 
-	for i = 0; i < 32; i++ {
+	for i := 0; i < 32; i++ {
 		if v&(1<<uint(31-i)) != 0 {
 			m[0] = byte(i)
 			for {
@@ -1454,11 +1432,9 @@
  * 64-bit masks (rldic etc)
  */
 func getmask64(m []byte, v uint64) bool {
-	var i int
-
 	m[1] = 0
 	m[0] = m[1]
-	for i = 0; i < 64; i++ {
+	for i := 0; i < 64; i++ {
 		if v&(uint64(1)<<uint(63-i)) != 0 {
 			m[0] = byte(i)
 			for {
@@ -1488,9 +1464,7 @@
 }
 
 func loadu32(r int, d int64) uint32 {
-	var v int32
-
-	v = int32(d >> 16)
+	v := int32(d >> 16)
 	if isuint32(uint64(d)) {
 		return LOP_IRR(OP_ORIS, uint32(r), REGZERO, uint32(v))
 	}
@@ -1505,24 +1479,11 @@
 }
 
 func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) {
-	var o1 uint32
-	var o2 uint32
-	var o3 uint32
-	var o4 uint32
-	var o5 uint32
-	var v int32
-	var t int32
-	var d int64
-	var r int
-	var a int
-	var mask [2]uint8
-	var rel *obj.Reloc
-
-	o1 = 0
-	o2 = 0
-	o3 = 0
-	o4 = 0
-	o5 = 0
+	o1 := uint32(0)
+	o2 := uint32(0)
+	o3 := uint32(0)
+	o4 := uint32(0)
+	o5 := uint32(0)
 
 	//print("%P => case %d\n", p, o->type);
 	switch o.type_ {
@@ -1535,7 +1496,7 @@
 
 	case 1: /* mov r1,r2 ==> OR Rs,Rs,Ra */
 		if p.To.Reg == REGZERO && p.From.Type == obj.TYPE_CONST {
-			v = regoff(ctxt, &p.From)
+			v := regoff(ctxt, &p.From)
 			if r0iszero != 0 /*TypeKind(100016)*/ && v != 0 {
 				//nerrors--;
 				ctxt.Diag("literal operation on R0\n%v", p)
@@ -1548,7 +1509,7 @@
 		o1 = LOP_RRR(OP_OR, uint32(p.To.Reg), uint32(p.From.Reg), uint32(p.From.Reg))
 
 	case 2: /* int/cr/fp op Rb,[Ra],Rd */
-		r = int(p.Reg)
+		r := int(p.Reg)
 
 		if r == 0 {
 			r = int(p.To.Reg)
@@ -1556,17 +1517,17 @@
 		o1 = AOP_RRR(uint32(oprrr(ctxt, int(p.As))), uint32(p.To.Reg), uint32(r), uint32(p.From.Reg))
 
 	case 3: /* mov $soreg/addcon/ucon, r ==> addis/addi $i,reg',r */
-		d = vregoff(ctxt, &p.From)
+		d := vregoff(ctxt, &p.From)
 
-		v = int32(d)
-		r = int(p.From.Reg)
+		v := int32(d)
+		r := int(p.From.Reg)
 		if r == 0 {
 			r = int(o.param)
 		}
 		if r0iszero != 0 /*TypeKind(100016)*/ && p.To.Reg == 0 && (r != 0 || v != 0) {
 			ctxt.Diag("literal operation on R0\n%v", p)
 		}
-		a = OP_ADDI
+		a := OP_ADDI
 		if o.a1 == C_UCON {
 			if d&0xffff != 0 {
 				log.Fatalf("invalid handling of %v", p)
@@ -1587,9 +1548,9 @@
 		o1 = AOP_IRR(uint32(a), uint32(p.To.Reg), uint32(r), uint32(v))
 
 	case 4: /* add/mul $scon,[r1],r2 */
-		v = regoff(ctxt, &p.From)
+		v := regoff(ctxt, &p.From)
 
-		r = int(p.Reg)
+		r := int(p.Reg)
 		if r == 0 {
 			r = int(p.To.Reg)
 		}
@@ -1605,7 +1566,7 @@
 		o1 = uint32(oprrr(ctxt, int(p.As)))
 
 	case 6: /* logical op Rb,[Rs,]Ra; no literal */
-		r = int(p.Reg)
+		r := int(p.Reg)
 
 		if r == 0 {
 			r = int(p.To.Reg)
@@ -1613,17 +1574,17 @@
 		o1 = LOP_RRR(uint32(oprrr(ctxt, int(p.As))), uint32(p.To.Reg), uint32(r), uint32(p.From.Reg))
 
 	case 7: /* mov r, soreg ==> stw o(r) */
-		r = int(p.To.Reg)
+		r := int(p.To.Reg)
 
 		if r == 0 {
 			r = int(o.param)
 		}
-		v = regoff(ctxt, &p.To)
-		if p.To.Type == obj.TYPE_MEM && p.Reg != 0 {
+		v := regoff(ctxt, &p.To)
+		if p.To.Type == obj.TYPE_MEM && p.To.Index != 0 {
 			if v != 0 {
 				ctxt.Diag("illegal indexed instruction\n%v", p)
 			}
-			o1 = AOP_RRR(uint32(opstorex(ctxt, int(p.As))), uint32(p.From.Reg), uint32(p.Reg), uint32(r))
+			o1 = AOP_RRR(uint32(opstorex(ctxt, int(p.As))), uint32(p.From.Reg), uint32(p.To.Index), uint32(r))
 		} else {
 			if int32(int16(v)) != v {
 				log.Fatalf("mishandled instruction %v", p)
@@ -1632,17 +1593,17 @@
 		}
 
 	case 8: /* mov soreg, r ==> lbz/lhz/lwz o(r) */
-		r = int(p.From.Reg)
+		r := int(p.From.Reg)
 
 		if r == 0 {
 			r = int(o.param)
 		}
-		v = regoff(ctxt, &p.From)
-		if p.From.Type == obj.TYPE_MEM && p.Reg != 0 {
+		v := regoff(ctxt, &p.From)
+		if p.From.Type == obj.TYPE_MEM && p.From.Index != 0 {
 			if v != 0 {
 				ctxt.Diag("illegal indexed instruction\n%v", p)
 			}
-			o1 = AOP_RRR(uint32(oploadx(ctxt, int(p.As))), uint32(p.To.Reg), uint32(p.Reg), uint32(r))
+			o1 = AOP_RRR(uint32(oploadx(ctxt, int(p.As))), uint32(p.To.Reg), uint32(p.From.Index), uint32(r))
 		} else {
 			if int32(int16(v)) != v {
 				log.Fatalf("mishandled instruction %v", p)
@@ -1651,24 +1612,24 @@
 		}
 
 	case 9: /* movb soreg, r ==> lbz o(r),r2; extsb r2,r2 */
-		r = int(p.From.Reg)
+		r := int(p.From.Reg)
 
 		if r == 0 {
 			r = int(o.param)
 		}
-		v = regoff(ctxt, &p.From)
-		if p.From.Type == obj.TYPE_MEM && p.Reg != 0 {
+		v := regoff(ctxt, &p.From)
+		if p.From.Type == obj.TYPE_MEM && p.From.Index != 0 {
 			if v != 0 {
 				ctxt.Diag("illegal indexed instruction\n%v", p)
 			}
-			o1 = AOP_RRR(uint32(oploadx(ctxt, int(p.As))), uint32(p.To.Reg), uint32(p.Reg), uint32(r))
+			o1 = AOP_RRR(uint32(oploadx(ctxt, int(p.As))), uint32(p.To.Reg), uint32(p.From.Index), uint32(r))
 		} else {
 			o1 = AOP_IRR(uint32(opload(ctxt, int(p.As))), uint32(p.To.Reg), uint32(r), uint32(v))
 		}
 		o2 = LOP_RRR(OP_EXTSB, uint32(p.To.Reg), uint32(p.To.Reg), 0)
 
 	case 10: /* sub Ra,[Rb],Rd => subf Rd,Ra,Rb */
-		r = int(p.Reg)
+		r := int(p.Reg)
 
 		if r == 0 {
 			r = int(p.To.Reg)
@@ -1676,7 +1637,7 @@
 		o1 = AOP_RRR(uint32(oprrr(ctxt, int(p.As))), uint32(p.To.Reg), uint32(p.From.Reg), uint32(r))
 
 	case 11: /* br/bl lbra */
-		v = 0
+		v := int32(0)
 
 		if p.Pcond != nil {
 			v = int32(p.Pcond.Pc - p.Pc)
@@ -1692,7 +1653,7 @@
 
 		o1 = OP_BR(uint32(opirr(ctxt, int(p.As))), uint32(v), 0)
 		if p.To.Sym != nil {
-			rel = obj.Addrel(ctxt.Cursym)
+			rel := obj.Addrel(ctxt.Cursym)
 			rel.Off = int32(ctxt.Pc)
 			rel.Siz = 4
 			rel.Sym = p.To.Sym
@@ -1708,7 +1669,7 @@
 
 	case 12: /* movb r,r (extsb); movw r,r (extsw) */
 		if p.To.Reg == REGZERO && p.From.Type == obj.TYPE_CONST {
-			v = regoff(ctxt, &p.From)
+			v := regoff(ctxt, &p.From)
 			if r0iszero != 0 /*TypeKind(100016)*/ && v != 0 {
 				ctxt.Diag("literal operation on R0\n%v", p)
 			}
@@ -1737,23 +1698,23 @@
 		}
 
 	case 14: /* rldc[lr] Rb,Rs,$mask,Ra -- left, right give different masks */
-		r = int(p.Reg)
+		r := int(p.Reg)
 
 		if r == 0 {
 			r = int(p.To.Reg)
 		}
-		d = vregoff(ctxt, &p.From3)
+		d := vregoff(ctxt, &p.From3)
+		var mask [2]uint8
 		maskgen64(ctxt, p, mask[:], uint64(d))
+		var a int
 		switch p.As {
-		case ARLDCL,
-			ARLDCLCC:
+		case ARLDCL, ARLDCLCC:
 			a = int(mask[0]) /* MB */
 			if mask[1] != 63 {
 				ctxt.Diag("invalid mask for rotate: %x (end != bit 63)\n%v", uint64(d), p)
 			}
 
-		case ARLDCR,
-			ARLDCRCC:
+		case ARLDCR, ARLDCRCC:
 			a = int(mask[1]) /* ME */
 			if mask[0] != 0 {
 				ctxt.Diag("invalid mask for rotate: %x (start != 0)\n%v", uint64(d), p)
@@ -1772,16 +1733,16 @@
 
 	case 17, /* bc bo,bi,lbra (same for now) */
 		16: /* bc bo,bi,sbra */
-		a = 0
+		a := 0
 
 		if p.From.Type == obj.TYPE_CONST {
 			a = int(regoff(ctxt, &p.From))
 		}
-		r = int(p.Reg)
+		r := int(p.Reg)
 		if r == 0 {
 			r = 0
 		}
-		v = 0
+		v := int32(0)
 		if p.Pcond != nil {
 			v = int32(p.Pcond.Pc - p.Pc)
 		}
@@ -1796,29 +1757,27 @@
 		o1 = OP_BC(uint32(opirr(ctxt, int(p.As))), uint32(a), uint32(r), uint32(v), 0)
 
 	case 15: /* br/bl (r) => mov r,lr; br/bl (lr) */
+		var v int32
 		if p.As == ABC || p.As == ABCL {
 			v = regoff(ctxt, &p.To) & 31
 		} else {
 			v = 20 /* unconditional */
 		}
-		r = int(p.Reg)
-		if r == 0 {
-			r = 0
-		}
 		o1 = AOP_RRR(OP_MTSPR, uint32(p.To.Reg), 0, 0) | (REG_LR&0x1f)<<16 | ((REG_LR>>5)&0x1f)<<11
 		o2 = OPVCC(19, 16, 0, 0)
 		if p.As == ABL || p.As == ABCL {
 			o2 |= 1
 		}
-		o2 = OP_BCR(o2, uint32(v), uint32(r))
+		o2 = OP_BCR(o2, uint32(v), uint32(p.To.Index))
 
 	case 18: /* br/bl (lr/ctr); bc/bcl bo,bi,(lr/ctr) */
+		var v int32
 		if p.As == ABC || p.As == ABCL {
 			v = regoff(ctxt, &p.From) & 31
 		} else {
 			v = 20 /* unconditional */
 		}
-		r = int(p.Reg)
+		r := int(p.Reg)
 		if r == 0 {
 			r = 0
 		}
@@ -1840,7 +1799,7 @@
 		o1 = OP_BCR(o1, uint32(v), uint32(r))
 
 	case 19: /* mov $lcon,r ==> cau+or */
-		d = vregoff(ctxt, &p.From)
+		d := vregoff(ctxt, &p.From)
 
 		if p.From.Sym == nil {
 			o1 = loadu32(int(p.To.Reg), d)
@@ -1854,9 +1813,9 @@
 	//if(dlm) reloc(&p->from, p->pc, 0);
 
 	case 20: /* add $ucon,,r */
-		v = regoff(ctxt, &p.From)
+		v := regoff(ctxt, &p.From)
 
-		r = int(p.Reg)
+		r := int(p.Reg)
 		if r == 0 {
 			r = int(p.To.Reg)
 		}
@@ -1869,10 +1828,10 @@
 		if p.To.Reg == REGTMP || p.Reg == REGTMP {
 			ctxt.Diag("cant synthesize large constant\n%v", p)
 		}
-		d = vregoff(ctxt, &p.From)
+		d := vregoff(ctxt, &p.From)
 		o1 = loadu32(REGTMP, d)
 		o2 = LOP_IRR(OP_ORI, REGTMP, REGTMP, uint32(int32(d)))
-		r = int(p.Reg)
+		r := int(p.Reg)
 		if r == 0 {
 			r = int(p.To.Reg)
 		}
@@ -1887,10 +1846,10 @@
 		if p.To.Reg == REGTMP || p.Reg == REGTMP {
 			ctxt.Diag("cant synthesize large constant\n%v", p)
 		}
-		d = vregoff(ctxt, &p.From)
+		d := vregoff(ctxt, &p.From)
 		o1 = loadu32(REGTMP, d)
 		o2 = LOP_IRR(OP_ORI, REGTMP, REGTMP, uint32(int32(d)))
-		r = int(p.Reg)
+		r := int(p.Reg)
 		if r == 0 {
 			r = int(p.To.Reg)
 		}
@@ -1904,25 +1863,24 @@
 		/*24*/
 	case 25:
 		/* sld[.] $sh,rS,rA -> rldicr[.] $sh,rS,mask(0,63-sh),rA; srd[.] -> rldicl */
-		v = regoff(ctxt, &p.From)
+		v := regoff(ctxt, &p.From)
 
 		if v < 0 {
 			v = 0
 		} else if v > 63 {
 			v = 63
 		}
-		r = int(p.Reg)
+		r := int(p.Reg)
 		if r == 0 {
 			r = int(p.To.Reg)
 		}
+		var a int
 		switch p.As {
-		case ASLD,
-			ASLDCC:
+		case ASLD, ASLDCC:
 			a = int(63 - v)
 			o1 = OP_RLDICR
 
-		case ASRD,
-			ASRDCC:
+		case ASRD, ASRDCC:
 			a = int(v)
 			v = 64 - v
 			o1 = OP_RLDICL
@@ -1949,8 +1907,8 @@
 		if p.To.Reg == REGTMP {
 			ctxt.Diag("can't synthesize large constant\n%v", p)
 		}
-		v = regoff(ctxt, &p.From)
-		r = int(p.From.Reg)
+		v := regoff(ctxt, &p.From)
+		r := int(p.From.Reg)
 		if r == 0 {
 			r = int(o.param)
 		}
@@ -1958,16 +1916,16 @@
 		o2 = AOP_IRR(OP_ADDI, uint32(p.To.Reg), REGTMP, uint32(v))
 
 	case 27: /* subc ra,$simm,rd => subfic rd,ra,$simm */
-		v = regoff(ctxt, &p.From3)
+		v := regoff(ctxt, &p.From3)
 
-		r = int(p.From.Reg)
+		r := int(p.From.Reg)
 		o1 = AOP_IRR(uint32(opirr(ctxt, int(p.As))), uint32(p.To.Reg), uint32(r), uint32(v))
 
 	case 28: /* subc r1,$lcon,r2 ==> cau+or+subfc */
 		if p.To.Reg == REGTMP || p.From.Reg == REGTMP {
 			ctxt.Diag("can't synthesize large constant\n%v", p)
 		}
-		v = regoff(ctxt, &p.From3)
+		v := regoff(ctxt, &p.From3)
 		o1 = AOP_IRR(OP_ADDIS, REGTMP, REGZERO, uint32(v)>>16)
 		o2 = LOP_IRR(OP_ORI, REGTMP, REGTMP, uint32(v))
 		o3 = AOP_RRR(uint32(oprrr(ctxt, int(p.As))), uint32(p.To.Reg), uint32(p.From.Reg), REGTMP)
@@ -1978,27 +1936,26 @@
 	//if(dlm) reloc(&p->from3, p->pc, 0);
 
 	case 29: /* rldic[lr]? $sh,s,$mask,a -- left, right, plain give different masks */
-		v = regoff(ctxt, &p.From)
+		v := regoff(ctxt, &p.From)
 
-		d = vregoff(ctxt, &p.From3)
+		d := vregoff(ctxt, &p.From3)
+		var mask [2]uint8
 		maskgen64(ctxt, p, mask[:], uint64(d))
+		var a int
 		switch p.As {
-		case ARLDC,
-			ARLDCCC:
+		case ARLDC, ARLDCCC:
 			a = int(mask[0]) /* MB */
 			if int32(mask[1]) != (63 - v) {
 				ctxt.Diag("invalid mask for shift: %x (shift %d)\n%v", uint64(d), v, p)
 			}
 
-		case ARLDCL,
-			ARLDCLCC:
+		case ARLDCL, ARLDCLCC:
 			a = int(mask[0]) /* MB */
 			if mask[1] != 63 {
 				ctxt.Diag("invalid mask for shift: %x (shift %d)\n%v", uint64(d), v, p)
 			}
 
-		case ARLDCR,
-			ARLDCRCC:
+		case ARLDCR, ARLDCRCC:
 			a = int(mask[1]) /* ME */
 			if mask[0] != 0 {
 				ctxt.Diag("invalid mask for shift: %x (shift %d)\n%v", uint64(d), v, p)
@@ -2019,9 +1976,10 @@
 		}
 
 	case 30: /* rldimi $sh,s,$mask,a */
-		v = regoff(ctxt, &p.From)
+		v := regoff(ctxt, &p.From)
 
-		d = vregoff(ctxt, &p.From3)
+		d := vregoff(ctxt, &p.From3)
+		var mask [2]uint8
 		maskgen64(ctxt, p, mask[:], uint64(d))
 		if int32(mask[1]) != (63 - v) {
 			ctxt.Diag("invalid mask for shift: %x (shift %d)\n%v", uint64(d), v, p)
@@ -2036,9 +1994,9 @@
 		}
 
 	case 31: /* dword */
-		d = vregoff(ctxt, &p.From)
+		d := vregoff(ctxt, &p.From)
 
-		if ctxt.Arch.Endian == obj.BigEndian {
+		if ctxt.Arch.ByteOrder == binary.BigEndian {
 			o1 = uint32(d >> 32)
 			o2 = uint32(d)
 		} else {
@@ -2047,7 +2005,7 @@
 		}
 
 		if p.From.Sym != nil {
-			rel = obj.Addrel(ctxt.Cursym)
+			rel := obj.Addrel(ctxt.Cursym)
 			rel.Off = int32(ctxt.Pc)
 			rel.Siz = 8
 			rel.Sym = p.From.Sym
@@ -2058,7 +2016,7 @@
 		}
 
 	case 32: /* fmul frc,fra,frd */
-		r = int(p.Reg)
+		r := int(p.Reg)
 
 		if r == 0 {
 			r = int(p.To.Reg)
@@ -2066,7 +2024,7 @@
 		o1 = AOP_RRR(uint32(oprrr(ctxt, int(p.As))), uint32(p.To.Reg), uint32(r), 0) | (uint32(p.From.Reg)&31)<<6
 
 	case 33: /* fabs [frb,]frd; fmr. frb,frd */
-		r = int(p.From.Reg)
+		r := int(p.From.Reg)
 
 		if oclass(&p.From) == C_NONE {
 			r = int(p.To.Reg)
@@ -2077,9 +2035,9 @@
 		o1 = AOP_RRR(uint32(oprrr(ctxt, int(p.As))), uint32(p.To.Reg), uint32(p.From.Reg), uint32(p.Reg)) | (uint32(p.From3.Reg)&31)<<6
 
 	case 35: /* mov r,lext/lauto/loreg ==> cau $(v>>16),sb,r'; store o(r') */
-		v = regoff(ctxt, &p.To)
+		v := regoff(ctxt, &p.To)
 
-		r = int(p.To.Reg)
+		r := int(p.To.Reg)
 		if r == 0 {
 			r = int(o.param)
 		}
@@ -2087,9 +2045,9 @@
 		o2 = AOP_IRR(uint32(opstore(ctxt, int(p.As))), uint32(p.From.Reg), REGTMP, uint32(v))
 
 	case 36: /* mov bz/h/hz lext/lauto/lreg,r ==> lbz/lha/lhz etc */
-		v = regoff(ctxt, &p.From)
+		v := regoff(ctxt, &p.From)
 
-		r = int(p.From.Reg)
+		r := int(p.From.Reg)
 		if r == 0 {
 			r = int(o.param)
 		}
@@ -2097,9 +2055,9 @@
 		o2 = AOP_IRR(uint32(opload(ctxt, int(p.As))), uint32(p.To.Reg), REGTMP, uint32(v))
 
 	case 37: /* movb lext/lauto/lreg,r ==> lbz o(reg),r; extsb r */
-		v = regoff(ctxt, &p.From)
+		v := regoff(ctxt, &p.From)
 
-		r = int(p.From.Reg)
+		r := int(p.From.Reg)
 		if r == 0 {
 			r = int(o.param)
 		}
@@ -2117,34 +2075,19 @@
 		o1 = AOP_RRR(uint32(opirr(ctxt, int(p.As))), uint32(p.To.Reg), uint32(p.From.Reg), 0) | (uint32(regoff(ctxt, &p.From3))&0x7F)<<11
 
 	case 43: /* unary indexed source: dcbf (b); dcbf (a+b) */
-		r = int(p.Reg)
-
-		if r == 0 {
-			r = 0
-		}
-		o1 = AOP_RRR(uint32(oprrr(ctxt, int(p.As))), 0, uint32(r), uint32(p.From.Reg))
+		o1 = AOP_RRR(uint32(oprrr(ctxt, int(p.As))), 0, uint32(p.From.Index), uint32(p.From.Reg))
 
 	case 44: /* indexed store */
-		r = int(p.Reg)
-
-		if r == 0 {
-			r = 0
-		}
-		o1 = AOP_RRR(uint32(opstorex(ctxt, int(p.As))), uint32(p.From.Reg), uint32(r), uint32(p.To.Reg))
+		o1 = AOP_RRR(uint32(opstorex(ctxt, int(p.As))), uint32(p.From.Reg), uint32(p.To.Index), uint32(p.To.Reg))
 
 	case 45: /* indexed load */
-		r = int(p.Reg)
-
-		if r == 0 {
-			r = 0
-		}
-		o1 = AOP_RRR(uint32(oploadx(ctxt, int(p.As))), uint32(p.To.Reg), uint32(r), uint32(p.From.Reg))
+		o1 = AOP_RRR(uint32(oploadx(ctxt, int(p.As))), uint32(p.To.Reg), uint32(p.From.Index), uint32(p.From.Reg))
 
 	case 46: /* plain op */
 		o1 = uint32(oprrr(ctxt, int(p.As)))
 
 	case 47: /* op Ra, Rd; also op [Ra,] Rd */
-		r = int(p.From.Reg)
+		r := int(p.From.Reg)
 
 		if r == 0 {
 			r = int(p.To.Reg)
@@ -2152,7 +2095,7 @@
 		o1 = AOP_RRR(uint32(oprrr(ctxt, int(p.As))), uint32(p.To.Reg), uint32(r), 0)
 
 	case 48: /* op Rs, Ra */
-		r = int(p.From.Reg)
+		r := int(p.From.Reg)
 
 		if r == 0 {
 			r = int(p.To.Reg)
@@ -2161,20 +2104,20 @@
 
 	case 49: /* op Rb; op $n, Rb */
 		if p.From.Type != obj.TYPE_REG { /* tlbie $L, rB */
-			v = regoff(ctxt, &p.From) & 1
+			v := regoff(ctxt, &p.From) & 1
 			o1 = AOP_RRR(uint32(oprrr(ctxt, int(p.As))), 0, 0, uint32(p.To.Reg)) | uint32(v)<<21
 		} else {
 			o1 = AOP_RRR(uint32(oprrr(ctxt, int(p.As))), 0, 0, uint32(p.From.Reg))
 		}
 
 	case 50: /* rem[u] r1[,r2],r3 */
-		r = int(p.Reg)
+		r := int(p.Reg)
 
 		if r == 0 {
 			r = int(p.To.Reg)
 		}
-		v = oprrr(ctxt, int(p.As))
-		t = v & (1<<10 | 1) /* OE|Rc */
+		v := oprrr(ctxt, int(p.As))
+		t := v & (1<<10 | 1) /* OE|Rc */
 		o1 = AOP_RRR(uint32(v)&^uint32(t), REGTMP, uint32(r), uint32(p.From.Reg))
 		o2 = AOP_RRR(OP_MULLW, REGTMP, REGTMP, uint32(p.From.Reg))
 		o3 = AOP_RRR(OP_SUBF|uint32(t), uint32(p.To.Reg), REGTMP, uint32(r))
@@ -2186,19 +2129,19 @@
 		}
 
 	case 51: /* remd[u] r1[,r2],r3 */
-		r = int(p.Reg)
+		r := int(p.Reg)
 
 		if r == 0 {
 			r = int(p.To.Reg)
 		}
-		v = oprrr(ctxt, int(p.As))
-		t = v & (1<<10 | 1) /* OE|Rc */
+		v := oprrr(ctxt, int(p.As))
+		t := v & (1<<10 | 1) /* OE|Rc */
 		o1 = AOP_RRR(uint32(v)&^uint32(t), REGTMP, uint32(r), uint32(p.From.Reg))
 		o2 = AOP_RRR(OP_MULLD, REGTMP, REGTMP, uint32(p.From.Reg))
 		o3 = AOP_RRR(OP_SUBF|uint32(t), uint32(p.To.Reg), REGTMP, uint32(r))
 
 	case 52: /* mtfsbNx cr(n) */
-		v = regoff(ctxt, &p.From) & 31
+		v := regoff(ctxt, &p.From) & 31
 
 		o1 = AOP_RRR(uint32(oprrr(ctxt, int(p.As))), uint32(v), 0, 0)
 
@@ -2220,9 +2163,9 @@
 		o1 = AOP_RRR(uint32(oprrr(ctxt, int(p.As))), uint32(p.To.Reg), 0, uint32(p.From.Reg))
 
 	case 56: /* sra $sh,[s,]a; srd $sh,[s,]a */
-		v = regoff(ctxt, &p.From)
+		v := regoff(ctxt, &p.From)
 
-		r = int(p.Reg)
+		r := int(p.Reg)
 		if r == 0 {
 			r = int(p.To.Reg)
 		}
@@ -2232,9 +2175,9 @@
 		}
 
 	case 57: /* slw $sh,[s,]a -> rlwinm ... */
-		v = regoff(ctxt, &p.From)
+		v := regoff(ctxt, &p.From)
 
-		r = int(p.Reg)
+		r := int(p.Reg)
 		if r == 0 {
 			r = int(p.To.Reg)
 		}
@@ -2251,6 +2194,7 @@
 		} else if v > 32 {
 			v = 32
 		}
+		var mask [2]uint8
 		if p.As == ASRW || p.As == ASRWCC { /* shift right */
 			mask[0] = uint8(v)
 			mask[1] = 31
@@ -2266,48 +2210,51 @@
 		}
 
 	case 58: /* logical $andcon,[s],a */
-		v = regoff(ctxt, &p.From)
+		v := regoff(ctxt, &p.From)
 
-		r = int(p.Reg)
+		r := int(p.Reg)
 		if r == 0 {
 			r = int(p.To.Reg)
 		}
 		o1 = LOP_IRR(uint32(opirr(ctxt, int(p.As))), uint32(p.To.Reg), uint32(r), uint32(v))
 
 	case 59: /* or/and $ucon,,r */
-		v = regoff(ctxt, &p.From)
+		v := regoff(ctxt, &p.From)
 
-		r = int(p.Reg)
+		r := int(p.Reg)
 		if r == 0 {
 			r = int(p.To.Reg)
 		}
 		o1 = LOP_IRR(uint32(opirr(ctxt, int(p.As)+ALAST)), uint32(p.To.Reg), uint32(r), uint32(v)>>16) /* oris, xoris, andis */
 
 	case 60: /* tw to,a,b */
-		r = int(regoff(ctxt, &p.From) & 31)
+		r := int(regoff(ctxt, &p.From) & 31)
 
 		o1 = AOP_RRR(uint32(oprrr(ctxt, int(p.As))), uint32(r), uint32(p.Reg), uint32(p.To.Reg))
 
 	case 61: /* tw to,a,$simm */
-		r = int(regoff(ctxt, &p.From) & 31)
+		r := int(regoff(ctxt, &p.From) & 31)
 
-		v = regoff(ctxt, &p.To)
+		v := regoff(ctxt, &p.To)
 		o1 = AOP_IRR(uint32(opirr(ctxt, int(p.As))), uint32(r), uint32(p.Reg), uint32(v))
 
 	case 62: /* rlwmi $sh,s,$mask,a */
-		v = regoff(ctxt, &p.From)
+		v := regoff(ctxt, &p.From)
 
+		var mask [2]uint8
 		maskgen(ctxt, p, mask[:], uint32(regoff(ctxt, &p.From3)))
 		o1 = AOP_RRR(uint32(opirr(ctxt, int(p.As))), uint32(p.Reg), uint32(p.To.Reg), uint32(v))
 		o1 |= (uint32(mask[0])&31)<<6 | (uint32(mask[1])&31)<<1
 
 	case 63: /* rlwmi b,s,$mask,a */
+		var mask [2]uint8
 		maskgen(ctxt, p, mask[:], uint32(regoff(ctxt, &p.From3)))
 
 		o1 = AOP_RRR(uint32(opirr(ctxt, int(p.As))), uint32(p.Reg), uint32(p.To.Reg), uint32(p.From.Reg))
 		o1 |= (uint32(mask[0])&31)<<6 | (uint32(mask[1])&31)<<1
 
 	case 64: /* mtfsf fr[, $m] {,fpcsr} */
+		var v int32
 		if p.From3.Type != obj.TYPE_NONE {
 			v = regoff(ctxt, &p.From3) & 255
 		} else {
@@ -2322,6 +2269,8 @@
 		o1 = OP_MTFSFI | (uint32(p.To.Reg)&15)<<23 | (uint32(regoff(ctxt, &p.From))&31)<<12
 
 	case 66: /* mov spr,r1; mov r1,spr, also dcr */
+		var r int
+		var v int32
 		if REG_R0 <= p.From.Reg && p.From.Reg <= REG_R31 {
 			r = int(p.From.Reg)
 			v = int32(p.To.Reg)
@@ -2350,13 +2299,14 @@
 
 	case 68: /* mfcr rD; mfocrf CRM,rD */
 		if p.From.Type == obj.TYPE_REG && REG_CR0 <= p.From.Reg && p.From.Reg <= REG_CR7 {
-			v = 1 << uint(7-(p.To.Reg&7))                                         /* CR(n) */
+			v := int32(1 << uint(7-(p.To.Reg&7)))                                 /* CR(n) */
 			o1 = AOP_RRR(OP_MFCR, uint32(p.To.Reg), 0, 0) | 1<<20 | uint32(v)<<12 /* new form, mfocrf */
 		} else {
 			o1 = AOP_RRR(OP_MFCR, uint32(p.To.Reg), 0, 0) /* old form, whole register */
 		}
 
 	case 69: /* mtcrf CRM,rS */
+		var v int32
 		if p.From3.Type != obj.TYPE_NONE {
 			if p.To.Reg != 0 {
 				ctxt.Diag("can't use both mask and CR(n)\n%v", p)
@@ -2373,6 +2323,7 @@
 		o1 = AOP_RRR(OP_MTCRF, uint32(p.From.Reg), 0, 0) | uint32(v)<<12
 
 	case 70: /* [f]cmp r,r,cr*/
+		var r int
 		if p.Reg == 0 {
 			r = 0
 		} else {
@@ -2381,6 +2332,7 @@
 		o1 = AOP_RRR(uint32(oprrr(ctxt, int(p.As))), uint32(r), uint32(p.From.Reg), uint32(p.To.Reg))
 
 	case 71: /* cmp[l] r,i,cr*/
+		var r int
 		if p.Reg == 0 {
 			r = 0
 		} else {
@@ -2419,7 +2371,7 @@
 
 		/* relocation operations */
 	case 74:
-		v = regoff(ctxt, &p.To)
+		v := regoff(ctxt, &p.To)
 
 		o1 = AOP_IRR(OP_ADDIS, REGTMP, REGZERO, uint32(high16adjusted(v)))
 		o2 = AOP_IRR(uint32(opstore(ctxt, int(p.As))), uint32(p.From.Reg), REGTMP, uint32(v))
@@ -2428,7 +2380,7 @@
 	//if(dlm) reloc(&p->to, p->pc, 1);
 
 	case 75:
-		v = regoff(ctxt, &p.From)
+		v := regoff(ctxt, &p.From)
 		o1 = AOP_IRR(OP_ADDIS, REGTMP, REGZERO, uint32(high16adjusted(v)))
 		o2 = AOP_IRR(uint32(opload(ctxt, int(p.As))), uint32(p.To.Reg), REGTMP, uint32(v))
 		addaddrreloc(ctxt, p.From.Sym, &o1, &o2)
@@ -2436,7 +2388,7 @@
 	//if(dlm) reloc(&p->from, p->pc, 1);
 
 	case 76:
-		v = regoff(ctxt, &p.From)
+		v := regoff(ctxt, &p.From)
 		o1 = AOP_IRR(OP_ADDIS, REGTMP, REGZERO, uint32(high16adjusted(v)))
 		o2 = AOP_IRR(uint32(opload(ctxt, int(p.As))), uint32(p.To.Reg), REGTMP, uint32(v))
 		addaddrreloc(ctxt, p.From.Sym, &o1, &o2)
@@ -2564,68 +2516,52 @@
 	case ADCBZ:
 		return int32(OPVCC(31, 1014, 0, 0))
 
-	case AREM,
-		ADIVW:
+	case AREM, ADIVW:
 		return int32(OPVCC(31, 491, 0, 0))
 
-	case AREMCC,
-		ADIVWCC:
+	case AREMCC, ADIVWCC:
 		return int32(OPVCC(31, 491, 0, 1))
 
-	case AREMV,
-		ADIVWV:
+	case AREMV, ADIVWV:
 		return int32(OPVCC(31, 491, 1, 0))
 
-	case AREMVCC,
-		ADIVWVCC:
+	case AREMVCC, ADIVWVCC:
 		return int32(OPVCC(31, 491, 1, 1))
 
-	case AREMU,
-		ADIVWU:
+	case AREMU, ADIVWU:
 		return int32(OPVCC(31, 459, 0, 0))
 
-	case AREMUCC,
-		ADIVWUCC:
+	case AREMUCC, ADIVWUCC:
 		return int32(OPVCC(31, 459, 0, 1))
 
-	case AREMUV,
-		ADIVWUV:
+	case AREMUV, ADIVWUV:
 		return int32(OPVCC(31, 459, 1, 0))
 
-	case AREMUVCC,
-		ADIVWUVCC:
+	case AREMUVCC, ADIVWUVCC:
 		return int32(OPVCC(31, 459, 1, 1))
 
-	case AREMD,
-		ADIVD:
+	case AREMD, ADIVD:
 		return int32(OPVCC(31, 489, 0, 0))
 
-	case AREMDCC,
-		ADIVDCC:
+	case AREMDCC, ADIVDCC:
 		return int32(OPVCC(31, 489, 0, 1))
 
-	case AREMDV,
-		ADIVDV:
+	case AREMDV, ADIVDV:
 		return int32(OPVCC(31, 489, 1, 0))
 
-	case AREMDVCC,
-		ADIVDVCC:
+	case AREMDVCC, ADIVDVCC:
 		return int32(OPVCC(31, 489, 1, 1))
 
-	case AREMDU,
-		ADIVDU:
+	case AREMDU, ADIVDU:
 		return int32(OPVCC(31, 457, 0, 0))
 
-	case AREMDUCC,
-		ADIVDUCC:
+	case AREMDUCC, ADIVDUCC:
 		return int32(OPVCC(31, 457, 0, 1))
 
-	case AREMDUV,
-		ADIVDUV:
+	case AREMDUV, ADIVDUV:
 		return int32(OPVCC(31, 457, 1, 0))
 
-	case AREMDUVCC,
-		ADIVDUVCC:
+	case AREMDUVCC, ADIVDUVCC:
 		return int32(OPVCC(31, 457, 1, 1))
 
 	case AEIEIO:
@@ -2702,8 +2638,7 @@
 	case AFMADDSCC:
 		return int32(OPVCC(59, 29, 0, 1))
 
-	case AFMOVS,
-		AFMOVD:
+	case AFMOVS, AFMOVD:
 		return int32(OPVCC(63, 72, 0, 0)) /* load */
 	case AFMOVDCC:
 		return int32(OPVCC(63, 72, 0, 1))
@@ -2980,7 +2915,7 @@
 		return int32(OPVCC(31, 316, 0, 1))
 	}
 
-	ctxt.Diag("bad r/r opcode %v", Aconv(a))
+	ctxt.Diag("bad r/r opcode %v", obj.Aconv(a))
 	return 0
 }
 
@@ -3102,7 +3037,7 @@
 		return int32(OPVCC(27, 0, 0, 0)) /* XORIU */
 	}
 
-	ctxt.Diag("bad opcode i/r %v", Aconv(a))
+	ctxt.Diag("bad opcode i/r %v", obj.Aconv(a))
 	return 0
 }
 
@@ -3123,13 +3058,11 @@
 		return int32(OPVCC(58, 0, 0, 0) | 1<<1) /* lwa */
 
 		/* no AMOVWU */
-	case AMOVB,
-		AMOVBZ:
+	case AMOVB, AMOVBZ:
 		return int32(OPVCC(34, 0, 0, 0))
 		/* load */
 
-	case AMOVBU,
-		AMOVBZU:
+	case AMOVBU, AMOVBZU:
 		return int32(OPVCC(35, 0, 0, 0))
 	case AFMOVD:
 		return int32(OPVCC(50, 0, 0, 0))
@@ -3151,7 +3084,7 @@
 		return int32(OPVCC(46, 0, 0, 0)) /* lmw */
 	}
 
-	ctxt.Diag("bad load opcode %v", Aconv(a))
+	ctxt.Diag("bad load opcode %v", obj.Aconv(a))
 	return 0
 }
 
@@ -3169,12 +3102,10 @@
 	case AMOVWU:
 		return int32(OPVCC(31, 373, 0, 0)) /* lwaux */
 
-	case AMOVB,
-		AMOVBZ:
+	case AMOVB, AMOVBZ:
 		return int32(OPVCC(31, 87, 0, 0)) /* lbzx */
 
-	case AMOVBU,
-		AMOVBZU:
+	case AMOVBU, AMOVBZU:
 		return int32(OPVCC(31, 119, 0, 0)) /* lbzux */
 	case AFMOVD:
 		return int32(OPVCC(31, 599, 0, 0)) /* lfdx */
@@ -3210,7 +3141,7 @@
 		return int32(OPVCC(31, 53, 0, 0)) /* ldux */
 	}
 
-	ctxt.Diag("bad loadx opcode %v", Aconv(a))
+	ctxt.Diag("bad loadx opcode %v", obj.Aconv(a))
 	return 0
 }
 
@@ -3219,12 +3150,10 @@
  */
 func opstore(ctxt *obj.Link, a int) int32 {
 	switch a {
-	case AMOVB,
-		AMOVBZ:
+	case AMOVB, AMOVBZ:
 		return int32(OPVCC(38, 0, 0, 0)) /* stb */
 
-	case AMOVBU,
-		AMOVBZU:
+	case AMOVBU, AMOVBZU:
 		return int32(OPVCC(39, 0, 0, 0)) /* stbu */
 	case AFMOVD:
 		return int32(OPVCC(54, 0, 0, 0)) /* stfd */
@@ -3235,24 +3164,20 @@
 	case AFMOVSU:
 		return int32(OPVCC(53, 0, 0, 0)) /* stfsu */
 
-	case AMOVHZ,
-		AMOVH:
+	case AMOVHZ, AMOVH:
 		return int32(OPVCC(44, 0, 0, 0)) /* sth */
 
-	case AMOVHZU,
-		AMOVHU:
+	case AMOVHZU, AMOVHU:
 		return int32(OPVCC(45, 0, 0, 0)) /* sthu */
 	case AMOVMW:
 		return int32(OPVCC(47, 0, 0, 0)) /* stmw */
 	case ASTSW:
 		return int32(OPVCC(31, 725, 0, 0)) /* stswi */
 
-	case AMOVWZ,
-		AMOVW:
+	case AMOVWZ, AMOVW:
 		return int32(OPVCC(36, 0, 0, 0)) /* stw */
 
-	case AMOVWZU,
-		AMOVWU:
+	case AMOVWZU, AMOVWU:
 		return int32(OPVCC(37, 0, 0, 0)) /* stwu */
 	case AMOVD:
 		return int32(OPVCC(62, 0, 0, 0)) /* std */
@@ -3260,7 +3185,7 @@
 		return int32(OPVCC(62, 0, 0, 1)) /* stdu */
 	}
 
-	ctxt.Diag("unknown store opcode %v", Aconv(a))
+	ctxt.Diag("unknown store opcode %v", obj.Aconv(a))
 	return 0
 }
 
@@ -3269,12 +3194,10 @@
  */
 func opstorex(ctxt *obj.Link, a int) int32 {
 	switch a {
-	case AMOVB,
-		AMOVBZ:
+	case AMOVB, AMOVBZ:
 		return int32(OPVCC(31, 215, 0, 0)) /* stbx */
 
-	case AMOVBU,
-		AMOVBZU:
+	case AMOVBU, AMOVBZU:
 		return int32(OPVCC(31, 247, 0, 0)) /* stbux */
 	case AFMOVD:
 		return int32(OPVCC(31, 727, 0, 0)) /* stfdx */
@@ -3285,22 +3208,18 @@
 	case AFMOVSU:
 		return int32(OPVCC(31, 695, 0, 0)) /* stfsux */
 
-	case AMOVHZ,
-		AMOVH:
+	case AMOVHZ, AMOVH:
 		return int32(OPVCC(31, 407, 0, 0)) /* sthx */
 	case AMOVHBR:
 		return int32(OPVCC(31, 918, 0, 0)) /* sthbrx */
 
-	case AMOVHZU,
-		AMOVHU:
+	case AMOVHZU, AMOVHU:
 		return int32(OPVCC(31, 439, 0, 0)) /* sthux */
 
-	case AMOVWZ,
-		AMOVW:
+	case AMOVWZ, AMOVW:
 		return int32(OPVCC(31, 151, 0, 0)) /* stwx */
 
-	case AMOVWZU,
-		AMOVWU:
+	case AMOVWZU, AMOVWU:
 		return int32(OPVCC(31, 183, 0, 0)) /* stwux */
 	case ASTSW:
 		return int32(OPVCC(31, 661, 0, 0)) /* stswx */
@@ -3318,6 +3237,6 @@
 		return int32(OPVCC(31, 181, 0, 0)) /* stdux */
 	}
 
-	ctxt.Diag("unknown storex opcode %v", Aconv(a))
+	ctxt.Diag("unknown storex opcode %v", obj.Aconv(a))
 	return 0
 }
diff --git a/src/cmd/internal/obj/ppc64/list9.go b/src/cmd/internal/obj/ppc64/list9.go
index 21a8642..4cdcfbc 100644
--- a/src/cmd/internal/obj/ppc64/list9.go
+++ b/src/cmd/internal/obj/ppc64/list9.go
@@ -34,108 +34,19 @@
 	"fmt"
 )
 
-const (
-	STRINGSZ = 1000
-)
-
-//
-// Format conversions
-//	%A int		Opcodes (instruction mnemonics)
-//
-//	%D Addr*	Addresses (instruction operands)
-//
-//	%P Prog*	Instructions
-//
-//	%R int		Registers
-//
-//	%$ char*	String constant addresses (for internal use only)
-//	%^ int   	C_* classes (for liblink internal use)
-
-var bigP *obj.Prog
-
-func Pconv(p *obj.Prog) string {
-	var str string
-	var fp string
-
-	var a int
-
-	a = int(p.As)
-
-	str = ""
-	if a == obj.ADATA {
-		str = fmt.Sprintf("%.5d (%v)\t%v\t%v/%d,%v",
-			p.Pc, p.Line(), Aconv(a), obj.Dconv(p, &p.From), p.From3.Offset, obj.Dconv(p, &p.To))
-	} else if a == obj.ATEXT || a == obj.AGLOBL {
-		if p.From3.Offset != 0 {
-			str = fmt.Sprintf("%.5d (%v)\t%v\t%v,%d,%v",
-				p.Pc, p.Line(), Aconv(a), obj.Dconv(p, &p.From), p.From3.Offset, obj.Dconv(p, &p.To))
-		} else {
-			str = fmt.Sprintf("%.5d (%v)\t%v\t%v,%v",
-				p.Pc, p.Line(), Aconv(a), obj.Dconv(p, &p.From), obj.Dconv(p, &p.To))
-		}
-	} else {
-		if p.Mark&NOSCHED != 0 {
-			str += fmt.Sprintf("*")
-		}
-		if p.Reg == 0 && p.From3.Type == obj.TYPE_NONE {
-			str += fmt.Sprintf("%.5d (%v)\t%v\t%v,%v",
-				p.Pc, p.Line(), Aconv(a), obj.Dconv(p, &p.From), obj.Dconv(p, &p.To))
-		} else if a != obj.ATEXT && p.From.Type == obj.TYPE_MEM {
-			off := ""
-			if p.From.Offset != 0 {
-				off = fmt.Sprintf("%d", p.From.Offset)
-			}
-			str += fmt.Sprintf("%.5d (%v)\t%v\t%s(%v+%v),%v",
-				p.Pc, p.Line(), Aconv(a), off, Rconv(int(p.From.Reg)), Rconv(int(p.Reg)), obj.Dconv(p, &p.To))
-		} else if p.To.Type == obj.TYPE_MEM {
-			off := ""
-			if p.From.Offset != 0 {
-				off = fmt.Sprintf("%d", p.From.Offset)
-			}
-			str += fmt.Sprintf("%.5d (%v)\t%v\t%v,%s(%v+%v)",
-				p.Pc, p.Line(), Aconv(a), obj.Dconv(p, &p.From), off, Rconv(int(p.To.Reg)), Rconv(int(p.Reg)))
-		} else {
-			str += fmt.Sprintf("%.5d (%v)\t%v\t%v",
-				p.Pc, p.Line(), Aconv(a), obj.Dconv(p, &p.From))
-			if p.Reg != 0 {
-				str += fmt.Sprintf(",%v", Rconv(int(p.Reg)))
-			}
-			if p.From3.Type != obj.TYPE_NONE {
-				str += fmt.Sprintf(",%v", obj.Dconv(p, &p.From3))
-			}
-			str += fmt.Sprintf(",%v", obj.Dconv(p, &p.To))
-		}
-
-		if p.Spadj != 0 {
-			fp += fmt.Sprintf("%s # spadj=%d", str, p.Spadj)
-			return fp
-		}
-	}
-
-	fp += str
-	return fp
-}
-
-func Aconv(a int) string {
-	var s string
-	var fp string
-
-	s = "???"
-	if a >= obj.AXXX && a < ALAST {
-		s = Anames[a]
-	}
-	fp += s
-	return fp
-}
-
 func init() {
 	obj.RegisterRegister(obj.RBasePPC64, REG_DCR0+1024, Rconv)
+	obj.RegisterOpcode(obj.ABasePPC64, Anames)
 }
 
 func Rconv(r int) string {
 	if r == 0 {
 		return "NONE"
 	}
+	if r == REGG {
+		// Special case.
+		return "g"
+	}
 	if REG_R0 <= r && r <= REG_R31 {
 		return fmt.Sprintf("R%d", r-REG_R0)
 	}
@@ -177,13 +88,11 @@
 }
 
 func DRconv(a int) string {
-	var s string
-	var fp string
-
-	s = "C_??"
+	s := "C_??"
 	if a >= C_NONE && a <= C_NCLASS {
 		s = cnames9[a]
 	}
+	var fp string
 	fp += s
 	return fp
 }
diff --git a/src/cmd/internal/obj/ppc64/obj9.go b/src/cmd/internal/obj/ppc64/obj9.go
index 0c3298a..e05061f 100644
--- a/src/cmd/internal/obj/ppc64/obj9.go
+++ b/src/cmd/internal/obj/ppc64/obj9.go
@@ -37,9 +37,6 @@
 )
 
 func progedit(ctxt *obj.Link, p *obj.Prog) {
-	var literal string
-	var s *obj.LSym
-
 	p.From.Class = 0
 	p.To.Class = 0
 
@@ -59,12 +56,10 @@
 	switch p.As {
 	case AFMOVS:
 		if p.From.Type == obj.TYPE_FCONST {
-			var i32 uint32
-			var f32 float32
-			f32 = float32(p.From.U.Dval)
-			i32 = math.Float32bits(f32)
-			literal = fmt.Sprintf("$f32.%08x", i32)
-			s = obj.Linklookup(ctxt, literal, 0)
+			f32 := float32(p.From.Val.(float64))
+			i32 := math.Float32bits(f32)
+			literal := fmt.Sprintf("$f32.%08x", i32)
+			s := obj.Linklookup(ctxt, literal, 0)
 			s.Size = 4
 			p.From.Type = obj.TYPE_MEM
 			p.From.Sym = s
@@ -74,10 +69,9 @@
 
 	case AFMOVD:
 		if p.From.Type == obj.TYPE_FCONST {
-			var i64 uint64
-			i64 = math.Float64bits(p.From.U.Dval)
-			literal = fmt.Sprintf("$f64.%016x", i64)
-			s = obj.Linklookup(ctxt, literal, 0)
+			i64 := math.Float64bits(p.From.Val.(float64))
+			literal := fmt.Sprintf("$f64.%016x", i64)
+			s := obj.Linklookup(ctxt, literal, 0)
 			s.Size = 8
 			p.From.Type = obj.TYPE_MEM
 			p.From.Sym = s
@@ -88,8 +82,8 @@
 		// Put >32-bit constants in memory and load them
 	case AMOVD:
 		if p.From.Type == obj.TYPE_CONST && p.From.Name == obj.NAME_NONE && p.From.Reg == 0 && int64(int32(p.From.Offset)) != p.From.Offset {
-			literal = fmt.Sprintf("$i64.%016x", uint64(p.From.Offset))
-			s = obj.Linklookup(ctxt, literal, 0)
+			literal := fmt.Sprintf("$i64.%016x", uint64(p.From.Offset))
+			s := obj.Linklookup(ctxt, literal, 0)
 			s.Size = 8
 			p.From.Type = obj.TYPE_MEM
 			p.From.Sym = s
@@ -121,17 +115,6 @@
 }
 
 func preprocess(ctxt *obj.Link, cursym *obj.LSym) {
-	var p *obj.Prog
-	var q *obj.Prog
-	var p1 *obj.Prog
-	var p2 *obj.Prog
-	var q1 *obj.Prog
-	var o int
-	var mov int
-	var aoffset int
-	var textstksiz int64
-	var autosize int32
-
 	if ctxt.Symmorestack[0] == nil {
 		ctxt.Symmorestack[0] = obj.Linklookup(ctxt, "runtime.morestack", 0)
 		ctxt.Symmorestack[1] = obj.Linklookup(ctxt, "runtime.morestack_noctxt", 0)
@@ -144,10 +127,10 @@
 		return
 	}
 
-	p = cursym.Text
-	textstksiz = p.To.Offset
+	p := cursym.Text
+	textstksiz := p.To.Offset
 
-	cursym.Args = p.To.U.Argsize
+	cursym.Args = p.To.Val.(int32)
 	cursym.Locals = int32(textstksiz)
 
 	/*
@@ -161,8 +144,9 @@
 	}
 	obj.Bflush(ctxt.Bso)
 
-	q = nil
-	for p = cursym.Text; p != nil; p = p.Link {
+	var q *obj.Prog
+	var q1 *obj.Prog
+	for p := cursym.Text; p != nil; p = p.Link {
 		switch p.As {
 		/* too hard, just leave alone */
 		case obj.ATEXT:
@@ -214,9 +198,7 @@
 			p.Mark |= LABEL | SYNC
 			continue
 
-		case AMOVW,
-			AMOVWZ,
-			AMOVD:
+		case AMOVW, AMOVWZ, AMOVD:
 			q = p
 			if p.From.Reg >= REG_SPECIAL || p.To.Reg >= REG_SPECIAL {
 				p.Mark |= LABEL | SYNC
@@ -301,8 +283,7 @@
 			}
 			continue
 
-		case AFCMPO,
-			AFCMPU:
+		case AFCMPO, AFCMPU:
 			q = p
 			p.Mark |= FCMP | FLOAT
 			continue
@@ -326,8 +307,13 @@
 		}
 	}
 
-	autosize = 0
-	for p = cursym.Text; p != nil; p = p.Link {
+	autosize := int32(0)
+	var aoffset int
+	var mov int
+	var o int
+	var p1 *obj.Prog
+	var p2 *obj.Prog
+	for p := cursym.Text; p != nil; p = p.Link {
 		o = int(p.As)
 		switch o {
 		case obj.ATEXT:
@@ -643,9 +629,6 @@
 	}
 */
 func stacksplit(ctxt *obj.Link, p *obj.Prog, framesize int32, noctxt bool) *obj.Prog {
-	var q *obj.Prog
-	var q1 *obj.Prog
-
 	// MOVD	g_stackguard(g), R3
 	p = obj.Appendp(ctxt, p)
 
@@ -659,7 +642,7 @@
 	p.To.Type = obj.TYPE_REG
 	p.To.Reg = REG_R3
 
-	q = nil
+	var q *obj.Prog
 	if framesize <= obj.StackSmall {
 		// small stack: SP < stackguard
 		//	CMP	stackguard, SP
@@ -750,7 +733,7 @@
 
 	// q1: BLT	done
 	p = obj.Appendp(ctxt, p)
-	q1 = p
+	q1 := p
 
 	p.As = ABLT
 	p.To.Type = obj.TYPE_BRANCH
@@ -795,13 +778,10 @@
 }
 
 func follow(ctxt *obj.Link, s *obj.LSym) {
-	var firstp *obj.Prog
-	var lastp *obj.Prog
-
 	ctxt.Cursym = s
 
-	firstp = ctxt.NewProg()
-	lastp = firstp
+	firstp := ctxt.NewProg()
+	lastp := firstp
 	xfol(ctxt, s.Text, &lastp)
 	lastp.Link = nil
 	s.Text = firstp.Link
@@ -872,7 +852,7 @@
 	if p.Mark&FOLL != 0 {
 		i = 0
 		q = p
-		for ; i < 4; (func() { i++; q = q.Link })() {
+		for ; i < 4; i, q = i+1, q.Link {
 			if q == *last || (q.Mark&NOSCHED != 0) {
 				break
 			}
@@ -965,12 +945,9 @@
 }
 
 var Linkppc64 = obj.LinkArch{
-	Rconv:      Rconv,
 	ByteOrder:  binary.BigEndian,
-	Pconv:      Pconv,
 	Name:       "ppc64",
 	Thechar:    '9',
-	Endian:     obj.BigEndian,
 	Preprocess: preprocess,
 	Assemble:   span9,
 	Follow:     follow,
@@ -981,12 +958,9 @@
 }
 
 var Linkppc64le = obj.LinkArch{
-	Rconv:      Rconv,
 	ByteOrder:  binary.LittleEndian,
-	Pconv:      Pconv,
 	Name:       "ppc64le",
 	Thechar:    '9',
-	Endian:     obj.LittleEndian,
 	Preprocess: preprocess,
 	Assemble:   span9,
 	Follow:     follow,
diff --git a/src/cmd/internal/obj/stringer.go b/src/cmd/internal/obj/stringer.go
new file mode 100644
index 0000000..c4b3712
--- /dev/null
+++ b/src/cmd/internal/obj/stringer.go
@@ -0,0 +1,104 @@
+// Copyright 2015 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.
+
+// +build ignore
+
+// This is a mini version of the stringer tool customized for the Anames table
+// in the architecture support for obj.
+// This version just generates the slice of strings, not the String method.
+
+package main
+
+import (
+	"bufio"
+	"flag"
+	"fmt"
+	"log"
+	"os"
+	"regexp"
+	"strings"
+)
+
+var (
+	input  = flag.String("i", "", "input file name")
+	output = flag.String("o", "", "output file name")
+	pkg    = flag.String("p", "", "package name")
+)
+
+var Are = regexp.MustCompile(`^\tA([A-Z0-9]+)`)
+
+func main() {
+	flag.Parse()
+	if *input == "" || *output == "" || *pkg == "" {
+		flag.Usage()
+		os.Exit(2)
+	}
+	in, err := os.Open(*input)
+	if err != nil {
+		log.Fatal(err)
+	}
+	fd, err := os.Create(*output)
+	if err != nil {
+		log.Fatal(err)
+	}
+	out := bufio.NewWriter(fd)
+	defer out.Flush()
+	var on = false
+	s := bufio.NewScanner(in)
+	first := true
+	for s.Scan() {
+		line := s.Text()
+		if !on {
+			// First relevant line contains "= obj.ABase".
+			// If we find it, delete the = so we don't stop immediately.
+			const prefix = "= obj.ABase"
+			index := strings.Index(line, prefix)
+			if index < 0 {
+				continue
+			}
+			// It's on. Start with the header.
+			fmt.Fprintf(out, header, *input, *output, *pkg, *pkg)
+			on = true
+			line = line[:index]
+		}
+		// Strip comments so their text won't defeat our heuristic.
+		index := strings.Index(line, "//")
+		if index > 0 {
+			line = line[:index]
+		}
+		index = strings.Index(line, "/*")
+		if index > 0 {
+			line = line[:index]
+		}
+		// Termination condition: Any line with an = changes the sequence,
+		// so stop there, and stop at a closing brace.
+		if strings.HasPrefix(line, "}") || strings.ContainsRune(line, '=') {
+			break
+		}
+		sub := Are.FindStringSubmatch(line)
+		if len(sub) < 2 {
+			continue
+		}
+		if first {
+			fmt.Fprintf(out, "\tobj.A_ARCHSPECIFIC: %q,\n", sub[1])
+			first = false
+		} else {
+			fmt.Fprintf(out, "\t%q,\n", sub[1])
+		}
+	}
+	fmt.Fprintln(out, "}")
+	if s.Err() != nil {
+		log.Fatal(err)
+	}
+}
+
+const header = `// Generated by stringer -i %s -o %s -p %s
+// Do not edit.
+
+package %s
+
+import "cmd/internal/obj"
+
+var Anames = []string{
+`
diff --git a/src/cmd/internal/obj/sym.go b/src/cmd/internal/obj/sym.go
index d22a339..3568a5c 100644
--- a/src/cmd/internal/obj/sym.go
+++ b/src/cmd/internal/obj/sym.go
@@ -123,11 +123,8 @@
 }
 
 func Linknew(arch *LinkArch) *Link {
-	var buf string
-
-	linksetexp()
-
 	ctxt := new(Link)
+	ctxt.Hash = make(map[SymVer]*LSym)
 	ctxt.Arch = arch
 	ctxt.Version = HistVersion
 	ctxt.Goroot = Getgoroot()
@@ -137,14 +134,18 @@
 		ctxt.Windows = 1
 	}
 
+	var buf string
 	buf, _ = os.Getwd()
 	if buf == "" {
 		buf = "/???"
 	}
 	buf = filepath.ToSlash(buf)
-
 	ctxt.Pathname = buf
 
+	ctxt.LineHist.GOROOT = ctxt.Goroot
+	ctxt.LineHist.GOROOT_FINAL = ctxt.Goroot_final
+	ctxt.LineHist.Dir = ctxt.Pathname
+
 	ctxt.Headtype = headtype(Getgoos())
 	if ctxt.Headtype < 0 {
 		log.Fatalf("unknown goos %s", Getgoos())
@@ -156,8 +157,7 @@
 	default:
 		log.Fatalf("unknown thread-local storage offset for %s", Headstr(ctxt.Headtype))
 
-	case Hplan9,
-		Hwindows:
+	case Hplan9, Hwindows:
 		break
 
 		/*
@@ -171,7 +171,7 @@
 		Hopenbsd,
 		Hdragonfly,
 		Hsolaris:
-		ctxt.Tlsoffset = -2 * ctxt.Arch.Ptrsize
+		ctxt.Tlsoffset = -1 * ctxt.Arch.Ptrsize
 
 	case Hnacl:
 		switch ctxt.Arch.Thechar {
@@ -232,7 +232,6 @@
 	s.Type = 0
 	s.Version = int16(v)
 	s.Value = 0
-	s.Sig = 0
 	s.Size = 0
 	ctxt.Nsymbol++
 
@@ -243,26 +242,14 @@
 }
 
 func _lookup(ctxt *Link, symb string, v int, creat int) *LSym {
-	h := uint32(v)
-	for i := 0; i < len(symb); i++ {
-		c := int(symb[i])
-		h = h + h + h + uint32(c)
-	}
-	h &= 0xffffff
-	h %= LINKHASH
-	for s := ctxt.Hash[h]; s != nil; s = s.Hash {
-		if int(s.Version) == v && s.Name == symb {
-			return s
-		}
-	}
-	if creat == 0 {
-		return nil
+	s := ctxt.Hash[SymVer{symb, v}]
+	if s != nil || creat == 0 {
+		return s
 	}
 
-	s := linknewsym(ctxt, symb, v)
+	s = linknewsym(ctxt, symb, v)
 	s.Extname = s.Name
-	s.Hash = ctxt.Hash[h]
-	ctxt.Hash[h] = s
+	ctxt.Hash[SymVer{symb, v}] = s
 
 	return s
 }
diff --git a/src/cmd/internal/obj/util.go b/src/cmd/internal/obj/util.go
index a3c88a2..b0d10b5 100644
--- a/src/cmd/internal/obj/util.go
+++ b/src/cmd/internal/obj/util.go
@@ -6,6 +6,7 @@
 
 import (
 	"bufio"
+	"bytes"
 	"fmt"
 	"io"
 	"log"
@@ -248,11 +249,93 @@
 	return Linklinefmt(p.Ctxt, int(p.Lineno), false, false)
 }
 
+var armCondCode = []string{
+	".EQ",
+	".NE",
+	".CS",
+	".CC",
+	".MI",
+	".PL",
+	".VS",
+	".VC",
+	".HI",
+	".LS",
+	".GE",
+	".LT",
+	".GT",
+	".LE",
+	"",
+	".NV",
+}
+
+/* ARM scond byte */
+const (
+	C_SCOND     = (1 << 4) - 1
+	C_SBIT      = 1 << 4
+	C_PBIT      = 1 << 5
+	C_WBIT      = 1 << 6
+	C_FBIT      = 1 << 7
+	C_UBIT      = 1 << 7
+	C_SCOND_XOR = 14
+)
+
+// CConv formats ARM condition codes.
+func CConv(s uint8) string {
+	if s == 0 {
+		return ""
+	}
+	sc := armCondCode[(s&C_SCOND)^C_SCOND_XOR]
+	if s&C_SBIT != 0 {
+		sc += ".S"
+	}
+	if s&C_PBIT != 0 {
+		sc += ".P"
+	}
+	if s&C_WBIT != 0 {
+		sc += ".W"
+	}
+	if s&C_UBIT != 0 { /* ambiguous with FBIT */
+		sc += ".U"
+	}
+	return sc
+}
+
 func (p *Prog) String() string {
 	if p.Ctxt == nil {
 		return "<Prog without ctxt>"
 	}
-	return p.Ctxt.Arch.Pconv(p)
+
+	sc := CConv(p.Scond)
+
+	var buf bytes.Buffer
+
+	fmt.Fprintf(&buf, "%.5d (%v)\t%v%s", p.Pc, p.Line(), Aconv(int(p.As)), sc)
+	sep := "\t"
+	if p.From.Type != TYPE_NONE {
+		fmt.Fprintf(&buf, "%s%v", sep, Dconv(p, &p.From))
+		sep = ", "
+	}
+	if p.Reg != REG_NONE {
+		// Should not happen but might as well show it if it does.
+		fmt.Fprintf(&buf, "%s%v", sep, Rconv(int(p.Reg)))
+		sep = ", "
+	}
+	if p.From3.Type != TYPE_NONE {
+		if p.From3.Type == TYPE_CONST && (p.As == ADATA || p.As == ATEXT || p.As == AGLOBL) {
+			// Special case - omit $.
+			fmt.Fprintf(&buf, "%s%d", sep, p.From3.Offset)
+		} else {
+			fmt.Fprintf(&buf, "%s%v", sep, Dconv(p, &p.From3))
+		}
+		sep = ", "
+	}
+	if p.To.Type != TYPE_NONE {
+		fmt.Fprintf(&buf, "%s%v", sep, Dconv(p, &p.To))
+	}
+	if p.To2.Type != TYPE_NONE {
+		fmt.Fprintf(&buf, "%s%v", sep, Dconv(p, &p.To2))
+	}
+	return buf.String()
 }
 
 func (ctxt *Link) NewProg() *Prog {
@@ -306,8 +389,8 @@
 			str = fmt.Sprintf("%s(SB)", a.Sym.Name)
 		} else if p != nil && p.Pcond != nil {
 			str = fmt.Sprintf("%d", p.Pcond.Pc)
-		} else if a.U.Branch != nil {
-			str = fmt.Sprintf("%d", a.U.Branch.Pc)
+		} else if a.Val != nil {
+			str = fmt.Sprintf("%d", a.Val.(*Prog).Pc)
 		} else {
 			str = fmt.Sprintf("%d(PC)", a.Offset)
 		}
@@ -329,14 +412,14 @@
 		}
 
 	case TYPE_TEXTSIZE:
-		if a.U.Argsize == ArgsSizeUnknown {
+		if a.Val.(int32) == ArgsSizeUnknown {
 			str = fmt.Sprintf("$%d", a.Offset)
 		} else {
-			str = fmt.Sprintf("$%d-%d", a.Offset, a.U.Argsize)
+			str = fmt.Sprintf("$%d-%d", a.Offset, a.Val.(int32))
 		}
 
 	case TYPE_FCONST:
-		str = fmt.Sprintf("%.17g", a.U.Dval)
+		str = fmt.Sprintf("%.17g", a.Val.(float64))
 		// Make sure 1 prints as 1.0
 		if !strings.ContainsAny(str, ".e") {
 			str += ".0"
@@ -344,7 +427,7 @@
 		str = fmt.Sprintf("$(%s)", str)
 
 	case TYPE_SCONST:
-		str = fmt.Sprintf("$%q", a.U.Sval)
+		str = fmt.Sprintf("$%q", a.Val.(string))
 
 	case TYPE_ADDR:
 		str = fmt.Sprintf("$%s", Mconv(a))
@@ -443,10 +526,8 @@
 	RBase386   = 1 * 1024
 	RBaseAMD64 = 2 * 1024
 	RBaseARM   = 3 * 1024
-	RBasePPC64 = 4 * 1024
-	// The next free base is 8*1024 (PPC64 has many registers).
-	// Alternatively, the next architecture, with an ordinary
-	// number of registers, could go under PPC64.
+	RBasePPC64 = 4 * 1024 // range [4k, 8k)
+	RBaseARM64 = 8 * 1024 // range [8k, 12k)
 )
 
 // RegisterRegister binds a pretty-printer (Rconv) for register
@@ -491,3 +572,69 @@
 	str += "]"
 	return str
 }
+
+/*
+	Each architecture defines an instruction (A*) space as a unique
+	integer range.
+	Global opcodes like CALL start at 0; the architecture-specific ones
+	start at a distinct, big-maskable offsets.
+	Here is the list of architectures and the base of their opcode spaces.
+*/
+
+const (
+	ABase386 = (1 + iota) << 12
+	ABaseARM
+	ABaseAMD64
+	ABasePPC64
+	ABaseARM64
+	AMask = 1<<12 - 1 // AND with this to use the opcode as an array index.
+)
+
+type opSet struct {
+	lo    int
+	names []string
+}
+
+// Not even worth sorting
+var aSpace []opSet
+
+// RegisterOpcode binds a list of instruction names
+// to a given instruction number range.
+func RegisterOpcode(lo int, Anames []string) {
+	aSpace = append(aSpace, opSet{lo, Anames})
+}
+
+func Aconv(a int) string {
+	if a < A_ARCHSPECIFIC {
+		return Anames[a]
+	}
+	for i := range aSpace {
+		as := &aSpace[i]
+		if as.lo <= a && a < as.lo+len(as.names) {
+			return as.names[a-as.lo]
+		}
+	}
+	return fmt.Sprintf("A???%d", a)
+}
+
+var Anames = []string{
+	"XXX",
+	"CALL",
+	"CHECKNIL",
+	"DATA",
+	"DUFFCOPY",
+	"DUFFZERO",
+	"END",
+	"FUNCDATA",
+	"GLOBL",
+	"JMP",
+	"NOP",
+	"PCDATA",
+	"RET",
+	"TEXT",
+	"TYPE",
+	"UNDEF",
+	"USEFIELD",
+	"VARDEF",
+	"VARKILL",
+}
diff --git a/src/cmd/internal/obj/x86/6.out.go b/src/cmd/internal/obj/x86/6.out.go
index 82f9291..c7f46e1 100644
--- a/src/cmd/internal/obj/x86/6.out.go
+++ b/src/cmd/internal/obj/x86/6.out.go
@@ -32,11 +32,13 @@
 
 import "cmd/internal/obj"
 
+//go:generate go run ../stringer.go -i $GOFILE -o anames.go -p x86
+
 /*
  *	amd64
  */
 const (
-	AAAA = obj.A_ARCHSPECIFIC + iota
+	AAAA = obj.ABaseAMD64 + obj.A_ARCHSPECIFIC + iota
 	AAAD
 	AAAM
 	AAAS
@@ -264,6 +266,7 @@
 	AXORB
 	AXORL
 	AXORW
+
 	AFMOVB
 	AFMOVBP
 	AFMOVD
@@ -278,6 +281,7 @@
 	AFMOVWP
 	AFMOVX
 	AFMOVXP
+
 	AFCOMB
 	AFCOMBP
 	AFCOMD
@@ -292,38 +296,46 @@
 	AFUCOM
 	AFUCOMP
 	AFUCOMPP
+
 	AFADDDP
 	AFADDW
 	AFADDL
 	AFADDF
 	AFADDD
+
 	AFMULDP
 	AFMULW
 	AFMULL
 	AFMULF
 	AFMULD
+
 	AFSUBDP
 	AFSUBW
 	AFSUBL
 	AFSUBF
 	AFSUBD
+
 	AFSUBRDP
 	AFSUBRW
 	AFSUBRL
 	AFSUBRF
 	AFSUBRD
+
 	AFDIVDP
 	AFDIVW
 	AFDIVL
 	AFDIVF
 	AFDIVD
+
 	AFDIVRDP
 	AFDIVRW
 	AFDIVRL
 	AFDIVRF
 	AFDIVRD
+
 	AFXCHD
 	AFFREE
+
 	AFLDCW
 	AFLDENV
 	AFRSTOR
@@ -331,6 +343,7 @@
 	AFSTCW
 	AFSTENV
 	AFSTSW
+
 	AF2XM1
 	AFABS
 	AFCHS
@@ -361,6 +374,8 @@
 	AFXTRACT
 	AFYL2X
 	AFYL2XP1
+
+	// extra 32-bit operations
 	ACMPXCHGB
 	ACMPXCHGL
 	ACMPXCHGW
@@ -382,6 +397,8 @@
 	AXADDB
 	AXADDL
 	AXADDW
+
+	// conditional move
 	ACMOVLCC
 	ACMOVLCS
 	ACMOVLEQ
@@ -430,6 +447,8 @@
 	ACMOVWPC
 	ACMOVWPL
 	ACMOVWPS
+
+	// 64-bit
 	AADCQ
 	AADDQ
 	AANDQ
@@ -481,6 +500,8 @@
 	AXADDQ
 	AXCHGQ
 	AXORQ
+
+	// media
 	AADDPD
 	AADDPS
 	AADDSD
@@ -682,6 +703,7 @@
 	AUNPCKLPS
 	AXORPD
 	AXORPS
+
 	APF2IW
 	APF2IL
 	API2FW
@@ -690,31 +712,55 @@
 	ARETFL
 	ARETFQ
 	ASWAPGS
+
 	AMODE
 	ACRC32B
 	ACRC32Q
 	AIMUL3Q
+
 	APREFETCHT0
 	APREFETCHT1
 	APREFETCHT2
 	APREFETCHNTA
+
 	AMOVQL
 	ABSWAPL
 	ABSWAPQ
+
 	AAESENC
 	AAESENCLAST
 	AAESDEC
 	AAESDECLAST
 	AAESIMC
 	AAESKEYGENASSIST
+
 	APSHUFD
 	APCLMULQDQ
+
+	// from 386
+	AJCXZW
+	AFCMOVCC
+	AFCMOVCS
+	AFCMOVEQ
+	AFCMOVHI
+	AFCMOVLS
+	AFCMOVNE
+	AFCMOVNU
+	AFCMOVUN
+	AFCOMI
+	AFCOMIP
+	AFUCOMI
+	AFUCOMIP
+
 	ALAST
 )
 
 const (
 	REG_NONE = 0
-	REG_AL   = obj.RBaseAMD64 + 0 + iota - 1
+)
+
+const (
+	REG_AL = obj.RBaseAMD64 + iota
 	REG_CL
 	REG_DL
 	REG_BL
@@ -730,7 +776,8 @@
 	REG_R13B
 	REG_R14B
 	REG_R15B
-	REG_AX = obj.RBaseAMD64 + 16 + iota - 17
+
+	REG_AX
 	REG_CX
 	REG_DX
 	REG_BX
@@ -746,13 +793,31 @@
 	REG_R13
 	REG_R14
 	REG_R15
-	REG_AH = obj.RBaseAMD64 + 32 + iota - 33
+
+	REG_AH
 	REG_CH
 	REG_DH
 	REG_BH
-	REG_F0 = obj.RBaseAMD64 + 36
-	REG_M0 = obj.RBaseAMD64 + 44
-	REG_X0 = obj.RBaseAMD64 + 52 + iota - 39
+
+	REG_F0
+	REG_F1
+	REG_F2
+	REG_F3
+	REG_F4
+	REG_F5
+	REG_F6
+	REG_F7
+
+	REG_M0
+	REG_M1
+	REG_M2
+	REG_M3
+	REG_M4
+	REG_M5
+	REG_M6
+	REG_M7
+
+	REG_X0
 	REG_X1
 	REG_X2
 	REG_X3
@@ -768,31 +833,72 @@
 	REG_X13
 	REG_X14
 	REG_X15
-	REG_CS = obj.RBaseAMD64 + 68 + iota - 55
+
+	REG_CS
 	REG_SS
 	REG_DS
 	REG_ES
 	REG_FS
 	REG_GS
-	REG_GDTR
-	REG_IDTR
-	REG_LDTR
-	REG_MSW
-	REG_TASK
-	REG_CR  = obj.RBaseAMD64 + 79
-	REG_DR  = obj.RBaseAMD64 + 95
-	REG_TR  = obj.RBaseAMD64 + 103
-	REG_TLS = obj.RBaseAMD64 + 111 + iota - 69
+
+	REG_GDTR /* global descriptor table register */
+	REG_IDTR /* interrupt descriptor table register */
+	REG_LDTR /* local descriptor table register */
+	REG_MSW  /* machine status word */
+	REG_TASK /* task register */
+
+	REG_CR0
+	REG_CR1
+	REG_CR2
+	REG_CR3
+	REG_CR4
+	REG_CR5
+	REG_CR6
+	REG_CR7
+	REG_CR8
+	REG_CR9
+	REG_CR10
+	REG_CR11
+	REG_CR12
+	REG_CR13
+	REG_CR14
+	REG_CR15
+
+	REG_DR0
+	REG_DR1
+	REG_DR2
+	REG_DR3
+	REG_DR4
+	REG_DR5
+	REG_DR6
+	REG_DR7
+
+	REG_TR0
+	REG_TR1
+	REG_TR2
+	REG_TR3
+	REG_TR4
+	REG_TR5
+	REG_TR6
+	REG_TR7
+
+	REG_TLS
+
 	MAXREG
+
+	REG_CR = REG_CR0
+	REG_DR = REG_DR0
+	REG_TR = REG_TR0
+
 	REGARG   = -1
 	REGRET   = REG_AX
 	FREGRET  = REG_X0
 	REGSP    = REG_SP
 	REGTMP   = REG_DI
 	REGCTXT  = REG_DX
-	REGEXT   = REG_R15
-	FREGMIN  = REG_X0 + 5
-	FREGEXT  = REG_X0 + 15
+	REGEXT   = REG_R15     /* compiler allocates external registers R15 down */
+	FREGMIN  = REG_X0 + 5  /* first register variable */
+	FREGEXT  = REG_X0 + 15 /* first external register */
 	T_TYPE   = 1 << 0
 	T_INDEX  = 1 << 1
 	T_OFFSET = 1 << 2
diff --git a/src/cmd/internal/obj/x86/anames6.go b/src/cmd/internal/obj/x86/anames.go
similarity index 95%
rename from src/cmd/internal/obj/x86/anames6.go
rename to src/cmd/internal/obj/x86/anames.go
index fca730bf..7f7dd56 100644
--- a/src/cmd/internal/obj/x86/anames6.go
+++ b/src/cmd/internal/obj/x86/anames.go
@@ -1,29 +1,12 @@
+// Generated by stringer -i 6.out.go -o anames.go -p x86
+// Do not edit.
+
 package x86
 
-/*
- * this is the ranlib header
- */
+import "cmd/internal/obj"
+
 var Anames = []string{
-	"XXX",
-	"CALL",
-	"CHECKNIL",
-	"DATA",
-	"DUFFCOPY",
-	"DUFFZERO",
-	"END",
-	"FUNCDATA",
-	"GLOBL",
-	"JMP",
-	"NOP",
-	"PCDATA",
-	"RET",
-	"TEXT",
-	"TYPE",
-	"UNDEF",
-	"USEFIELD",
-	"VARDEF",
-	"VARKILL",
-	"AAA",
+	obj.A_ARCHSPECIFIC: "AAA",
 	"AAD",
 	"AAM",
 	"AAS",
@@ -696,5 +679,18 @@
 	"AESKEYGENASSIST",
 	"PSHUFD",
 	"PCLMULQDQ",
+	"JCXZW",
+	"FCMOVCC",
+	"FCMOVCS",
+	"FCMOVEQ",
+	"FCMOVHI",
+	"FCMOVLS",
+	"FCMOVNE",
+	"FCMOVNU",
+	"FCMOVUN",
+	"FCOMI",
+	"FCOMIP",
+	"FUCOMI",
+	"FUCOMIP",
 	"LAST",
 }
diff --git a/src/cmd/internal/obj/x86/asm6.go b/src/cmd/internal/obj/x86/asm6.go
index 5af037f..997e920 100644
--- a/src/cmd/internal/obj/x86/asm6.go
+++ b/src/cmd/internal/obj/x86/asm6.go
@@ -40,7 +40,21 @@
 // Instruction layout.
 
 const (
-	MaxAlign   = 32
+	MaxAlign = 32 // max data alignment
+
+	// Loop alignment constants:
+	// want to align loop entry to LoopAlign-byte boundary,
+	// and willing to insert at most MaxLoopPad bytes of NOP to do so.
+	// We define a loop entry as the target of a backward jump.
+	//
+	// gcc uses MaxLoopPad = 10 for its 'generic x86-64' config,
+	// and it aligns all jump targets, not just backward jump targets.
+	//
+	// As of 6/1/2012, the effect of setting MaxLoopPad = 10 here
+	// is very slight but negative, so the alignment is disabled by
+	// setting MaxLoopPad = 0. The code is here for reference and
+	// for future experiments.
+	//
 	LoopAlign  = 16
 	MaxLoopPad = 0
 	FuncAlign  = 16
@@ -55,6 +69,7 @@
 
 type ytab struct {
 	from    uint8
+	from3   uint8
 	to      uint8
 	zcase   uint8
 	zoffset uint8
@@ -63,17 +78,20 @@
 type Movtab struct {
 	as   int16
 	ft   uint8
+	f3t  uint8
 	tt   uint8
 	code uint8
 	op   [4]uint8
 }
 
 const (
-	Yxxx = 0 + iota
+	Yxxx = iota
 	Ynone
-	Yi0
-	Yi1
-	Yi8
+	Yi0 // $0
+	Yi1 // $1
+	Yi8 // $x, x fits in int8
+	Yu8 // $x, x fits in uint8
+	Yu7 // $x, x in 0..127 (fits in both int8 and uint8)
 	Ys32
 	Yi32
 	Yi64
@@ -84,6 +102,7 @@
 	Ycx
 	Yrb
 	Yrl
+	Yrl32 // Yrl on 32-bit system
 	Yrf
 	Yf0
 	Yrx
@@ -91,7 +110,6 @@
 	Yml
 	Ym
 	Ybr
-	Ycol
 	Ycs
 	Yss
 	Yds
@@ -128,21 +146,26 @@
 	Ytr5
 	Ytr6
 	Ytr7
-	Yrl32
-	Yrl64
 	Ymr
 	Ymm
 	Yxr
 	Yxm
 	Ytls
 	Ytextsize
+	Yindir
 	Ymax
-	Zxxx = 0 + iota - 68
+)
+
+const (
+	Zxxx = iota
 	Zlit
 	Zlitm_r
 	Z_rp
 	Zbr
 	Zcall
+	Zcallcon
+	Zcallduff
+	Zcallind
 	Zcallindreg
 	Zib_
 	Zib_rp
@@ -154,6 +177,7 @@
 	Zilo_m
 	Ziqo_m
 	Zjmp
+	Zjmpcon
 	Zloop
 	Zo_iw
 	Zm_o
@@ -164,7 +188,7 @@
 	Zm_r_3d
 	Zm_r_xm_nr
 	Zr_m_xm_nr
-	Zibm_r
+	Zibm_r /* mmx1,mmx2/mem64,imm8 */
 	Zmb_r
 	Zaut_r
 	Zo_m
@@ -172,7 +196,6 @@
 	Zpseudo
 	Zr_m
 	Zr_m_xm
-	Zr_m_i_xm
 	Zrp_
 	Z_ib
 	Z_il
@@ -183,24 +206,33 @@
 	Zclr
 	Zbyte
 	Zmax
-	Px     = 0
-	P32    = 0x32
-	Pe     = 0x66
-	Pm     = 0x0f
-	Pq     = 0xff
-	Pb     = 0xfe
-	Pf2    = 0xf2
-	Pf3    = 0xf3
-	Pq3    = 0x67
-	Pw     = 0x48
-	Py     = 0x80
-	Rxf    = 1 << 9
-	Rxt    = 1 << 8
-	Rxw    = 1 << 3
-	Rxr    = 1 << 2
-	Rxx    = 1 << 1
-	Rxb    = 1 << 0
-	Maxand = 10
+)
+
+const (
+	Px  = 0
+	Px1 = 1    // symbolic; exact value doesn't matter
+	P32 = 0x32 /* 32-bit only */
+	Pe  = 0x66 /* operand escape */
+	Pm  = 0x0f /* 2byte opcode escape */
+	Pq  = 0xff /* both escapes: 66 0f */
+	Pb  = 0xfe /* byte operands */
+	Pf2 = 0xf2 /* xmm escape 1: f2 0f */
+	Pf3 = 0xf3 /* xmm escape 2: f3 0f */
+	Pq3 = 0x67 /* xmm escape 3: 66 48 0f */
+	Pw  = 0x48 /* Rex.w */
+	Pw8 = 0x90 // symbolic; exact value doesn't matter
+	Py  = 0x80 /* defaults to 64-bit mode */
+	Py1 = 0x81 // symbolic; exact value doesn't matter
+	Py3 = 0x83 // symbolic; exact value doesn't matter
+
+	Rxf = 1 << 9 /* internal flag for Rxr on from */
+	Rxt = 1 << 8 /* internal flag for Rxr on to */
+	Rxw = 1 << 3 /* =1, 64-bit operand size */
+	Rxr = 1 << 2 /* extend modrm reg */
+	Rxx = 1 << 1 /* extend sib index */
+	Rxb = 1 << 0 /* extend modrm r/m, sib base, or opcode reg */
+
+	Maxand = 10 /* in -a output width of the byte codes */
 )
 
 var ycover [Ymax * Ymax]uint8
@@ -210,481 +242,502 @@
 var regrex [MAXREG + 1]int
 
 var ynone = []ytab{
-	{Ynone, Ynone, Zlit, 1},
+	{Ynone, Ynone, Ynone, Zlit, 1},
+}
+
+var ysahf = []ytab{
+	{Ynone, Ynone, Ynone, Zlit, 2},
+	{Ynone, Ynone, Ynone, Zlit, 1},
 }
 
 var ytext = []ytab{
-	{Ymb, Ytextsize, Zpseudo, 1},
+	{Ymb, Ynone, Ytextsize, Zpseudo, 0},
+	{Ymb, Yi32, Ytextsize, Zpseudo, 1},
 }
 
 var ynop = []ytab{
-	{Ynone, Ynone, Zpseudo, 0},
-	{Ynone, Yiauto, Zpseudo, 0},
-	{Ynone, Yml, Zpseudo, 0},
-	{Ynone, Yrf, Zpseudo, 0},
-	{Ynone, Yxr, Zpseudo, 0},
-	{Yiauto, Ynone, Zpseudo, 0},
-	{Yml, Ynone, Zpseudo, 0},
-	{Yrf, Ynone, Zpseudo, 0},
-	{Yxr, Ynone, Zpseudo, 1},
+	{Ynone, Ynone, Ynone, Zpseudo, 0},
+	{Ynone, Ynone, Yiauto, Zpseudo, 0},
+	{Ynone, Ynone, Yml, Zpseudo, 0},
+	{Ynone, Ynone, Yrf, Zpseudo, 0},
+	{Ynone, Ynone, Yxr, Zpseudo, 0},
+	{Yiauto, Ynone, Ynone, Zpseudo, 0},
+	{Yml, Ynone, Ynone, Zpseudo, 0},
+	{Yrf, Ynone, Ynone, Zpseudo, 0},
+	{Yxr, Ynone, Ynone, Zpseudo, 1},
 }
 
 var yfuncdata = []ytab{
-	{Yi32, Ym, Zpseudo, 0},
+	{Yi32, Ynone, Ym, Zpseudo, 0},
 }
 
 var ypcdata = []ytab{
-	{Yi32, Yi32, Zpseudo, 0},
+	{Yi32, Ynone, Yi32, Zpseudo, 0},
 }
 
 var yxorb = []ytab{
-	{Yi32, Yal, Zib_, 1},
-	{Yi32, Ymb, Zibo_m, 2},
-	{Yrb, Ymb, Zr_m, 1},
-	{Ymb, Yrb, Zm_r, 1},
+	{Yi32, Ynone, Yal, Zib_, 1},
+	{Yi32, Ynone, Ymb, Zibo_m, 2},
+	{Yrb, Ynone, Ymb, Zr_m, 1},
+	{Ymb, Ynone, Yrb, Zm_r, 1},
 }
 
 var yxorl = []ytab{
-	{Yi8, Yml, Zibo_m, 2},
-	{Yi32, Yax, Zil_, 1},
-	{Yi32, Yml, Zilo_m, 2},
-	{Yrl, Yml, Zr_m, 1},
-	{Yml, Yrl, Zm_r, 1},
+	{Yi8, Ynone, Yml, Zibo_m, 2},
+	{Yi32, Ynone, Yax, Zil_, 1},
+	{Yi32, Ynone, Yml, Zilo_m, 2},
+	{Yrl, Ynone, Yml, Zr_m, 1},
+	{Yml, Ynone, Yrl, Zm_r, 1},
 }
 
 var yaddl = []ytab{
-	{Yi8, Yml, Zibo_m, 2},
-	{Yi32, Yax, Zil_, 1},
-	{Yi32, Yml, Zilo_m, 2},
-	{Yrl, Yml, Zr_m, 1},
-	{Yml, Yrl, Zm_r, 1},
+	{Yi8, Ynone, Yml, Zibo_m, 2},
+	{Yi32, Ynone, Yax, Zil_, 1},
+	{Yi32, Ynone, Yml, Zilo_m, 2},
+	{Yrl, Ynone, Yml, Zr_m, 1},
+	{Yml, Ynone, Yrl, Zm_r, 1},
 }
 
 var yincb = []ytab{
-	{Ynone, Ymb, Zo_m, 2},
+	{Ynone, Ynone, Ymb, Zo_m, 2},
 }
 
 var yincw = []ytab{
-	{Ynone, Yml, Zo_m, 2},
+	{Ynone, Ynone, Yml, Zo_m, 2},
 }
 
 var yincl = []ytab{
-	{Ynone, Yml, Zo_m, 2},
+	{Ynone, Ynone, Yrl, Z_rp, 1},
+	{Ynone, Ynone, Yml, Zo_m, 2},
+}
+
+var yincq = []ytab{
+	{Ynone, Ynone, Yml, Zo_m, 2},
 }
 
 var ycmpb = []ytab{
-	{Yal, Yi32, Z_ib, 1},
-	{Ymb, Yi32, Zm_ibo, 2},
-	{Ymb, Yrb, Zm_r, 1},
-	{Yrb, Ymb, Zr_m, 1},
+	{Yal, Ynone, Yi32, Z_ib, 1},
+	{Ymb, Ynone, Yi32, Zm_ibo, 2},
+	{Ymb, Ynone, Yrb, Zm_r, 1},
+	{Yrb, Ynone, Ymb, Zr_m, 1},
 }
 
 var ycmpl = []ytab{
-	{Yml, Yi8, Zm_ibo, 2},
-	{Yax, Yi32, Z_il, 1},
-	{Yml, Yi32, Zm_ilo, 2},
-	{Yml, Yrl, Zm_r, 1},
-	{Yrl, Yml, Zr_m, 1},
+	{Yml, Ynone, Yi8, Zm_ibo, 2},
+	{Yax, Ynone, Yi32, Z_il, 1},
+	{Yml, Ynone, Yi32, Zm_ilo, 2},
+	{Yml, Ynone, Yrl, Zm_r, 1},
+	{Yrl, Ynone, Yml, Zr_m, 1},
 }
 
 var yshb = []ytab{
-	{Yi1, Ymb, Zo_m, 2},
-	{Yi32, Ymb, Zibo_m, 2},
-	{Ycx, Ymb, Zo_m, 2},
+	{Yi1, Ynone, Ymb, Zo_m, 2},
+	{Yi32, Ynone, Ymb, Zibo_m, 2},
+	{Ycx, Ynone, Ymb, Zo_m, 2},
 }
 
 var yshl = []ytab{
-	{Yi1, Yml, Zo_m, 2},
-	{Yi32, Yml, Zibo_m, 2},
-	{Ycl, Yml, Zo_m, 2},
-	{Ycx, Yml, Zo_m, 2},
+	{Yi1, Ynone, Yml, Zo_m, 2},
+	{Yi32, Ynone, Yml, Zibo_m, 2},
+	{Ycl, Ynone, Yml, Zo_m, 2},
+	{Ycx, Ynone, Yml, Zo_m, 2},
 }
 
 var ytestb = []ytab{
-	{Yi32, Yal, Zib_, 1},
-	{Yi32, Ymb, Zibo_m, 2},
-	{Yrb, Ymb, Zr_m, 1},
-	{Ymb, Yrb, Zm_r, 1},
+	{Yi32, Ynone, Yal, Zib_, 1},
+	{Yi32, Ynone, Ymb, Zibo_m, 2},
+	{Yrb, Ynone, Ymb, Zr_m, 1},
+	{Ymb, Ynone, Yrb, Zm_r, 1},
 }
 
 var ytestl = []ytab{
-	{Yi32, Yax, Zil_, 1},
-	{Yi32, Yml, Zilo_m, 2},
-	{Yrl, Yml, Zr_m, 1},
-	{Yml, Yrl, Zm_r, 1},
+	{Yi32, Ynone, Yax, Zil_, 1},
+	{Yi32, Ynone, Yml, Zilo_m, 2},
+	{Yrl, Ynone, Yml, Zr_m, 1},
+	{Yml, Ynone, Yrl, Zm_r, 1},
 }
 
 var ymovb = []ytab{
-	{Yrb, Ymb, Zr_m, 1},
-	{Ymb, Yrb, Zm_r, 1},
-	{Yi32, Yrb, Zib_rp, 1},
-	{Yi32, Ymb, Zibo_m, 2},
+	{Yrb, Ynone, Ymb, Zr_m, 1},
+	{Ymb, Ynone, Yrb, Zm_r, 1},
+	{Yi32, Ynone, Yrb, Zib_rp, 1},
+	{Yi32, Ynone, Ymb, Zibo_m, 2},
 }
 
 var ymbs = []ytab{
-	{Ymb, Ynone, Zm_o, 2},
+	{Ymb, Ynone, Ynone, Zm_o, 2},
 }
 
 var ybtl = []ytab{
-	{Yi8, Yml, Zibo_m, 2},
-	{Yrl, Yml, Zr_m, 1},
+	{Yi8, Ynone, Yml, Zibo_m, 2},
+	{Yrl, Ynone, Yml, Zr_m, 1},
 }
 
 var ymovw = []ytab{
-	{Yrl, Yml, Zr_m, 1},
-	{Yml, Yrl, Zm_r, 1},
-	{Yi0, Yrl, Zclr, 1},
-	{Yi32, Yrl, Zil_rp, 1},
-	{Yi32, Yml, Zilo_m, 2},
-	{Yiauto, Yrl, Zaut_r, 2},
+	{Yrl, Ynone, Yml, Zr_m, 1},
+	{Yml, Ynone, Yrl, Zm_r, 1},
+	{Yi0, Ynone, Yrl, Zclr, 1},
+	{Yi32, Ynone, Yrl, Zil_rp, 1},
+	{Yi32, Ynone, Yml, Zilo_m, 2},
+	{Yiauto, Ynone, Yrl, Zaut_r, 2},
 }
 
 var ymovl = []ytab{
-	{Yrl, Yml, Zr_m, 1},
-	{Yml, Yrl, Zm_r, 1},
-	{Yi0, Yrl, Zclr, 1},
-	{Yi32, Yrl, Zil_rp, 1},
-	{Yi32, Yml, Zilo_m, 2},
-	{Yml, Ymr, Zm_r_xm, 1}, // MMX MOVD
-	{Ymr, Yml, Zr_m_xm, 1}, // MMX MOVD
-	{Yml, Yxr, Zm_r_xm, 2}, // XMM MOVD (32 bit)
-	{Yxr, Yml, Zr_m_xm, 2}, // XMM MOVD (32 bit)
-	{Yiauto, Yrl, Zaut_r, 2},
+	{Yrl, Ynone, Yml, Zr_m, 1},
+	{Yml, Ynone, Yrl, Zm_r, 1},
+	{Yi0, Ynone, Yrl, Zclr, 1},
+	{Yi32, Ynone, Yrl, Zil_rp, 1},
+	{Yi32, Ynone, Yml, Zilo_m, 2},
+	{Yml, Ynone, Ymr, Zm_r_xm, 1}, // MMX MOVD
+	{Ymr, Ynone, Yml, Zr_m_xm, 1}, // MMX MOVD
+	{Yml, Ynone, Yxr, Zm_r_xm, 2}, // XMM MOVD (32 bit)
+	{Yxr, Ynone, Yml, Zr_m_xm, 2}, // XMM MOVD (32 bit)
+	{Yiauto, Ynone, Yrl, Zaut_r, 2},
 }
 
 var yret = []ytab{
-	{Ynone, Ynone, Zo_iw, 1},
-	{Yi32, Ynone, Zo_iw, 1},
+	{Ynone, Ynone, Ynone, Zo_iw, 1},
+	{Yi32, Ynone, Ynone, Zo_iw, 1},
 }
 
 var ymovq = []ytab{
-	{Yrl, Yml, Zr_m, 1},       // 0x89
-	{Yml, Yrl, Zm_r, 1},       // 0x8b
-	{Yi0, Yrl, Zclr, 1},       // 0x31
-	{Ys32, Yrl, Zilo_m, 2},    // 32 bit signed 0xc7,(0)
-	{Yi64, Yrl, Ziq_rp, 1},    // 0xb8 -- 32/64 bit immediate
-	{Yi32, Yml, Zilo_m, 2},    // 0xc7,(0)
-	{Ym, Ymr, Zm_r_xm_nr, 1},  // MMX MOVQ (shorter encoding)
-	{Ymr, Ym, Zr_m_xm_nr, 1},  // MMX MOVQ
-	{Ymm, Ymr, Zm_r_xm, 1},    // MMX MOVD
-	{Ymr, Ymm, Zr_m_xm, 1},    // MMX MOVD
-	{Yxr, Ymr, Zm_r_xm_nr, 2}, // MOVDQ2Q
-	{Yxm, Yxr, Zm_r_xm_nr, 2}, // MOVQ xmm1/m64 -> xmm2
-	{Yxr, Yxm, Zr_m_xm_nr, 2}, // MOVQ xmm1 -> xmm2/m64
-	{Yml, Yxr, Zm_r_xm, 2},    // MOVD xmm load
-	{Yxr, Yml, Zr_m_xm, 2},    // MOVD xmm store
-	{Yiauto, Yrl, Zaut_r, 2},  // built-in LEAQ
+	// valid in 32-bit mode
+	{Ym, Ynone, Ymr, Zm_r_xm_nr, 1},  // 0x6f MMX MOVQ (shorter encoding)
+	{Ymr, Ynone, Ym, Zr_m_xm_nr, 1},  // 0x7f MMX MOVQ
+	{Yxr, Ynone, Ymr, Zm_r_xm_nr, 2}, // Pf2, 0xd6 MOVDQ2Q
+	{Yxm, Ynone, Yxr, Zm_r_xm_nr, 2}, // Pf3, 0x7e MOVQ xmm1/m64 -> xmm2
+	{Yxr, Ynone, Yxm, Zr_m_xm_nr, 2}, // Pe, 0xd6 MOVQ xmm1 -> xmm2/m64
+
+	// valid only in 64-bit mode, usually with 64-bit prefix
+	{Yrl, Ynone, Yml, Zr_m, 1},      // 0x89
+	{Yml, Ynone, Yrl, Zm_r, 1},      // 0x8b
+	{Yi0, Ynone, Yrl, Zclr, 1},      // 0x31
+	{Ys32, Ynone, Yrl, Zilo_m, 2},   // 32 bit signed 0xc7,(0)
+	{Yi64, Ynone, Yrl, Ziq_rp, 1},   // 0xb8 -- 32/64 bit immediate
+	{Yi32, Ynone, Yml, Zilo_m, 2},   // 0xc7,(0)
+	{Ymm, Ynone, Ymr, Zm_r_xm, 1},   // 0x6e MMX MOVD
+	{Ymr, Ynone, Ymm, Zr_m_xm, 1},   // 0x7e MMX MOVD
+	{Yml, Ynone, Yxr, Zm_r_xm, 2},   // Pe, 0x6e MOVD xmm load
+	{Yxr, Ynone, Yml, Zr_m_xm, 2},   // Pe, 0x7e MOVD xmm store
+	{Yiauto, Ynone, Yrl, Zaut_r, 1}, // 0 built-in LEAQ
 }
 
 var ym_rl = []ytab{
-	{Ym, Yrl, Zm_r, 1},
+	{Ym, Ynone, Yrl, Zm_r, 1},
 }
 
 var yrl_m = []ytab{
-	{Yrl, Ym, Zr_m, 1},
+	{Yrl, Ynone, Ym, Zr_m, 1},
 }
 
 var ymb_rl = []ytab{
-	{Ymb, Yrl, Zmb_r, 1},
+	{Ymb, Ynone, Yrl, Zmb_r, 1},
 }
 
 var yml_rl = []ytab{
-	{Yml, Yrl, Zm_r, 1},
+	{Yml, Ynone, Yrl, Zm_r, 1},
 }
 
 var yrl_ml = []ytab{
-	{Yrl, Yml, Zr_m, 1},
+	{Yrl, Ynone, Yml, Zr_m, 1},
 }
 
 var yml_mb = []ytab{
-	{Yrb, Ymb, Zr_m, 1},
-	{Ymb, Yrb, Zm_r, 1},
+	{Yrb, Ynone, Ymb, Zr_m, 1},
+	{Ymb, Ynone, Yrb, Zm_r, 1},
 }
 
 var yrb_mb = []ytab{
-	{Yrb, Ymb, Zr_m, 1},
+	{Yrb, Ynone, Ymb, Zr_m, 1},
 }
 
 var yxchg = []ytab{
-	{Yax, Yrl, Z_rp, 1},
-	{Yrl, Yax, Zrp_, 1},
-	{Yrl, Yml, Zr_m, 1},
-	{Yml, Yrl, Zm_r, 1},
+	{Yax, Ynone, Yrl, Z_rp, 1},
+	{Yrl, Ynone, Yax, Zrp_, 1},
+	{Yrl, Ynone, Yml, Zr_m, 1},
+	{Yml, Ynone, Yrl, Zm_r, 1},
 }
 
 var ydivl = []ytab{
-	{Yml, Ynone, Zm_o, 2},
+	{Yml, Ynone, Ynone, Zm_o, 2},
 }
 
 var ydivb = []ytab{
-	{Ymb, Ynone, Zm_o, 2},
+	{Ymb, Ynone, Ynone, Zm_o, 2},
 }
 
 var yimul = []ytab{
-	{Yml, Ynone, Zm_o, 2},
-	{Yi8, Yrl, Zib_rr, 1},
-	{Yi32, Yrl, Zil_rr, 1},
-	{Yml, Yrl, Zm_r, 2},
+	{Yml, Ynone, Ynone, Zm_o, 2},
+	{Yi8, Ynone, Yrl, Zib_rr, 1},
+	{Yi32, Ynone, Yrl, Zil_rr, 1},
+	{Yml, Ynone, Yrl, Zm_r, 2},
 }
 
 var yimul3 = []ytab{
-	{Yml, Yrl, Zibm_r, 2},
+	{Yi8, Yml, Yrl, Zibm_r, 2},
 }
 
 var ybyte = []ytab{
-	{Yi64, Ynone, Zbyte, 1},
+	{Yi64, Ynone, Ynone, Zbyte, 1},
 }
 
 var yin = []ytab{
-	{Yi32, Ynone, Zib_, 1},
-	{Ynone, Ynone, Zlit, 1},
+	{Yi32, Ynone, Ynone, Zib_, 1},
+	{Ynone, Ynone, Ynone, Zlit, 1},
 }
 
 var yint = []ytab{
-	{Yi32, Ynone, Zib_, 1},
+	{Yi32, Ynone, Ynone, Zib_, 1},
 }
 
 var ypushl = []ytab{
-	{Yrl, Ynone, Zrp_, 1},
-	{Ym, Ynone, Zm_o, 2},
-	{Yi8, Ynone, Zib_, 1},
-	{Yi32, Ynone, Zil_, 1},
+	{Yrl, Ynone, Ynone, Zrp_, 1},
+	{Ym, Ynone, Ynone, Zm_o, 2},
+	{Yi8, Ynone, Ynone, Zib_, 1},
+	{Yi32, Ynone, Ynone, Zil_, 1},
 }
 
 var ypopl = []ytab{
-	{Ynone, Yrl, Z_rp, 1},
-	{Ynone, Ym, Zo_m, 2},
+	{Ynone, Ynone, Yrl, Z_rp, 1},
+	{Ynone, Ynone, Ym, Zo_m, 2},
 }
 
 var ybswap = []ytab{
-	{Ynone, Yrl, Z_rp, 2},
+	{Ynone, Ynone, Yrl, Z_rp, 2},
 }
 
 var yscond = []ytab{
-	{Ynone, Ymb, Zo_m, 2},
+	{Ynone, Ynone, Ymb, Zo_m, 2},
 }
 
 var yjcond = []ytab{
-	{Ynone, Ybr, Zbr, 0},
-	{Yi0, Ybr, Zbr, 0},
-	{Yi1, Ybr, Zbr, 1},
+	{Ynone, Ynone, Ybr, Zbr, 0},
+	{Yi0, Ynone, Ybr, Zbr, 0},
+	{Yi1, Ynone, Ybr, Zbr, 1},
 }
 
 var yloop = []ytab{
-	{Ynone, Ybr, Zloop, 1},
+	{Ynone, Ynone, Ybr, Zloop, 1},
 }
 
 var ycall = []ytab{
-	{Ynone, Yml, Zcallindreg, 0},
-	{Yrx, Yrx, Zcallindreg, 2},
-	{Ynone, Ybr, Zcall, 1},
+	{Ynone, Ynone, Yml, Zcallindreg, 0},
+	{Yrx, Ynone, Yrx, Zcallindreg, 2},
+	{Ynone, Ynone, Yindir, Zcallind, 2},
+	{Ynone, Ynone, Ybr, Zcall, 0},
+	{Ynone, Ynone, Yi32, Zcallcon, 1},
 }
 
 var yduff = []ytab{
-	{Ynone, Yi32, Zcall, 1},
+	{Ynone, Ynone, Yi32, Zcallduff, 1},
 }
 
 var yjmp = []ytab{
-	{Ynone, Yml, Zo_m64, 2},
-	{Ynone, Ybr, Zjmp, 1},
+	{Ynone, Ynone, Yml, Zo_m64, 2},
+	{Ynone, Ynone, Ybr, Zjmp, 0},
+	{Ynone, Ynone, Yi32, Zjmpcon, 1},
 }
 
 var yfmvd = []ytab{
-	{Ym, Yf0, Zm_o, 2},
-	{Yf0, Ym, Zo_m, 2},
-	{Yrf, Yf0, Zm_o, 2},
-	{Yf0, Yrf, Zo_m, 2},
+	{Ym, Ynone, Yf0, Zm_o, 2},
+	{Yf0, Ynone, Ym, Zo_m, 2},
+	{Yrf, Ynone, Yf0, Zm_o, 2},
+	{Yf0, Ynone, Yrf, Zo_m, 2},
 }
 
 var yfmvdp = []ytab{
-	{Yf0, Ym, Zo_m, 2},
-	{Yf0, Yrf, Zo_m, 2},
+	{Yf0, Ynone, Ym, Zo_m, 2},
+	{Yf0, Ynone, Yrf, Zo_m, 2},
 }
 
 var yfmvf = []ytab{
-	{Ym, Yf0, Zm_o, 2},
-	{Yf0, Ym, Zo_m, 2},
+	{Ym, Ynone, Yf0, Zm_o, 2},
+	{Yf0, Ynone, Ym, Zo_m, 2},
 }
 
 var yfmvx = []ytab{
-	{Ym, Yf0, Zm_o, 2},
+	{Ym, Ynone, Yf0, Zm_o, 2},
 }
 
 var yfmvp = []ytab{
-	{Yf0, Ym, Zo_m, 2},
+	{Yf0, Ynone, Ym, Zo_m, 2},
+}
+
+var yfcmv = []ytab{
+	{Yrf, Ynone, Yf0, Zm_o, 2},
 }
 
 var yfadd = []ytab{
-	{Ym, Yf0, Zm_o, 2},
-	{Yrf, Yf0, Zm_o, 2},
-	{Yf0, Yrf, Zo_m, 2},
+	{Ym, Ynone, Yf0, Zm_o, 2},
+	{Yrf, Ynone, Yf0, Zm_o, 2},
+	{Yf0, Ynone, Yrf, Zo_m, 2},
 }
 
 var yfaddp = []ytab{
-	{Yf0, Yrf, Zo_m, 2},
+	{Yf0, Ynone, Yrf, Zo_m, 2},
 }
 
 var yfxch = []ytab{
-	{Yf0, Yrf, Zo_m, 2},
-	{Yrf, Yf0, Zm_o, 2},
+	{Yf0, Ynone, Yrf, Zo_m, 2},
+	{Yrf, Ynone, Yf0, Zm_o, 2},
 }
 
 var ycompp = []ytab{
-	{Yf0, Yrf, Zo_m, 2}, /* botch is really f0,f1 */
+	{Yf0, Ynone, Yrf, Zo_m, 2}, /* botch is really f0,f1 */
 }
 
 var ystsw = []ytab{
-	{Ynone, Ym, Zo_m, 2},
-	{Ynone, Yax, Zlit, 1},
+	{Ynone, Ynone, Ym, Zo_m, 2},
+	{Ynone, Ynone, Yax, Zlit, 1},
 }
 
 var ystcw = []ytab{
-	{Ynone, Ym, Zo_m, 2},
-	{Ym, Ynone, Zm_o, 2},
+	{Ynone, Ynone, Ym, Zo_m, 2},
+	{Ym, Ynone, Ynone, Zm_o, 2},
 }
 
 var ysvrs = []ytab{
-	{Ynone, Ym, Zo_m, 2},
-	{Ym, Ynone, Zm_o, 2},
+	{Ynone, Ynone, Ym, Zo_m, 2},
+	{Ym, Ynone, Ynone, Zm_o, 2},
 }
 
 var ymm = []ytab{
-	{Ymm, Ymr, Zm_r_xm, 1},
-	{Yxm, Yxr, Zm_r_xm, 2},
+	{Ymm, Ynone, Ymr, Zm_r_xm, 1},
+	{Yxm, Ynone, Yxr, Zm_r_xm, 2},
 }
 
 var yxm = []ytab{
-	{Yxm, Yxr, Zm_r_xm, 1},
+	{Yxm, Ynone, Yxr, Zm_r_xm, 1},
 }
 
 var yxcvm1 = []ytab{
-	{Yxm, Yxr, Zm_r_xm, 2},
-	{Yxm, Ymr, Zm_r_xm, 2},
+	{Yxm, Ynone, Yxr, Zm_r_xm, 2},
+	{Yxm, Ynone, Ymr, Zm_r_xm, 2},
 }
 
 var yxcvm2 = []ytab{
-	{Yxm, Yxr, Zm_r_xm, 2},
-	{Ymm, Yxr, Zm_r_xm, 2},
+	{Yxm, Ynone, Yxr, Zm_r_xm, 2},
+	{Ymm, Ynone, Yxr, Zm_r_xm, 2},
 }
 
 /*
 var yxmq = []ytab{
-	{Yxm, Yxr, Zm_r_xm, 2},
+	{Yxm, Ynone, Yxr, Zm_r_xm, 2},
 }
 */
 
 var yxr = []ytab{
-	{Yxr, Yxr, Zm_r_xm, 1},
+	{Yxr, Ynone, Yxr, Zm_r_xm, 1},
 }
 
 var yxr_ml = []ytab{
-	{Yxr, Yml, Zr_m_xm, 1},
+	{Yxr, Ynone, Yml, Zr_m_xm, 1},
 }
 
 var ymr = []ytab{
-	{Ymr, Ymr, Zm_r, 1},
+	{Ymr, Ynone, Ymr, Zm_r, 1},
 }
 
 var ymr_ml = []ytab{
-	{Ymr, Yml, Zr_m_xm, 1},
+	{Ymr, Ynone, Yml, Zr_m_xm, 1},
 }
 
 var yxcmp = []ytab{
-	{Yxm, Yxr, Zm_r_xm, 1},
+	{Yxm, Ynone, Yxr, Zm_r_xm, 1},
 }
 
 var yxcmpi = []ytab{
-	{Yxm, Yxr, Zm_r_i_xm, 2},
+	{Yxm, Yxr, Yi8, Zm_r_i_xm, 2},
 }
 
 var yxmov = []ytab{
-	{Yxm, Yxr, Zm_r_xm, 1},
-	{Yxr, Yxm, Zr_m_xm, 1},
+	{Yxm, Ynone, Yxr, Zm_r_xm, 1},
+	{Yxr, Ynone, Yxm, Zr_m_xm, 1},
 }
 
 var yxcvfl = []ytab{
-	{Yxm, Yrl, Zm_r_xm, 1},
+	{Yxm, Ynone, Yrl, Zm_r_xm, 1},
 }
 
 var yxcvlf = []ytab{
-	{Yml, Yxr, Zm_r_xm, 1},
+	{Yml, Ynone, Yxr, Zm_r_xm, 1},
 }
 
 var yxcvfq = []ytab{
-	{Yxm, Yrl, Zm_r_xm, 2},
+	{Yxm, Ynone, Yrl, Zm_r_xm, 2},
 }
 
 var yxcvqf = []ytab{
-	{Yml, Yxr, Zm_r_xm, 2},
+	{Yml, Ynone, Yxr, Zm_r_xm, 2},
 }
 
 var yps = []ytab{
-	{Ymm, Ymr, Zm_r_xm, 1},
-	{Yi8, Ymr, Zibo_m_xm, 2},
-	{Yxm, Yxr, Zm_r_xm, 2},
-	{Yi8, Yxr, Zibo_m_xm, 3},
+	{Ymm, Ynone, Ymr, Zm_r_xm, 1},
+	{Yi8, Ynone, Ymr, Zibo_m_xm, 2},
+	{Yxm, Ynone, Yxr, Zm_r_xm, 2},
+	{Yi8, Ynone, Yxr, Zibo_m_xm, 3},
 }
 
 var yxrrl = []ytab{
-	{Yxr, Yrl, Zm_r, 1},
+	{Yxr, Ynone, Yrl, Zm_r, 1},
 }
 
 var ymfp = []ytab{
-	{Ymm, Ymr, Zm_r_3d, 1},
+	{Ymm, Ynone, Ymr, Zm_r_3d, 1},
 }
 
 var ymrxr = []ytab{
-	{Ymr, Yxr, Zm_r, 1},
-	{Yxm, Yxr, Zm_r_xm, 1},
+	{Ymr, Ynone, Yxr, Zm_r, 1},
+	{Yxm, Ynone, Yxr, Zm_r_xm, 1},
 }
 
 var ymshuf = []ytab{
-	{Ymm, Ymr, Zibm_r, 2},
+	{Yi8, Ymm, Ymr, Zibm_r, 2},
 }
 
 var ymshufb = []ytab{
-	{Yxm, Yxr, Zm2_r, 2},
+	{Yxm, Ynone, Yxr, Zm2_r, 2},
 }
 
 var yxshuf = []ytab{
-	{Yxm, Yxr, Zibm_r, 2},
+	{Yu8, Yxm, Yxr, Zibm_r, 2},
 }
 
 var yextrw = []ytab{
-	{Yxr, Yrl, Zibm_r, 2},
+	{Yu8, Yxr, Yrl, Zibm_r, 2},
 }
 
 var yinsrw = []ytab{
-	{Yml, Yxr, Zibm_r, 2},
+	{Yu8, Yml, Yxr, Zibm_r, 2},
 }
 
 var yinsr = []ytab{
-	{Ymm, Yxr, Zibm_r, 3},
+	{Yu8, Ymm, Yxr, Zibm_r, 3},
 }
 
 var ypsdq = []ytab{
-	{Yi8, Yxr, Zibo_m, 2},
+	{Yi8, Ynone, Yxr, Zibo_m, 2},
 }
 
 var ymskb = []ytab{
-	{Yxr, Yrl, Zm_r_xm, 2},
-	{Ymr, Yrl, Zm_r_xm, 1},
+	{Yxr, Ynone, Yrl, Zm_r_xm, 2},
+	{Ymr, Ynone, Yrl, Zm_r_xm, 1},
 }
 
 var ycrc32l = []ytab{
-	{Yml, Yrl, Zlitm_r, 0},
+	{Yml, Ynone, Yrl, Zlitm_r, 0},
 }
 
 var yprefetch = []ytab{
-	{Ym, Ynone, Zm_o, 2},
+	{Ym, Ynone, Ynone, Zm_o, 2},
 }
 
 var yaes = []ytab{
-	{Yxm, Yxr, Zlitm_r, 2},
+	{Yxm, Ynone, Yxr, Zlitm_r, 2},
 }
 
 var yaes2 = []ytab{
-	{Yxm, Yxr, Zibm_r, 2},
+	{Yu8, Yxm, Yxr, Zibm_r, 2},
 }
 
 /*
@@ -798,7 +851,7 @@
 	Optab{ABTSW, ybtl, Pq, [23]uint8{0xba, 05, 0xab}},
 	Optab{ABTW, ybtl, Pq, [23]uint8{0xba, 04, 0xa3}},
 	Optab{ABYTE, ybyte, Px, [23]uint8{1}},
-	Optab{obj.ACALL, ycall, Px, [23]uint8{0xff, 02, 0xe8}},
+	Optab{obj.ACALL, ycall, Px, [23]uint8{0xff, 02, 0xff, 0x15, 0xe8}},
 	Optab{ACDQ, ynone, Px, [23]uint8{0x99}},
 	Optab{ACLC, ynone, Px, [23]uint8{0xf8}},
 	Optab{ACLD, ynone, Px, [23]uint8{0xfc}},
@@ -897,8 +950,8 @@
 	Optab{ADAS, ynone, P32, [23]uint8{0x2f}},
 	Optab{obj.ADATA, nil, 0, [23]uint8{}},
 	Optab{ADECB, yincb, Pb, [23]uint8{0xfe, 01}},
-	Optab{ADECL, yincl, Px, [23]uint8{0xff, 01}},
-	Optab{ADECQ, yincl, Pw, [23]uint8{0xff, 01}},
+	Optab{ADECL, yincl, Px1, [23]uint8{0x48, 0xff, 01}},
+	Optab{ADECQ, yincq, Pw, [23]uint8{0xff, 01}},
 	Optab{ADECW, yincw, Pe, [23]uint8{0xff, 01}},
 	Optab{ADIVB, ydivb, Pb, [23]uint8{0xf6, 06}},
 	Optab{ADIVL, ydivl, Px, [23]uint8{0xf7, 06}},
@@ -927,8 +980,8 @@
 	Optab{AIMUL3Q, yimul3, Pw, [23]uint8{0x6b, 00}},
 	Optab{AINB, yin, Pb, [23]uint8{0xe4, 0xec}},
 	Optab{AINCB, yincb, Pb, [23]uint8{0xfe, 00}},
-	Optab{AINCL, yincl, Px, [23]uint8{0xff, 00}},
-	Optab{AINCQ, yincl, Pw, [23]uint8{0xff, 00}},
+	Optab{AINCL, yincl, Px1, [23]uint8{0x40, 0xff, 00}},
+	Optab{AINCQ, yincq, Pw, [23]uint8{0xff, 00}},
 	Optab{AINCW, yincw, Pe, [23]uint8{0xff, 00}},
 	Optab{AINL, yin, Px, [23]uint8{0xe5, 0xed}},
 	Optab{AINSB, ynone, Pb, [23]uint8{0x6c}},
@@ -943,6 +996,7 @@
 	Optab{AJCC, yjcond, Px, [23]uint8{0x73, 0x83, 00}},
 	Optab{AJCS, yjcond, Px, [23]uint8{0x72, 0x82}},
 	Optab{AJCXZL, yloop, Px, [23]uint8{0xe3}},
+	Optab{AJCXZW, yloop, Px, [23]uint8{0xe3}},
 	Optab{AJCXZQ, yloop, Px, [23]uint8{0xe3}},
 	Optab{AJEQ, yjcond, Px, [23]uint8{0x74, 0x84}},
 	Optab{AJGE, yjcond, Px, [23]uint8{0x7d, 0x8d}},
@@ -1016,7 +1070,7 @@
 	Optab{AMOVNTPD, yxr_ml, Pe, [23]uint8{0x2b}},
 	Optab{AMOVNTPS, yxr_ml, Pm, [23]uint8{0x2b}},
 	Optab{AMOVNTQ, ymr_ml, Pm, [23]uint8{0xe7}},
-	Optab{AMOVQ, ymovq, Pw, [23]uint8{0x89, 0x8b, 0x31, 0xc7, 00, 0xb8, 0xc7, 00, 0x6f, 0x7f, 0x6e, 0x7e, Pf2, 0xd6, Pf3, 0x7e, Pe, 0xd6, Pe, 0x6e, Pe, 0x7e, 0}},
+	Optab{AMOVQ, ymovq, Pw8, [23]uint8{0x6f, 0x7f, Pf2, 0xd6, Pf3, 0x7e, Pe, 0xd6, 0x89, 0x8b, 0x31, 0xc7, 00, 0xb8, 0xc7, 00, 0x6e, 0x7e, Pe, 0x6e, Pe, 0x7e, 0}},
 	Optab{AMOVQOZX, ymrxr, Pf3, [23]uint8{0xd6, 0x7e}},
 	Optab{AMOVSB, ynone, Pb, [23]uint8{0xa4}},
 	Optab{AMOVSD, yxmov, Pf2, [23]uint8{0x10, 0x11}},
@@ -1045,7 +1099,7 @@
 	Optab{ANEGW, yscond, Pe, [23]uint8{0xf7, 03}},
 	Optab{obj.ANOP, ynop, Px, [23]uint8{0, 0}},
 	Optab{ANOTB, yscond, Pb, [23]uint8{0xf6, 02}},
-	Optab{ANOTL, yscond, Px, [23]uint8{0xf7, 02}},
+	Optab{ANOTL, yscond, Px, [23]uint8{0xf7, 02}}, // TODO(rsc): yscond is wrong here.
 	Optab{ANOTQ, yscond, Pw, [23]uint8{0xf7, 02}},
 	Optab{ANOTW, yscond, Pe, [23]uint8{0xf7, 02}},
 	Optab{AORB, yxorb, Pb, [23]uint8{0x0c, 0x80, 01, 0x08, 0x0a}},
@@ -1060,28 +1114,28 @@
 	Optab{AOUTSL, ynone, Px, [23]uint8{0x6f}},
 	Optab{AOUTSW, ynone, Pe, [23]uint8{0x6f}},
 	Optab{AOUTW, yin, Pe, [23]uint8{0xe7, 0xef}},
-	Optab{APACKSSLW, ymm, Py, [23]uint8{0x6b, Pe, 0x6b}},
-	Optab{APACKSSWB, ymm, Py, [23]uint8{0x63, Pe, 0x63}},
-	Optab{APACKUSWB, ymm, Py, [23]uint8{0x67, Pe, 0x67}},
-	Optab{APADDB, ymm, Py, [23]uint8{0xfc, Pe, 0xfc}},
-	Optab{APADDL, ymm, Py, [23]uint8{0xfe, Pe, 0xfe}},
+	Optab{APACKSSLW, ymm, Py1, [23]uint8{0x6b, Pe, 0x6b}},
+	Optab{APACKSSWB, ymm, Py1, [23]uint8{0x63, Pe, 0x63}},
+	Optab{APACKUSWB, ymm, Py1, [23]uint8{0x67, Pe, 0x67}},
+	Optab{APADDB, ymm, Py1, [23]uint8{0xfc, Pe, 0xfc}},
+	Optab{APADDL, ymm, Py1, [23]uint8{0xfe, Pe, 0xfe}},
 	Optab{APADDQ, yxm, Pe, [23]uint8{0xd4}},
-	Optab{APADDSB, ymm, Py, [23]uint8{0xec, Pe, 0xec}},
-	Optab{APADDSW, ymm, Py, [23]uint8{0xed, Pe, 0xed}},
-	Optab{APADDUSB, ymm, Py, [23]uint8{0xdc, Pe, 0xdc}},
-	Optab{APADDUSW, ymm, Py, [23]uint8{0xdd, Pe, 0xdd}},
-	Optab{APADDW, ymm, Py, [23]uint8{0xfd, Pe, 0xfd}},
-	Optab{APAND, ymm, Py, [23]uint8{0xdb, Pe, 0xdb}},
-	Optab{APANDN, ymm, Py, [23]uint8{0xdf, Pe, 0xdf}},
+	Optab{APADDSB, ymm, Py1, [23]uint8{0xec, Pe, 0xec}},
+	Optab{APADDSW, ymm, Py1, [23]uint8{0xed, Pe, 0xed}},
+	Optab{APADDUSB, ymm, Py1, [23]uint8{0xdc, Pe, 0xdc}},
+	Optab{APADDUSW, ymm, Py1, [23]uint8{0xdd, Pe, 0xdd}},
+	Optab{APADDW, ymm, Py1, [23]uint8{0xfd, Pe, 0xfd}},
+	Optab{APAND, ymm, Py1, [23]uint8{0xdb, Pe, 0xdb}},
+	Optab{APANDN, ymm, Py1, [23]uint8{0xdf, Pe, 0xdf}},
 	Optab{APAUSE, ynone, Px, [23]uint8{0xf3, 0x90}},
-	Optab{APAVGB, ymm, Py, [23]uint8{0xe0, Pe, 0xe0}},
-	Optab{APAVGW, ymm, Py, [23]uint8{0xe3, Pe, 0xe3}},
-	Optab{APCMPEQB, ymm, Py, [23]uint8{0x74, Pe, 0x74}},
-	Optab{APCMPEQL, ymm, Py, [23]uint8{0x76, Pe, 0x76}},
-	Optab{APCMPEQW, ymm, Py, [23]uint8{0x75, Pe, 0x75}},
-	Optab{APCMPGTB, ymm, Py, [23]uint8{0x64, Pe, 0x64}},
-	Optab{APCMPGTL, ymm, Py, [23]uint8{0x66, Pe, 0x66}},
-	Optab{APCMPGTW, ymm, Py, [23]uint8{0x65, Pe, 0x65}},
+	Optab{APAVGB, ymm, Py1, [23]uint8{0xe0, Pe, 0xe0}},
+	Optab{APAVGW, ymm, Py1, [23]uint8{0xe3, Pe, 0xe3}},
+	Optab{APCMPEQB, ymm, Py1, [23]uint8{0x74, Pe, 0x74}},
+	Optab{APCMPEQL, ymm, Py1, [23]uint8{0x76, Pe, 0x76}},
+	Optab{APCMPEQW, ymm, Py1, [23]uint8{0x75, Pe, 0x75}},
+	Optab{APCMPGTB, ymm, Py1, [23]uint8{0x64, Pe, 0x64}},
+	Optab{APCMPGTL, ymm, Py1, [23]uint8{0x66, Pe, 0x66}},
+	Optab{APCMPGTW, ymm, Py1, [23]uint8{0x65, Pe, 0x65}},
 	Optab{APEXTRW, yextrw, Pq, [23]uint8{0xc5, 00}},
 	Optab{APF2IL, ymfp, Px, [23]uint8{0x1d}},
 	Optab{APF2IW, ymfp, Px, [23]uint8{0x1c}},
@@ -1106,17 +1160,17 @@
 	Optab{APINSRW, yinsrw, Pq, [23]uint8{0xc4, 00}},
 	Optab{APINSRD, yinsr, Pq, [23]uint8{0x3a, 0x22, 00}},
 	Optab{APINSRQ, yinsr, Pq3, [23]uint8{0x3a, 0x22, 00}},
-	Optab{APMADDWL, ymm, Py, [23]uint8{0xf5, Pe, 0xf5}},
+	Optab{APMADDWL, ymm, Py1, [23]uint8{0xf5, Pe, 0xf5}},
 	Optab{APMAXSW, yxm, Pe, [23]uint8{0xee}},
 	Optab{APMAXUB, yxm, Pe, [23]uint8{0xde}},
 	Optab{APMINSW, yxm, Pe, [23]uint8{0xea}},
 	Optab{APMINUB, yxm, Pe, [23]uint8{0xda}},
 	Optab{APMOVMSKB, ymskb, Px, [23]uint8{Pe, 0xd7, 0xd7}},
 	Optab{APMULHRW, ymfp, Px, [23]uint8{0xb7}},
-	Optab{APMULHUW, ymm, Py, [23]uint8{0xe4, Pe, 0xe4}},
-	Optab{APMULHW, ymm, Py, [23]uint8{0xe5, Pe, 0xe5}},
-	Optab{APMULLW, ymm, Py, [23]uint8{0xd5, Pe, 0xd5}},
-	Optab{APMULULQ, ymm, Py, [23]uint8{0xf4, Pe, 0xf4}},
+	Optab{APMULHUW, ymm, Py1, [23]uint8{0xe4, Pe, 0xe4}},
+	Optab{APMULHW, ymm, Py1, [23]uint8{0xe5, Pe, 0xe5}},
+	Optab{APMULLW, ymm, Py1, [23]uint8{0xd5, Pe, 0xd5}},
+	Optab{APMULULQ, ymm, Py1, [23]uint8{0xf4, Pe, 0xf4}},
 	Optab{APOPAL, ynone, P32, [23]uint8{0x61}},
 	Optab{APOPAW, ynone, Pe, [23]uint8{0x61}},
 	Optab{APOPFL, ynone, P32, [23]uint8{0x9d}},
@@ -1125,7 +1179,7 @@
 	Optab{APOPL, ypopl, P32, [23]uint8{0x58, 0x8f, 00}},
 	Optab{APOPQ, ypopl, Py, [23]uint8{0x58, 0x8f, 00}},
 	Optab{APOPW, ypopl, Pe, [23]uint8{0x58, 0x8f, 00}},
-	Optab{APOR, ymm, Py, [23]uint8{0xeb, Pe, 0xeb}},
+	Optab{APOR, ymm, Py1, [23]uint8{0xeb, Pe, 0xeb}},
 	Optab{APSADBW, yxm, Pq, [23]uint8{0xf6}},
 	Optab{APSHUFHW, yxshuf, Pf3, [23]uint8{0x70, 00}},
 	Optab{APSHUFL, yxshuf, Pq, [23]uint8{0x70, 00}},
@@ -1133,15 +1187,15 @@
 	Optab{APSHUFW, ymshuf, Pm, [23]uint8{0x70, 00}},
 	Optab{APSHUFB, ymshufb, Pq, [23]uint8{0x38, 0x00}},
 	Optab{APSLLO, ypsdq, Pq, [23]uint8{0x73, 07}},
-	Optab{APSLLL, yps, Py, [23]uint8{0xf2, 0x72, 06, Pe, 0xf2, Pe, 0x72, 06}},
-	Optab{APSLLQ, yps, Py, [23]uint8{0xf3, 0x73, 06, Pe, 0xf3, Pe, 0x73, 06}},
-	Optab{APSLLW, yps, Py, [23]uint8{0xf1, 0x71, 06, Pe, 0xf1, Pe, 0x71, 06}},
-	Optab{APSRAL, yps, Py, [23]uint8{0xe2, 0x72, 04, Pe, 0xe2, Pe, 0x72, 04}},
-	Optab{APSRAW, yps, Py, [23]uint8{0xe1, 0x71, 04, Pe, 0xe1, Pe, 0x71, 04}},
+	Optab{APSLLL, yps, Py3, [23]uint8{0xf2, 0x72, 06, Pe, 0xf2, Pe, 0x72, 06}},
+	Optab{APSLLQ, yps, Py3, [23]uint8{0xf3, 0x73, 06, Pe, 0xf3, Pe, 0x73, 06}},
+	Optab{APSLLW, yps, Py3, [23]uint8{0xf1, 0x71, 06, Pe, 0xf1, Pe, 0x71, 06}},
+	Optab{APSRAL, yps, Py3, [23]uint8{0xe2, 0x72, 04, Pe, 0xe2, Pe, 0x72, 04}},
+	Optab{APSRAW, yps, Py3, [23]uint8{0xe1, 0x71, 04, Pe, 0xe1, Pe, 0x71, 04}},
 	Optab{APSRLO, ypsdq, Pq, [23]uint8{0x73, 03}},
-	Optab{APSRLL, yps, Py, [23]uint8{0xd2, 0x72, 02, Pe, 0xd2, Pe, 0x72, 02}},
-	Optab{APSRLQ, yps, Py, [23]uint8{0xd3, 0x73, 02, Pe, 0xd3, Pe, 0x73, 02}},
-	Optab{APSRLW, yps, Py, [23]uint8{0xd1, 0x71, 02, Pe, 0xe1, Pe, 0x71, 02}},
+	Optab{APSRLL, yps, Py3, [23]uint8{0xd2, 0x72, 02, Pe, 0xd2, Pe, 0x72, 02}},
+	Optab{APSRLQ, yps, Py3, [23]uint8{0xd3, 0x73, 02, Pe, 0xd3, Pe, 0x73, 02}},
+	Optab{APSRLW, yps, Py3, [23]uint8{0xd1, 0x71, 02, Pe, 0xe1, Pe, 0x71, 02}},
 	Optab{APSUBB, yxm, Pe, [23]uint8{0xf8}},
 	Optab{APSUBL, yxm, Pe, [23]uint8{0xfa}},
 	Optab{APSUBQ, yxm, Pe, [23]uint8{0xfb}},
@@ -1151,14 +1205,14 @@
 	Optab{APSUBUSW, yxm, Pe, [23]uint8{0xd9}},
 	Optab{APSUBW, yxm, Pe, [23]uint8{0xf9}},
 	Optab{APSWAPL, ymfp, Px, [23]uint8{0xbb}},
-	Optab{APUNPCKHBW, ymm, Py, [23]uint8{0x68, Pe, 0x68}},
-	Optab{APUNPCKHLQ, ymm, Py, [23]uint8{0x6a, Pe, 0x6a}},
+	Optab{APUNPCKHBW, ymm, Py1, [23]uint8{0x68, Pe, 0x68}},
+	Optab{APUNPCKHLQ, ymm, Py1, [23]uint8{0x6a, Pe, 0x6a}},
 	Optab{APUNPCKHQDQ, yxm, Pe, [23]uint8{0x6d}},
-	Optab{APUNPCKHWL, ymm, Py, [23]uint8{0x69, Pe, 0x69}},
-	Optab{APUNPCKLBW, ymm, Py, [23]uint8{0x60, Pe, 0x60}},
-	Optab{APUNPCKLLQ, ymm, Py, [23]uint8{0x62, Pe, 0x62}},
+	Optab{APUNPCKHWL, ymm, Py1, [23]uint8{0x69, Pe, 0x69}},
+	Optab{APUNPCKLBW, ymm, Py1, [23]uint8{0x60, Pe, 0x60}},
+	Optab{APUNPCKLLQ, ymm, Py1, [23]uint8{0x62, Pe, 0x62}},
 	Optab{APUNPCKLQDQ, yxm, Pe, [23]uint8{0x6c}},
-	Optab{APUNPCKLWL, ymm, Py, [23]uint8{0x61, Pe, 0x61}},
+	Optab{APUNPCKLWL, ymm, Py1, [23]uint8{0x61, Pe, 0x61}},
 	Optab{APUSHAL, ynone, P32, [23]uint8{0x60}},
 	Optab{APUSHAW, ynone, Pe, [23]uint8{0x60}},
 	Optab{APUSHFL, ynone, P32, [23]uint8{0x9c}},
@@ -1167,7 +1221,7 @@
 	Optab{APUSHL, ypushl, P32, [23]uint8{0x50, 0xff, 06, 0x6a, 0x68}},
 	Optab{APUSHQ, ypushl, Py, [23]uint8{0x50, 0xff, 06, 0x6a, 0x68}},
 	Optab{APUSHW, ypushl, Pe, [23]uint8{0x50, 0xff, 06, 0x6a, 0x68}},
-	Optab{APXOR, ymm, Py, [23]uint8{0xef, Pe, 0xef}},
+	Optab{APXOR, ymm, Py1, [23]uint8{0xef, Pe, 0xef}},
 	Optab{AQUAD, ybyte, Px, [23]uint8{8}},
 	Optab{ARCLB, yshb, Pb, [23]uint8{0xd0, 02, 0xc0, 02, 0xd2, 02}},
 	Optab{ARCLL, yshl, Px, [23]uint8{0xd1, 02, 0xc1, 02, 0xd3, 02, 0xd3, 02}},
@@ -1195,7 +1249,7 @@
 	Optab{ARORW, yshl, Pe, [23]uint8{0xd1, 01, 0xc1, 01, 0xd3, 01, 0xd3, 01}},
 	Optab{ARSQRTPS, yxm, Pm, [23]uint8{0x52}},
 	Optab{ARSQRTSS, yxm, Pf3, [23]uint8{0x52}},
-	Optab{ASAHF, ynone, Px, [23]uint8{0x86, 0xe0, 0x50, 0x9d}}, /* XCHGB AH,AL; PUSH AX; POPFL */
+	Optab{ASAHF, ynone, Px1, [23]uint8{0x9e, 00, 0x86, 0xe0, 0x50, 0x9d}}, /* XCHGB AH,AL; PUSH AX; POPFL */
 	Optab{ASALB, yshb, Pb, [23]uint8{0xd0, 04, 0xc0, 04, 0xd2, 04}},
 	Optab{ASALL, yshl, Px, [23]uint8{0xd1, 04, 0xc1, 04, 0xd3, 04, 0xd3, 04}},
 	Optab{ASALQ, yshl, Pw, [23]uint8{0xd1, 04, 0xc1, 04, 0xd3, 04, 0xd3, 04}},
@@ -1300,6 +1354,14 @@
 	Optab{AFMOVWP, yfmvp, Px, [23]uint8{0xdf, 03}},
 	Optab{AFMOVX, yfmvx, Px, [23]uint8{0xdb, 05}},
 	Optab{AFMOVXP, yfmvp, Px, [23]uint8{0xdb, 07}},
+	Optab{AFCMOVCC, yfcmv, Px, [23]uint8{0xdb, 00}},
+	Optab{AFCMOVCS, yfcmv, Px, [23]uint8{0xda, 00}},
+	Optab{AFCMOVEQ, yfcmv, Px, [23]uint8{0xda, 01}},
+	Optab{AFCMOVHI, yfcmv, Px, [23]uint8{0xdb, 02}},
+	Optab{AFCMOVLS, yfcmv, Px, [23]uint8{0xda, 02}},
+	Optab{AFCMOVNE, yfcmv, Px, [23]uint8{0xdb, 01}},
+	Optab{AFCMOVNU, yfcmv, Px, [23]uint8{0xdb, 03}},
+	Optab{AFCMOVUN, yfcmv, Px, [23]uint8{0xda, 03}},
 	Optab{AFCOMB, nil, 0, [23]uint8{}},
 	Optab{AFCOMBP, nil, 0, [23]uint8{}},
 	Optab{AFCOMD, yfadd, Px, [23]uint8{0xdc, 02, 0xd8, 02, 0xdc, 02}},  /* botch */
@@ -1307,11 +1369,15 @@
 	Optab{AFCOMDPP, ycompp, Px, [23]uint8{0xde, 03}},
 	Optab{AFCOMF, yfmvx, Px, [23]uint8{0xd8, 02}},
 	Optab{AFCOMFP, yfmvx, Px, [23]uint8{0xd8, 03}},
+	Optab{AFCOMI, yfmvx, Px, [23]uint8{0xdb, 06}},
+	Optab{AFCOMIP, yfmvx, Px, [23]uint8{0xdf, 06}},
 	Optab{AFCOML, yfmvx, Px, [23]uint8{0xda, 02}},
 	Optab{AFCOMLP, yfmvx, Px, [23]uint8{0xda, 03}},
 	Optab{AFCOMW, yfmvx, Px, [23]uint8{0xde, 02}},
 	Optab{AFCOMWP, yfmvx, Px, [23]uint8{0xde, 03}},
 	Optab{AFUCOM, ycompp, Px, [23]uint8{0xdd, 04}},
+	Optab{AFUCOMI, ycompp, Px, [23]uint8{0xdb, 05}},
+	Optab{AFUCOMIP, ycompp, Px, [23]uint8{0xdf, 05}},
 	Optab{AFUCOMP, ycompp, Px, [23]uint8{0xdd, 05}},
 	Optab{AFUCOMPP, ycompp, Px, [23]uint8{0xda, 13}},
 	Optab{AFADDDP, yfaddp, Px, [23]uint8{0xde, 00}},
@@ -1420,7 +1486,7 @@
 	Optab{AAESDECLAST, yaes, Pq, [23]uint8{0x38, 0xdf, 0}},
 	Optab{AAESIMC, yaes, Pq, [23]uint8{0x38, 0xdb, 0}},
 	Optab{AAESKEYGENASSIST, yaes2, Pq, [23]uint8{0x3a, 0xdf, 0}},
-	Optab{APSHUFD, yaes2, Pq, [23]uint8{0x70, 0}},
+	Optab{APSHUFD, yxshuf, Pq, [23]uint8{0x70, 0}},
 	Optab{APCLMULQDQ, yxshuf, Pq, [23]uint8{0x3a, 0x44, 0}},
 	Optab{obj.AUSEFIELD, ynop, Px, [23]uint8{0, 0}},
 	Optab{obj.ATYPE, nil, 0, [23]uint8{}},
@@ -1435,7 +1501,7 @@
 	Optab{0, nil, 0, [23]uint8{}},
 }
 
-var opindex [ALAST + 1]*Optab
+var opindex [(ALAST + 1) & obj.AMask]*Optab
 
 // isextern reports whether s describes an external symbol that must avoid pc-relative addressing.
 // This happens on systems like Solaris that call .so functions instead of system calls.
@@ -1492,16 +1558,6 @@
 }
 
 func span6(ctxt *obj.Link, s *obj.LSym) {
-	var p *obj.Prog
-	var q *obj.Prog
-	var c int32
-	var v int32
-	var loop int32
-	var bp []byte
-	var n int
-	var m int
-	var i int
-
 	ctxt.Cursym = s
 
 	if s.P != nil {
@@ -1512,7 +1568,8 @@
 		instinit()
 	}
 
-	for p = ctxt.Cursym.Text; p != nil; p = p.Link {
+	var v int32
+	for p := ctxt.Cursym.Text; p != nil; p = p.Link {
 		if p.To.Type == obj.TYPE_BRANCH {
 			if p.Pcond == nil {
 				p.Pcond = p
@@ -1536,7 +1593,8 @@
 		}
 	}
 
-	for p = s.Text; p != nil; p = p.Link {
+	var q *obj.Prog
+	for p := s.Text; p != nil; p = p.Link {
 		p.Back = 2 // use short branches first time through
 		q = p.Pcond
 		if q != nil && (q.Back&2 != 0) {
@@ -1562,7 +1620,13 @@
 		}
 	}
 
-	n = 0
+	n := 0
+	var bp []byte
+	var c int32
+	var i int
+	var loop int32
+	var m int
+	var p *obj.Prog
 	for {
 		loop = 0
 		for i = 0; i < len(s.R); i++ {
@@ -1686,6 +1750,7 @@
 
 	if false { /* debug['a'] > 1 */
 		fmt.Printf("span1 %s %d (%d tries)\n %.6x", s.Name, s.Size, n, 0)
+		var i int
 		for i = 0; i < len(s.P); i++ {
 			fmt.Printf(" %.2x", s.P[i])
 			if i%16 == 15 {
@@ -1697,10 +1762,8 @@
 			fmt.Printf("\n")
 		}
 
-		for i = 0; i < len(s.R); i++ {
-			var r *obj.Reloc
-
-			r = &s.R[i]
+		for i := 0; i < len(s.R); i++ {
+			r := &s.R[i]
 			fmt.Printf(" rel %#.4x/%d %s%+d\n", uint32(r.Off), r.Siz, r.Sym.Name, r.Add)
 		}
 	}
@@ -1708,34 +1771,47 @@
 
 func instinit() {
 	var c int
-	var i int
 
-	for i = 1; optab[i].as != 0; i++ {
+	for i := 1; optab[i].as != 0; i++ {
 		c = int(optab[i].as)
-		if opindex[c] != nil {
-			log.Fatalf("phase error in optab: %d (%v)", i, Aconv(c))
+		if opindex[c&obj.AMask] != nil {
+			log.Fatalf("phase error in optab: %d (%v)", i, obj.Aconv(c))
 		}
-		opindex[c] = &optab[i]
+		opindex[c&obj.AMask] = &optab[i]
 	}
 
-	for i = 0; i < Ymax; i++ {
+	for i := 0; i < Ymax; i++ {
 		ycover[i*Ymax+i] = 1
 	}
 
 	ycover[Yi0*Ymax+Yi8] = 1
 	ycover[Yi1*Ymax+Yi8] = 1
+	ycover[Yu7*Ymax+Yi8] = 1
+
+	ycover[Yi0*Ymax+Yu7] = 1
+	ycover[Yi1*Ymax+Yu7] = 1
+
+	ycover[Yi0*Ymax+Yu8] = 1
+	ycover[Yi1*Ymax+Yu8] = 1
+	ycover[Yu7*Ymax+Yu8] = 1
 
 	ycover[Yi0*Ymax+Ys32] = 1
 	ycover[Yi1*Ymax+Ys32] = 1
+	ycover[Yu7*Ymax+Ys32] = 1
+	ycover[Yu8*Ymax+Ys32] = 1
 	ycover[Yi8*Ymax+Ys32] = 1
 
 	ycover[Yi0*Ymax+Yi32] = 1
 	ycover[Yi1*Ymax+Yi32] = 1
+	ycover[Yu7*Ymax+Yi32] = 1
+	ycover[Yu8*Ymax+Yi32] = 1
 	ycover[Yi8*Ymax+Yi32] = 1
 	ycover[Ys32*Ymax+Yi32] = 1
 
 	ycover[Yi0*Ymax+Yi64] = 1
 	ycover[Yi1*Ymax+Yi64] = 1
+	ycover[Yu7*Ymax+Yi64] = 1
+	ycover[Yu8*Ymax+Yi64] = 1
 	ycover[Yi8*Ymax+Yi64] = 1
 	ycover[Ys32*Ymax+Yi64] = 1
 	ycover[Yi32*Ymax+Yi64] = 1
@@ -1745,7 +1821,7 @@
 	ycover[Yax*Ymax+Yrb] = 1
 	ycover[Ycx*Ymax+Yrb] = 1
 	ycover[Yrx*Ymax+Yrb] = 1
-	ycover[Yrl*Ymax+Yrb] = 1
+	ycover[Yrl*Ymax+Yrb] = 1 // but not Yrl32
 
 	ycover[Ycl*Ymax+Ycx] = 1
 
@@ -1755,6 +1831,7 @@
 	ycover[Yax*Ymax+Yrl] = 1
 	ycover[Ycx*Ymax+Yrl] = 1
 	ycover[Yrx*Ymax+Yrl] = 1
+	ycover[Yrl32*Ymax+Yrl] = 1
 
 	ycover[Yf0*Ymax+Yrf] = 1
 
@@ -1764,26 +1841,28 @@
 	ycover[Ycx*Ymax+Ymb] = 1
 	ycover[Yrx*Ymax+Ymb] = 1
 	ycover[Yrb*Ymax+Ymb] = 1
-	ycover[Yrl*Ymax+Ymb] = 1
+	ycover[Yrl*Ymax+Ymb] = 1 // but not Yrl32
 	ycover[Ym*Ymax+Ymb] = 1
 
 	ycover[Yax*Ymax+Yml] = 1
 	ycover[Ycx*Ymax+Yml] = 1
 	ycover[Yrx*Ymax+Yml] = 1
 	ycover[Yrl*Ymax+Yml] = 1
+	ycover[Yrl32*Ymax+Yml] = 1
 	ycover[Ym*Ymax+Yml] = 1
 
 	ycover[Yax*Ymax+Ymm] = 1
 	ycover[Ycx*Ymax+Ymm] = 1
 	ycover[Yrx*Ymax+Ymm] = 1
 	ycover[Yrl*Ymax+Ymm] = 1
+	ycover[Yrl32*Ymax+Ymm] = 1
 	ycover[Ym*Ymax+Ymm] = 1
 	ycover[Ymr*Ymax+Ymm] = 1
 
 	ycover[Ym*Ymax+Yxm] = 1
 	ycover[Yxr*Ymax+Yxm] = 1
 
-	for i = 0; i < MAXREG; i++ {
+	for i := 0; i < MAXREG; i++ {
 		reg[i] = -1
 		if i >= REG_AL && i <= REG_R15B {
 			reg[i] = (i - REG_AL) & 7
@@ -1824,7 +1903,10 @@
 	}
 }
 
-func prefixof(ctxt *obj.Link, a *obj.Addr) int {
+func prefixof(ctxt *obj.Link, p *obj.Prog, a *obj.Addr) int {
+	if a.Reg < REG_CS && a.Index < REG_CS { // fast path
+		return 0
+	}
 	if a.Type == obj.TYPE_MEM && a.Name == obj.NAME_NONE {
 		switch a.Reg {
 		case REG_CS:
@@ -1842,20 +1924,40 @@
 		case REG_GS:
 			return 0x65
 
-			// NOTE: Systems listed here should be only systems that
-		// support direct TLS references like 8(TLS) implemented as
-		// direct references from FS or GS. Systems that require
-		// the initial-exec model, where you load the TLS base into
-		// a register and then index from that register, do not reach
-		// this code and should not be listed.
 		case REG_TLS:
+			// NOTE: Systems listed here should be only systems that
+			// support direct TLS references like 8(TLS) implemented as
+			// direct references from FS or GS. Systems that require
+			// the initial-exec model, where you load the TLS base into
+			// a register and then index from that register, do not reach
+			// this code and should not be listed.
+			if p.Mode == 32 {
+				switch ctxt.Headtype {
+				default:
+					log.Fatalf("unknown TLS base register for %s", obj.Headstr(ctxt.Headtype))
+
+				case obj.Hdarwin,
+					obj.Hdragonfly,
+					obj.Hfreebsd,
+					obj.Hnetbsd,
+					obj.Hopenbsd:
+					return 0x65 // GS
+				}
+			}
+
 			switch ctxt.Headtype {
 			default:
 				log.Fatalf("unknown TLS base register for %s", obj.Headstr(ctxt.Headtype))
 
+			case obj.Hlinux:
+				if ctxt.Flag_shared != 0 {
+					log.Fatalf("unknown TLS base register for linux with -shared")
+				} else {
+					return 0x64 // FS
+				}
+
 			case obj.Hdragonfly,
 				obj.Hfreebsd,
-				obj.Hlinux,
 				obj.Hnetbsd,
 				obj.Hopenbsd,
 				obj.Hsolaris:
@@ -1867,6 +1969,10 @@
 		}
 	}
 
+	if p.Mode == 32 {
+		return 0
+	}
+
 	switch a.Index {
 	case REG_CS:
 		return 0x2e
@@ -1877,6 +1983,21 @@
 	case REG_ES:
 		return 0x26
 
+	case REG_TLS:
+		if ctxt.Flag_shared != 0 {
+			// When building for inclusion into a shared library, an instruction of the form
+			//     MOV 0(CX)(TLS*1), AX
+			// becomes
+			//     mov %fs:(%rcx), %rax
+			// which assumes that the correct TLS offset has been loaded into %rcx (today
+			// there is only one TLS variable -- g -- so this is OK). When not building for
+			// a shared library the instruction does not require a prefix.
+			if a.Offset != 0 {
+				log.Fatalf("cannot handle non-0 offsets to TLS")
+			}
+			return 0x64
+		}
+
 	case REG_FS:
 		return 0x64
 
@@ -1888,17 +2009,6 @@
 }
 
 func oclass(ctxt *obj.Link, p *obj.Prog, a *obj.Addr) int {
-	var v int64
-	var l int32
-
-	// TODO(rsc): This special case is for SHRQ $3, AX:DX,
-	// which encodes as SHRQ $32(DX*0), AX.
-	// Similarly SHRQ CX, AX:DX is really SHRQ CX(DX*0), AX.
-	// Change encoding and remove.
-	if (a.Type == obj.TYPE_CONST || a.Type == obj.TYPE_REG) && a.Index != REG_NONE && a.Scale == 0 {
-		return Ycol
-	}
-
 	switch a.Type {
 	case obj.TYPE_NONE:
 		return Ynone
@@ -1906,6 +2016,12 @@
 	case obj.TYPE_BRANCH:
 		return Ybr
 
+	case obj.TYPE_INDIR:
+		if a.Name != obj.NAME_NONE && a.Reg == REG_NONE && a.Index == REG_NONE && a.Scale == 0 {
+			return Yindir
+		}
+		return Yxxx
+
 	case obj.TYPE_MEM:
 		return Ym
 
@@ -1913,7 +2029,7 @@
 		switch a.Name {
 		case obj.NAME_EXTERN,
 			obj.NAME_STATIC:
-			if a.Sym != nil && isextern(a.Sym) {
+			if a.Sym != nil && isextern(a.Sym) || p.Mode == 32 {
 				return Yi32
 			}
 			return Yiauto // use pc-relative addressing
@@ -1942,17 +2058,29 @@
 			ctxt.Diag("TYPE_CONST with symbol: %v", obj.Dconv(p, a))
 		}
 
-		v = a.Offset
+		v := a.Offset
+		if p.Mode == 32 {
+			v = int64(int32(v))
+		}
 		if v == 0 {
 			return Yi0
 		}
 		if v == 1 {
 			return Yi1
 		}
+		if v >= 0 && v <= 127 {
+			return Yu7
+		}
+		if v >= 0 && v <= 255 {
+			return Yu8
+		}
 		if v >= -128 && v <= 127 {
 			return Yi8
 		}
-		l = int32(v)
+		if p.Mode == 32 {
+			return Yi32
+		}
+		l := int32(v)
 		if int64(l) == v {
 			return Ys32 /* can sign extend */
 		}
@@ -2010,8 +2138,7 @@
 	case REG_CX:
 		return Ycx
 
-	case REG_DX,
-		REG_BX:
+	case REG_DX, REG_BX:
 		return Yrx
 
 	case REG_R8, /* not really Yrl */
@@ -2027,10 +2154,10 @@
 		}
 		fallthrough
 
-	case REG_SP,
-		REG_BP,
-		REG_SI,
-		REG_DI:
+	case REG_SP, REG_BP, REG_SI, REG_DI:
+		if p.Mode == 32 {
+			return Yrl32
+		}
 		return Yrl
 
 	case REG_F0 + 0:
@@ -2259,16 +2386,14 @@
 }
 
 func relput4(ctxt *obj.Link, p *obj.Prog, a *obj.Addr) {
-	var v int64
 	var rel obj.Reloc
-	var r *obj.Reloc
 
-	v = vaddr(ctxt, p, a, &rel)
+	v := vaddr(ctxt, p, a, &rel)
 	if rel.Siz != 0 {
 		if rel.Siz != 4 {
 			ctxt.Diag("bad reloc")
 		}
-		r = obj.Addrel(ctxt.Cursym)
+		r := obj.Addrel(ctxt.Cursym)
 		*r = rel
 		r.Off = int32(p.Pc + int64(-cap(ctxt.Andptr)+cap(ctxt.And[:])))
 	}
@@ -2306,8 +2431,6 @@
 }
 */
 func vaddr(ctxt *obj.Link, p *obj.Prog, a *obj.Addr, r *obj.Reloc) int64 {
-	var s *obj.LSym
-
 	if r != nil {
 		*r = obj.Reloc{}
 	}
@@ -2315,13 +2438,13 @@
 	switch a.Name {
 	case obj.NAME_STATIC,
 		obj.NAME_EXTERN:
-		s = a.Sym
+		s := a.Sym
 		if r == nil {
 			ctxt.Diag("need reloc for %v", obj.Dconv(p, a))
 			log.Fatalf("reloc")
 		}
 
-		if isextern(s) {
+		if isextern(s) || p.Mode != 64 {
 			r.Siz = 4
 			r.Type = obj.R_ADDR
 		} else {
@@ -2358,12 +2481,11 @@
 }
 
 func asmandsz(ctxt *obj.Link, p *obj.Prog, a *obj.Addr, r int, rex int, m64 int) {
-	var v int32
 	var base int
 	var rel obj.Reloc
 
 	rex &= 0x40 | Rxr
-	v = int32(a.Offset)
+	v := int32(a.Offset)
 	rel.Siz = 0
 
 	switch a.Type {
@@ -2394,11 +2516,11 @@
 	}
 
 	if a.Index != REG_NONE && a.Index != REG_TLS {
-		base = int(a.Reg)
+		base := int(a.Reg)
 		switch a.Name {
 		case obj.NAME_EXTERN,
 			obj.NAME_STATIC:
-			if !isextern(a.Sym) {
+			if !isextern(a.Sym) && p.Mode == 64 {
 				goto bad
 			}
 			base = REG_NONE
@@ -2460,7 +2582,7 @@
 
 	ctxt.Rexflag |= regrex[base]&Rxb | rex
 	if base == REG_NONE || (REG_CS <= base && base <= REG_GS) || base == REG_TLS {
-		if (a.Sym == nil || !isextern(a.Sym)) && base == REG_NONE && (a.Name == obj.NAME_STATIC || a.Name == obj.NAME_EXTERN) || ctxt.Asmode != 64 {
+		if (a.Sym == nil || !isextern(a.Sym)) && base == REG_NONE && (a.Name == obj.NAME_STATIC || a.Name == obj.NAME_EXTERN) || p.Mode != 64 {
 			ctxt.Andptr[0] = byte(0<<6 | 5<<0 | r<<3)
 			ctxt.Andptr = ctxt.Andptr[1:]
 			goto putrelv
@@ -2498,7 +2620,7 @@
 	}
 
 	if REG_AX <= base && base <= REG_R15 {
-		if a.Index == REG_TLS {
+		if a.Index == REG_TLS && ctxt.Flag_shared == 0 {
 			rel = obj.Reloc{}
 			rel.Type = obj.R_TLS_IE
 			rel.Siz = 4
@@ -2529,14 +2651,12 @@
 
 putrelv:
 	if rel.Siz != 0 {
-		var r *obj.Reloc
-
 		if rel.Siz != 4 {
 			ctxt.Diag("bad rel")
 			goto bad
 		}
 
-		r = obj.Addrel(ctxt.Cursym)
+		r := obj.Addrel(ctxt.Cursym)
 		*r = rel
 		r.Off = int32(ctxt.Curp.Pc + int64(-cap(ctxt.Andptr)+cap(ctxt.And[:])))
 	}
@@ -2564,141 +2684,160 @@
 	}
 }
 
+func unbytereg(a *obj.Addr, t *uint8) {
+	if a.Type == obj.TYPE_REG && a.Index == REG_NONE && (REG_AL <= a.Reg && a.Reg <= REG_R15B) {
+		a.Reg += REG_AX - REG_AL
+		*t = 0
+	}
+}
+
 const (
 	E = 0xff
 )
 
 var ymovtab = []Movtab{
 	/* push */
-	Movtab{APUSHL, Ycs, Ynone, 0, [4]uint8{0x0e, E, 0, 0}},
-	Movtab{APUSHL, Yss, Ynone, 0, [4]uint8{0x16, E, 0, 0}},
-	Movtab{APUSHL, Yds, Ynone, 0, [4]uint8{0x1e, E, 0, 0}},
-	Movtab{APUSHL, Yes, Ynone, 0, [4]uint8{0x06, E, 0, 0}},
-	Movtab{APUSHL, Yfs, Ynone, 0, [4]uint8{0x0f, 0xa0, E, 0}},
-	Movtab{APUSHL, Ygs, Ynone, 0, [4]uint8{0x0f, 0xa8, E, 0}},
-	Movtab{APUSHQ, Yfs, Ynone, 0, [4]uint8{0x0f, 0xa0, E, 0}},
-	Movtab{APUSHQ, Ygs, Ynone, 0, [4]uint8{0x0f, 0xa8, E, 0}},
-	Movtab{APUSHW, Ycs, Ynone, 0, [4]uint8{Pe, 0x0e, E, 0}},
-	Movtab{APUSHW, Yss, Ynone, 0, [4]uint8{Pe, 0x16, E, 0}},
-	Movtab{APUSHW, Yds, Ynone, 0, [4]uint8{Pe, 0x1e, E, 0}},
-	Movtab{APUSHW, Yes, Ynone, 0, [4]uint8{Pe, 0x06, E, 0}},
-	Movtab{APUSHW, Yfs, Ynone, 0, [4]uint8{Pe, 0x0f, 0xa0, E}},
-	Movtab{APUSHW, Ygs, Ynone, 0, [4]uint8{Pe, 0x0f, 0xa8, E}},
+	Movtab{APUSHL, Ycs, Ynone, Ynone, 0, [4]uint8{0x0e, E, 0, 0}},
+	Movtab{APUSHL, Yss, Ynone, Ynone, 0, [4]uint8{0x16, E, 0, 0}},
+	Movtab{APUSHL, Yds, Ynone, Ynone, 0, [4]uint8{0x1e, E, 0, 0}},
+	Movtab{APUSHL, Yes, Ynone, Ynone, 0, [4]uint8{0x06, E, 0, 0}},
+	Movtab{APUSHL, Yfs, Ynone, Ynone, 0, [4]uint8{0x0f, 0xa0, E, 0}},
+	Movtab{APUSHL, Ygs, Ynone, Ynone, 0, [4]uint8{0x0f, 0xa8, E, 0}},
+	Movtab{APUSHQ, Yfs, Ynone, Ynone, 0, [4]uint8{0x0f, 0xa0, E, 0}},
+	Movtab{APUSHQ, Ygs, Ynone, Ynone, 0, [4]uint8{0x0f, 0xa8, E, 0}},
+	Movtab{APUSHW, Ycs, Ynone, Ynone, 0, [4]uint8{Pe, 0x0e, E, 0}},
+	Movtab{APUSHW, Yss, Ynone, Ynone, 0, [4]uint8{Pe, 0x16, E, 0}},
+	Movtab{APUSHW, Yds, Ynone, Ynone, 0, [4]uint8{Pe, 0x1e, E, 0}},
+	Movtab{APUSHW, Yes, Ynone, Ynone, 0, [4]uint8{Pe, 0x06, E, 0}},
+	Movtab{APUSHW, Yfs, Ynone, Ynone, 0, [4]uint8{Pe, 0x0f, 0xa0, E}},
+	Movtab{APUSHW, Ygs, Ynone, Ynone, 0, [4]uint8{Pe, 0x0f, 0xa8, E}},
 
 	/* pop */
-	Movtab{APOPL, Ynone, Yds, 0, [4]uint8{0x1f, E, 0, 0}},
-	Movtab{APOPL, Ynone, Yes, 0, [4]uint8{0x07, E, 0, 0}},
-	Movtab{APOPL, Ynone, Yss, 0, [4]uint8{0x17, E, 0, 0}},
-	Movtab{APOPL, Ynone, Yfs, 0, [4]uint8{0x0f, 0xa1, E, 0}},
-	Movtab{APOPL, Ynone, Ygs, 0, [4]uint8{0x0f, 0xa9, E, 0}},
-	Movtab{APOPQ, Ynone, Yfs, 0, [4]uint8{0x0f, 0xa1, E, 0}},
-	Movtab{APOPQ, Ynone, Ygs, 0, [4]uint8{0x0f, 0xa9, E, 0}},
-	Movtab{APOPW, Ynone, Yds, 0, [4]uint8{Pe, 0x1f, E, 0}},
-	Movtab{APOPW, Ynone, Yes, 0, [4]uint8{Pe, 0x07, E, 0}},
-	Movtab{APOPW, Ynone, Yss, 0, [4]uint8{Pe, 0x17, E, 0}},
-	Movtab{APOPW, Ynone, Yfs, 0, [4]uint8{Pe, 0x0f, 0xa1, E}},
-	Movtab{APOPW, Ynone, Ygs, 0, [4]uint8{Pe, 0x0f, 0xa9, E}},
+	Movtab{APOPL, Ynone, Ynone, Yds, 0, [4]uint8{0x1f, E, 0, 0}},
+	Movtab{APOPL, Ynone, Ynone, Yes, 0, [4]uint8{0x07, E, 0, 0}},
+	Movtab{APOPL, Ynone, Ynone, Yss, 0, [4]uint8{0x17, E, 0, 0}},
+	Movtab{APOPL, Ynone, Ynone, Yfs, 0, [4]uint8{0x0f, 0xa1, E, 0}},
+	Movtab{APOPL, Ynone, Ynone, Ygs, 0, [4]uint8{0x0f, 0xa9, E, 0}},
+	Movtab{APOPQ, Ynone, Ynone, Yfs, 0, [4]uint8{0x0f, 0xa1, E, 0}},
+	Movtab{APOPQ, Ynone, Ynone, Ygs, 0, [4]uint8{0x0f, 0xa9, E, 0}},
+	Movtab{APOPW, Ynone, Ynone, Yds, 0, [4]uint8{Pe, 0x1f, E, 0}},
+	Movtab{APOPW, Ynone, Ynone, Yes, 0, [4]uint8{Pe, 0x07, E, 0}},
+	Movtab{APOPW, Ynone, Ynone, Yss, 0, [4]uint8{Pe, 0x17, E, 0}},
+	Movtab{APOPW, Ynone, Ynone, Yfs, 0, [4]uint8{Pe, 0x0f, 0xa1, E}},
+	Movtab{APOPW, Ynone, Ynone, Ygs, 0, [4]uint8{Pe, 0x0f, 0xa9, E}},
 
 	/* mov seg */
-	Movtab{AMOVW, Yes, Yml, 1, [4]uint8{0x8c, 0, 0, 0}},
-	Movtab{AMOVW, Ycs, Yml, 1, [4]uint8{0x8c, 1, 0, 0}},
-	Movtab{AMOVW, Yss, Yml, 1, [4]uint8{0x8c, 2, 0, 0}},
-	Movtab{AMOVW, Yds, Yml, 1, [4]uint8{0x8c, 3, 0, 0}},
-	Movtab{AMOVW, Yfs, Yml, 1, [4]uint8{0x8c, 4, 0, 0}},
-	Movtab{AMOVW, Ygs, Yml, 1, [4]uint8{0x8c, 5, 0, 0}},
-	Movtab{AMOVW, Yml, Yes, 2, [4]uint8{0x8e, 0, 0, 0}},
-	Movtab{AMOVW, Yml, Ycs, 2, [4]uint8{0x8e, 1, 0, 0}},
-	Movtab{AMOVW, Yml, Yss, 2, [4]uint8{0x8e, 2, 0, 0}},
-	Movtab{AMOVW, Yml, Yds, 2, [4]uint8{0x8e, 3, 0, 0}},
-	Movtab{AMOVW, Yml, Yfs, 2, [4]uint8{0x8e, 4, 0, 0}},
-	Movtab{AMOVW, Yml, Ygs, 2, [4]uint8{0x8e, 5, 0, 0}},
+	Movtab{AMOVW, Yes, Ynone, Yml, 1, [4]uint8{0x8c, 0, 0, 0}},
+	Movtab{AMOVW, Ycs, Ynone, Yml, 1, [4]uint8{0x8c, 1, 0, 0}},
+	Movtab{AMOVW, Yss, Ynone, Yml, 1, [4]uint8{0x8c, 2, 0, 0}},
+	Movtab{AMOVW, Yds, Ynone, Yml, 1, [4]uint8{0x8c, 3, 0, 0}},
+	Movtab{AMOVW, Yfs, Ynone, Yml, 1, [4]uint8{0x8c, 4, 0, 0}},
+	Movtab{AMOVW, Ygs, Ynone, Yml, 1, [4]uint8{0x8c, 5, 0, 0}},
+	Movtab{AMOVW, Yml, Ynone, Yes, 2, [4]uint8{0x8e, 0, 0, 0}},
+	Movtab{AMOVW, Yml, Ynone, Ycs, 2, [4]uint8{0x8e, 1, 0, 0}},
+	Movtab{AMOVW, Yml, Ynone, Yss, 2, [4]uint8{0x8e, 2, 0, 0}},
+	Movtab{AMOVW, Yml, Ynone, Yds, 2, [4]uint8{0x8e, 3, 0, 0}},
+	Movtab{AMOVW, Yml, Ynone, Yfs, 2, [4]uint8{0x8e, 4, 0, 0}},
+	Movtab{AMOVW, Yml, Ynone, Ygs, 2, [4]uint8{0x8e, 5, 0, 0}},
 
 	/* mov cr */
-	Movtab{AMOVL, Ycr0, Yml, 3, [4]uint8{0x0f, 0x20, 0, 0}},
-	Movtab{AMOVL, Ycr2, Yml, 3, [4]uint8{0x0f, 0x20, 2, 0}},
-	Movtab{AMOVL, Ycr3, Yml, 3, [4]uint8{0x0f, 0x20, 3, 0}},
-	Movtab{AMOVL, Ycr4, Yml, 3, [4]uint8{0x0f, 0x20, 4, 0}},
-	Movtab{AMOVL, Ycr8, Yml, 3, [4]uint8{0x0f, 0x20, 8, 0}},
-	Movtab{AMOVQ, Ycr0, Yml, 3, [4]uint8{0x0f, 0x20, 0, 0}},
-	Movtab{AMOVQ, Ycr2, Yml, 3, [4]uint8{0x0f, 0x20, 2, 0}},
-	Movtab{AMOVQ, Ycr3, Yml, 3, [4]uint8{0x0f, 0x20, 3, 0}},
-	Movtab{AMOVQ, Ycr4, Yml, 3, [4]uint8{0x0f, 0x20, 4, 0}},
-	Movtab{AMOVQ, Ycr8, Yml, 3, [4]uint8{0x0f, 0x20, 8, 0}},
-	Movtab{AMOVL, Yml, Ycr0, 4, [4]uint8{0x0f, 0x22, 0, 0}},
-	Movtab{AMOVL, Yml, Ycr2, 4, [4]uint8{0x0f, 0x22, 2, 0}},
-	Movtab{AMOVL, Yml, Ycr3, 4, [4]uint8{0x0f, 0x22, 3, 0}},
-	Movtab{AMOVL, Yml, Ycr4, 4, [4]uint8{0x0f, 0x22, 4, 0}},
-	Movtab{AMOVL, Yml, Ycr8, 4, [4]uint8{0x0f, 0x22, 8, 0}},
-	Movtab{AMOVQ, Yml, Ycr0, 4, [4]uint8{0x0f, 0x22, 0, 0}},
-	Movtab{AMOVQ, Yml, Ycr2, 4, [4]uint8{0x0f, 0x22, 2, 0}},
-	Movtab{AMOVQ, Yml, Ycr3, 4, [4]uint8{0x0f, 0x22, 3, 0}},
-	Movtab{AMOVQ, Yml, Ycr4, 4, [4]uint8{0x0f, 0x22, 4, 0}},
-	Movtab{AMOVQ, Yml, Ycr8, 4, [4]uint8{0x0f, 0x22, 8, 0}},
+	Movtab{AMOVL, Ycr0, Ynone, Yml, 3, [4]uint8{0x0f, 0x20, 0, 0}},
+	Movtab{AMOVL, Ycr2, Ynone, Yml, 3, [4]uint8{0x0f, 0x20, 2, 0}},
+	Movtab{AMOVL, Ycr3, Ynone, Yml, 3, [4]uint8{0x0f, 0x20, 3, 0}},
+	Movtab{AMOVL, Ycr4, Ynone, Yml, 3, [4]uint8{0x0f, 0x20, 4, 0}},
+	Movtab{AMOVL, Ycr8, Ynone, Yml, 3, [4]uint8{0x0f, 0x20, 8, 0}},
+	Movtab{AMOVQ, Ycr0, Ynone, Yml, 3, [4]uint8{0x0f, 0x20, 0, 0}},
+	Movtab{AMOVQ, Ycr2, Ynone, Yml, 3, [4]uint8{0x0f, 0x20, 2, 0}},
+	Movtab{AMOVQ, Ycr3, Ynone, Yml, 3, [4]uint8{0x0f, 0x20, 3, 0}},
+	Movtab{AMOVQ, Ycr4, Ynone, Yml, 3, [4]uint8{0x0f, 0x20, 4, 0}},
+	Movtab{AMOVQ, Ycr8, Ynone, Yml, 3, [4]uint8{0x0f, 0x20, 8, 0}},
+	Movtab{AMOVL, Yml, Ynone, Ycr0, 4, [4]uint8{0x0f, 0x22, 0, 0}},
+	Movtab{AMOVL, Yml, Ynone, Ycr2, 4, [4]uint8{0x0f, 0x22, 2, 0}},
+	Movtab{AMOVL, Yml, Ynone, Ycr3, 4, [4]uint8{0x0f, 0x22, 3, 0}},
+	Movtab{AMOVL, Yml, Ynone, Ycr4, 4, [4]uint8{0x0f, 0x22, 4, 0}},
+	Movtab{AMOVL, Yml, Ynone, Ycr8, 4, [4]uint8{0x0f, 0x22, 8, 0}},
+	Movtab{AMOVQ, Yml, Ynone, Ycr0, 4, [4]uint8{0x0f, 0x22, 0, 0}},
+	Movtab{AMOVQ, Yml, Ynone, Ycr2, 4, [4]uint8{0x0f, 0x22, 2, 0}},
+	Movtab{AMOVQ, Yml, Ynone, Ycr3, 4, [4]uint8{0x0f, 0x22, 3, 0}},
+	Movtab{AMOVQ, Yml, Ynone, Ycr4, 4, [4]uint8{0x0f, 0x22, 4, 0}},
+	Movtab{AMOVQ, Yml, Ynone, Ycr8, 4, [4]uint8{0x0f, 0x22, 8, 0}},
 
 	/* mov dr */
-	Movtab{AMOVL, Ydr0, Yml, 3, [4]uint8{0x0f, 0x21, 0, 0}},
-	Movtab{AMOVL, Ydr6, Yml, 3, [4]uint8{0x0f, 0x21, 6, 0}},
-	Movtab{AMOVL, Ydr7, Yml, 3, [4]uint8{0x0f, 0x21, 7, 0}},
-	Movtab{AMOVQ, Ydr0, Yml, 3, [4]uint8{0x0f, 0x21, 0, 0}},
-	Movtab{AMOVQ, Ydr6, Yml, 3, [4]uint8{0x0f, 0x21, 6, 0}},
-	Movtab{AMOVQ, Ydr7, Yml, 3, [4]uint8{0x0f, 0x21, 7, 0}},
-	Movtab{AMOVL, Yml, Ydr0, 4, [4]uint8{0x0f, 0x23, 0, 0}},
-	Movtab{AMOVL, Yml, Ydr6, 4, [4]uint8{0x0f, 0x23, 6, 0}},
-	Movtab{AMOVL, Yml, Ydr7, 4, [4]uint8{0x0f, 0x23, 7, 0}},
-	Movtab{AMOVQ, Yml, Ydr0, 4, [4]uint8{0x0f, 0x23, 0, 0}},
-	Movtab{AMOVQ, Yml, Ydr6, 4, [4]uint8{0x0f, 0x23, 6, 0}},
-	Movtab{AMOVQ, Yml, Ydr7, 4, [4]uint8{0x0f, 0x23, 7, 0}},
+	Movtab{AMOVL, Ydr0, Ynone, Yml, 3, [4]uint8{0x0f, 0x21, 0, 0}},
+	Movtab{AMOVL, Ydr6, Ynone, Yml, 3, [4]uint8{0x0f, 0x21, 6, 0}},
+	Movtab{AMOVL, Ydr7, Ynone, Yml, 3, [4]uint8{0x0f, 0x21, 7, 0}},
+	Movtab{AMOVQ, Ydr0, Ynone, Yml, 3, [4]uint8{0x0f, 0x21, 0, 0}},
+	Movtab{AMOVQ, Ydr6, Ynone, Yml, 3, [4]uint8{0x0f, 0x21, 6, 0}},
+	Movtab{AMOVQ, Ydr7, Ynone, Yml, 3, [4]uint8{0x0f, 0x21, 7, 0}},
+	Movtab{AMOVL, Yml, Ynone, Ydr0, 4, [4]uint8{0x0f, 0x23, 0, 0}},
+	Movtab{AMOVL, Yml, Ynone, Ydr6, 4, [4]uint8{0x0f, 0x23, 6, 0}},
+	Movtab{AMOVL, Yml, Ynone, Ydr7, 4, [4]uint8{0x0f, 0x23, 7, 0}},
+	Movtab{AMOVQ, Yml, Ynone, Ydr0, 4, [4]uint8{0x0f, 0x23, 0, 0}},
+	Movtab{AMOVQ, Yml, Ynone, Ydr6, 4, [4]uint8{0x0f, 0x23, 6, 0}},
+	Movtab{AMOVQ, Yml, Ynone, Ydr7, 4, [4]uint8{0x0f, 0x23, 7, 0}},
 
 	/* mov tr */
-	Movtab{AMOVL, Ytr6, Yml, 3, [4]uint8{0x0f, 0x24, 6, 0}},
-	Movtab{AMOVL, Ytr7, Yml, 3, [4]uint8{0x0f, 0x24, 7, 0}},
-	Movtab{AMOVL, Yml, Ytr6, 4, [4]uint8{0x0f, 0x26, 6, E}},
-	Movtab{AMOVL, Yml, Ytr7, 4, [4]uint8{0x0f, 0x26, 7, E}},
+	Movtab{AMOVL, Ytr6, Ynone, Yml, 3, [4]uint8{0x0f, 0x24, 6, 0}},
+	Movtab{AMOVL, Ytr7, Ynone, Yml, 3, [4]uint8{0x0f, 0x24, 7, 0}},
+	Movtab{AMOVL, Yml, Ynone, Ytr6, 4, [4]uint8{0x0f, 0x26, 6, E}},
+	Movtab{AMOVL, Yml, Ynone, Ytr7, 4, [4]uint8{0x0f, 0x26, 7, E}},
 
 	/* lgdt, sgdt, lidt, sidt */
-	Movtab{AMOVL, Ym, Ygdtr, 4, [4]uint8{0x0f, 0x01, 2, 0}},
-	Movtab{AMOVL, Ygdtr, Ym, 3, [4]uint8{0x0f, 0x01, 0, 0}},
-	Movtab{AMOVL, Ym, Yidtr, 4, [4]uint8{0x0f, 0x01, 3, 0}},
-	Movtab{AMOVL, Yidtr, Ym, 3, [4]uint8{0x0f, 0x01, 1, 0}},
-	Movtab{AMOVQ, Ym, Ygdtr, 4, [4]uint8{0x0f, 0x01, 2, 0}},
-	Movtab{AMOVQ, Ygdtr, Ym, 3, [4]uint8{0x0f, 0x01, 0, 0}},
-	Movtab{AMOVQ, Ym, Yidtr, 4, [4]uint8{0x0f, 0x01, 3, 0}},
-	Movtab{AMOVQ, Yidtr, Ym, 3, [4]uint8{0x0f, 0x01, 1, 0}},
+	Movtab{AMOVL, Ym, Ynone, Ygdtr, 4, [4]uint8{0x0f, 0x01, 2, 0}},
+	Movtab{AMOVL, Ygdtr, Ynone, Ym, 3, [4]uint8{0x0f, 0x01, 0, 0}},
+	Movtab{AMOVL, Ym, Ynone, Yidtr, 4, [4]uint8{0x0f, 0x01, 3, 0}},
+	Movtab{AMOVL, Yidtr, Ynone, Ym, 3, [4]uint8{0x0f, 0x01, 1, 0}},
+	Movtab{AMOVQ, Ym, Ynone, Ygdtr, 4, [4]uint8{0x0f, 0x01, 2, 0}},
+	Movtab{AMOVQ, Ygdtr, Ynone, Ym, 3, [4]uint8{0x0f, 0x01, 0, 0}},
+	Movtab{AMOVQ, Ym, Ynone, Yidtr, 4, [4]uint8{0x0f, 0x01, 3, 0}},
+	Movtab{AMOVQ, Yidtr, Ynone, Ym, 3, [4]uint8{0x0f, 0x01, 1, 0}},
 
 	/* lldt, sldt */
-	Movtab{AMOVW, Yml, Yldtr, 4, [4]uint8{0x0f, 0x00, 2, 0}},
-	Movtab{AMOVW, Yldtr, Yml, 3, [4]uint8{0x0f, 0x00, 0, 0}},
+	Movtab{AMOVW, Yml, Ynone, Yldtr, 4, [4]uint8{0x0f, 0x00, 2, 0}},
+	Movtab{AMOVW, Yldtr, Ynone, Yml, 3, [4]uint8{0x0f, 0x00, 0, 0}},
 
 	/* lmsw, smsw */
-	Movtab{AMOVW, Yml, Ymsw, 4, [4]uint8{0x0f, 0x01, 6, 0}},
-	Movtab{AMOVW, Ymsw, Yml, 3, [4]uint8{0x0f, 0x01, 4, 0}},
+	Movtab{AMOVW, Yml, Ynone, Ymsw, 4, [4]uint8{0x0f, 0x01, 6, 0}},
+	Movtab{AMOVW, Ymsw, Ynone, Yml, 3, [4]uint8{0x0f, 0x01, 4, 0}},
 
 	/* ltr, str */
-	Movtab{AMOVW, Yml, Ytask, 4, [4]uint8{0x0f, 0x00, 3, 0}},
-	Movtab{AMOVW, Ytask, Yml, 3, [4]uint8{0x0f, 0x00, 1, 0}},
+	Movtab{AMOVW, Yml, Ynone, Ytask, 4, [4]uint8{0x0f, 0x00, 3, 0}},
+	Movtab{AMOVW, Ytask, Ynone, Yml, 3, [4]uint8{0x0f, 0x00, 1, 0}},
 
-	/* load full pointer */
+	/* load full pointer - unsupported
 	Movtab{AMOVL, Yml, Ycol, 5, [4]uint8{0, 0, 0, 0}},
 	Movtab{AMOVW, Yml, Ycol, 5, [4]uint8{Pe, 0, 0, 0}},
+	*/
 
 	/* double shift */
-	Movtab{ASHLL, Ycol, Yml, 6, [4]uint8{0xa4, 0xa5, 0, 0}},
-	Movtab{ASHRL, Ycol, Yml, 6, [4]uint8{0xac, 0xad, 0, 0}},
-	Movtab{ASHLQ, Ycol, Yml, 6, [4]uint8{Pw, 0xa4, 0xa5, 0}},
-	Movtab{ASHRQ, Ycol, Yml, 6, [4]uint8{Pw, 0xac, 0xad, 0}},
-	Movtab{ASHLW, Ycol, Yml, 6, [4]uint8{Pe, 0xa4, 0xa5, 0}},
-	Movtab{ASHRW, Ycol, Yml, 6, [4]uint8{Pe, 0xac, 0xad, 0}},
+	Movtab{ASHLL, Yi8, Yrl, Yml, 6, [4]uint8{0xa4, 0xa5, 0, 0}},
+	Movtab{ASHLL, Ycl, Yrl, Yml, 6, [4]uint8{0xa4, 0xa5, 0, 0}},
+	Movtab{ASHLL, Ycx, Yrl, Yml, 6, [4]uint8{0xa4, 0xa5, 0, 0}},
+	Movtab{ASHRL, Yi8, Yrl, Yml, 6, [4]uint8{0xac, 0xad, 0, 0}},
+	Movtab{ASHRL, Ycl, Yrl, Yml, 6, [4]uint8{0xac, 0xad, 0, 0}},
+	Movtab{ASHRL, Ycx, Yrl, Yml, 6, [4]uint8{0xac, 0xad, 0, 0}},
+	Movtab{ASHLQ, Yi8, Yrl, Yml, 6, [4]uint8{Pw, 0xa4, 0xa5, 0}},
+	Movtab{ASHLQ, Ycl, Yrl, Yml, 6, [4]uint8{Pw, 0xa4, 0xa5, 0}},
+	Movtab{ASHLQ, Ycx, Yrl, Yml, 6, [4]uint8{Pw, 0xa4, 0xa5, 0}},
+	Movtab{ASHRQ, Yi8, Yrl, Yml, 6, [4]uint8{Pw, 0xac, 0xad, 0}},
+	Movtab{ASHRQ, Ycl, Yrl, Yml, 6, [4]uint8{Pw, 0xac, 0xad, 0}},
+	Movtab{ASHRQ, Ycx, Yrl, Yml, 6, [4]uint8{Pw, 0xac, 0xad, 0}},
+	Movtab{ASHLW, Yi8, Yrl, Yml, 6, [4]uint8{Pe, 0xa4, 0xa5, 0}},
+	Movtab{ASHLW, Ycl, Yrl, Yml, 6, [4]uint8{Pe, 0xa4, 0xa5, 0}},
+	Movtab{ASHLW, Ycx, Yrl, Yml, 6, [4]uint8{Pe, 0xa4, 0xa5, 0}},
+	Movtab{ASHRW, Yi8, Yrl, Yml, 6, [4]uint8{Pe, 0xac, 0xad, 0}},
+	Movtab{ASHRW, Ycl, Yrl, Yml, 6, [4]uint8{Pe, 0xac, 0xad, 0}},
+	Movtab{ASHRW, Ycx, Yrl, Yml, 6, [4]uint8{Pe, 0xac, 0xad, 0}},
 
 	/* load TLS base */
-	Movtab{AMOVQ, Ytls, Yrl, 7, [4]uint8{0, 0, 0, 0}},
-	Movtab{0, 0, 0, 0, [4]uint8{}},
+	Movtab{AMOVL, Ytls, Ynone, Yrl, 7, [4]uint8{0, 0, 0, 0}},
+	Movtab{AMOVQ, Ytls, Ynone, Yrl, 7, [4]uint8{0, 0, 0, 0}},
+	Movtab{0, 0, 0, 0, 0, [4]uint8{}},
 }
 
 func isax(a *obj.Addr) bool {
 	switch a.Reg {
-	case REG_AX,
-		REG_AL,
-		REG_AH:
+	case REG_AX, REG_AL, REG_AH:
 		return true
 	}
 
@@ -2740,10 +2879,7 @@
 
 func mediaop(ctxt *obj.Link, o *Optab, op int, osize int, z int) int {
 	switch op {
-	case Pm,
-		Pe,
-		Pf2,
-		Pf3:
+	case Pm, Pe, Pf2, Pf3:
 		if osize != 1 {
 			if op != Pm {
 				ctxt.Andptr[0] = byte(op)
@@ -2769,639 +2905,1001 @@
 	return z
 }
 
-func doasm(ctxt *obj.Link, p *obj.Prog) {
-	var o *Optab
-	var q *obj.Prog
-	var pp obj.Prog
-	var t []byte
-	var mo []Movtab
-	var z int
-	var op int
-	var ft int
-	var tt int
-	var xo int
-	var l int
-	var pre int
-	var v int64
-	var rel obj.Reloc
-	var r *obj.Reloc
-	var a *obj.Addr
-	var yt ytab
+var bpduff1 = []byte{
+	0x48, 0x89, 0x6c, 0x24, 0xf0, // MOVQ BP, -16(SP)
+	0x48, 0x8d, 0x6c, 0x24, 0xf0, // LEAQ -16(SP), BP
+}
 
+var bpduff2 = []byte{
+	0x90,
+	0x48, 0x8b, 0x6d, 0x00, // MOVQ 0(BP), BP
+}
+
+func doasm(ctxt *obj.Link, p *obj.Prog) {
 	ctxt.Curp = p // TODO
 
-	o = opindex[p.As]
+	o := opindex[p.As&obj.AMask]
 
 	if o == nil {
 		ctxt.Diag("asmins: missing op %v", p)
 		return
 	}
 
-	pre = prefixof(ctxt, &p.From)
+	pre := prefixof(ctxt, p, &p.From)
 	if pre != 0 {
 		ctxt.Andptr[0] = byte(pre)
 		ctxt.Andptr = ctxt.Andptr[1:]
 	}
-	pre = prefixof(ctxt, &p.To)
+	pre = prefixof(ctxt, p, &p.To)
 	if pre != 0 {
 		ctxt.Andptr[0] = byte(pre)
 		ctxt.Andptr = ctxt.Andptr[1:]
 	}
 
+	// TODO(rsc): This special case is for SHRQ $3, AX:DX,
+	// which encodes as SHRQ $32(DX*0), AX.
+	// Similarly SHRQ CX, AX:DX is really SHRQ CX(DX*0), AX.
+	// Change encoding generated by assemblers and compilers and remove.
+	if (p.From.Type == obj.TYPE_CONST || p.From.Type == obj.TYPE_REG) && p.From.Index != REG_NONE && p.From.Scale == 0 {
+		p.From3.Type = obj.TYPE_REG
+		p.From3.Reg = p.From.Index
+		p.From.Index = 0
+	}
+
+	// TODO(rsc): This special case is for PINSRQ etc, CMPSD etc.
+	// Change encoding generated by assemblers and compilers (if any) and remove.
+	switch p.As {
+	case AIMUL3Q, APEXTRW, APINSRW, APINSRD, APINSRQ, APSHUFHW, APSHUFL, APSHUFW, ASHUFPD, ASHUFPS, AAESKEYGENASSIST, APSHUFD, APCLMULQDQ:
+		if p.From3.Type == obj.TYPE_NONE {
+			p.From3 = p.From
+			p.From = obj.Addr{}
+			p.From.Type = obj.TYPE_CONST
+			p.From.Offset = p.To.Offset
+			p.To.Offset = 0
+		}
+	case ACMPSD, ACMPSS, ACMPPS, ACMPPD:
+		if p.From3.Type == obj.TYPE_NONE {
+			p.From3 = p.To
+			p.To = obj.Addr{}
+			p.To.Type = obj.TYPE_CONST
+			p.To.Offset = p.From3.Offset
+			p.From3.Offset = 0
+		}
+	}
+
 	if p.Ft == 0 {
 		p.Ft = uint8(oclass(ctxt, p, &p.From))
 	}
+	if p.F3t == 0 {
+		p.F3t = uint8(oclass(ctxt, p, &p.From3))
+	}
 	if p.Tt == 0 {
 		p.Tt = uint8(oclass(ctxt, p, &p.To))
 	}
 
-	ft = int(p.Ft) * Ymax
-	tt = int(p.Tt) * Ymax
+	ft := int(p.Ft) * Ymax
+	f3t := int(p.F3t) * Ymax
+	tt := int(p.Tt) * Ymax
 
-	xo = bool2int(o.op[0] == 0x0f)
-	z = 0
-	for _, yt = range o.ytab {
-		if ycover[ft+int(yt.from)] != 0 && ycover[tt+int(yt.to)] != 0 {
-			goto found
-		}
-		z += int(yt.zoffset) + xo
-	}
-	goto domov
+	xo := bool2int(o.op[0] == 0x0f)
+	z := 0
+	var a *obj.Addr
+	var l int
+	var op int
+	var q *obj.Prog
+	var r *obj.Reloc
+	var rel obj.Reloc
+	var v int64
+	for i := range o.ytab {
+		yt := &o.ytab[i]
+		if ycover[ft+int(yt.from)] != 0 && ycover[f3t+int(yt.from3)] != 0 && ycover[tt+int(yt.to)] != 0 {
+			switch o.prefix {
+			case Px1: /* first option valid only in 32-bit mode */
+				if ctxt.Mode == 64 && z == 0 {
+					z += int(yt.zoffset) + xo
+					continue
+				}
+			case Pq: /* 16 bit escape and opcode escape */
+				ctxt.Andptr[0] = Pe
+				ctxt.Andptr = ctxt.Andptr[1:]
 
-found:
-	switch o.prefix {
-	case Pq: /* 16 bit escape and opcode escape */
-		ctxt.Andptr[0] = Pe
-		ctxt.Andptr = ctxt.Andptr[1:]
+				ctxt.Andptr[0] = Pm
+				ctxt.Andptr = ctxt.Andptr[1:]
 
-		ctxt.Andptr[0] = Pm
-		ctxt.Andptr = ctxt.Andptr[1:]
+			case Pq3: /* 16 bit escape, Rex.w, and opcode escape */
+				ctxt.Andptr[0] = Pe
+				ctxt.Andptr = ctxt.Andptr[1:]
 
-	case Pq3: /* 16 bit escape, Rex.w, and opcode escape */
-		ctxt.Andptr[0] = Pe
-		ctxt.Andptr = ctxt.Andptr[1:]
+				ctxt.Andptr[0] = Pw
+				ctxt.Andptr = ctxt.Andptr[1:]
+				ctxt.Andptr[0] = Pm
+				ctxt.Andptr = ctxt.Andptr[1:]
 
-		ctxt.Andptr[0] = Pw
-		ctxt.Andptr = ctxt.Andptr[1:]
-		ctxt.Andptr[0] = Pm
-		ctxt.Andptr = ctxt.Andptr[1:]
+			case Pf2, /* xmm opcode escape */
+				Pf3:
+				ctxt.Andptr[0] = byte(o.prefix)
+				ctxt.Andptr = ctxt.Andptr[1:]
 
-	case Pf2, /* xmm opcode escape */
-		Pf3:
-		ctxt.Andptr[0] = byte(o.prefix)
-		ctxt.Andptr = ctxt.Andptr[1:]
+				ctxt.Andptr[0] = Pm
+				ctxt.Andptr = ctxt.Andptr[1:]
 
-		ctxt.Andptr[0] = Pm
-		ctxt.Andptr = ctxt.Andptr[1:]
+			case Pm: /* opcode escape */
+				ctxt.Andptr[0] = Pm
+				ctxt.Andptr = ctxt.Andptr[1:]
 
-	case Pm: /* opcode escape */
-		ctxt.Andptr[0] = Pm
-		ctxt.Andptr = ctxt.Andptr[1:]
+			case Pe: /* 16 bit escape */
+				ctxt.Andptr[0] = Pe
+				ctxt.Andptr = ctxt.Andptr[1:]
 
-	case Pe: /* 16 bit escape */
-		ctxt.Andptr[0] = Pe
-		ctxt.Andptr = ctxt.Andptr[1:]
+			case Pw: /* 64-bit escape */
+				if p.Mode != 64 {
+					ctxt.Diag("asmins: illegal 64: %v", p)
+				}
+				ctxt.Rexflag |= Pw
 
-	case Pw: /* 64-bit escape */
-		if p.Mode != 64 {
-			ctxt.Diag("asmins: illegal 64: %v", p)
-		}
-		ctxt.Rexflag |= Pw
+			case Pw8: /* 64-bit escape if z >= 8 */
+				if z >= 8 {
+					if p.Mode != 64 {
+						ctxt.Diag("asmins: illegal 64: %v", p)
+					}
+					ctxt.Rexflag |= Pw
+				}
 
-	case Pb: /* botch */
-		bytereg(&p.From, &p.Ft)
+			case Pb: /* botch */
+				if p.Mode != 64 && (isbadbyte(&p.From) || isbadbyte(&p.To)) {
+					goto bad
+				}
+				// NOTE(rsc): This is probably safe to do always,
+				// but when enabled it chooses different encodings
+				// than the old cmd/internal/obj/i386 code did,
+				// which breaks our "same bits out" checks.
+				// In particular, CMPB AX, $0 encodes as 80 f8 00
+				// in the original obj/i386, and it would encode
+				// (using a valid, shorter form) as 3c 00 if we enabled
+				// the call to bytereg here.
+				if p.Mode == 64 {
+					bytereg(&p.From, &p.Ft)
+					bytereg(&p.To, &p.Tt)
+				}
 
-		bytereg(&p.To, &p.Tt)
+			case P32: /* 32 bit but illegal if 64-bit mode */
+				if p.Mode == 64 {
+					ctxt.Diag("asmins: illegal in 64-bit mode: %v", p)
+				}
 
-	case P32: /* 32 bit but illegal if 64-bit mode */
-		if p.Mode == 64 {
-			ctxt.Diag("asmins: illegal in 64-bit mode: %v", p)
-		}
+			case Py: /* 64-bit only, no prefix */
+				if p.Mode != 64 {
+					ctxt.Diag("asmins: illegal in %d-bit mode: %v", p.Mode, p)
+				}
 
-	case Py: /* 64-bit only, no prefix */
-		if p.Mode != 64 {
-			ctxt.Diag("asmins: illegal in %d-bit mode: %v", p.Mode, p)
-		}
-	}
+			case Py1: /* 64-bit only if z < 1, no prefix */
+				if z < 1 && p.Mode != 64 {
+					ctxt.Diag("asmins: illegal in %d-bit mode: %v", p.Mode, p)
+				}
 
-	if z >= len(o.op) {
-		log.Fatalf("asmins bad table %v", p)
-	}
-	op = int(o.op[z])
-	if op == 0x0f {
-		ctxt.Andptr[0] = byte(op)
-		ctxt.Andptr = ctxt.Andptr[1:]
-		z++
-		op = int(o.op[z])
-	}
+			case Py3: /* 64-bit only if z < 3, no prefix */
+				if z < 3 && p.Mode != 64 {
+					ctxt.Diag("asmins: illegal in %d-bit mode: %v", p.Mode, p)
+				}
+			}
 
-	switch yt.zcase {
-	default:
-		ctxt.Diag("asmins: unknown z %d %v", yt.zcase, p)
-		return
-
-	case Zpseudo:
-		break
-
-	case Zlit:
-		for ; ; z++ {
+			if z >= len(o.op) {
+				log.Fatalf("asmins bad table %v", p)
+			}
 			op = int(o.op[z])
-			if op == 0 {
+			if op == 0x0f {
+				ctxt.Andptr[0] = byte(op)
+				ctxt.Andptr = ctxt.Andptr[1:]
+				z++
+				op = int(o.op[z])
+			}
+
+			switch yt.zcase {
+			default:
+				ctxt.Diag("asmins: unknown z %d %v", yt.zcase, p)
+				return
+
+			case Zpseudo:
 				break
-			}
-			ctxt.Andptr[0] = byte(op)
-			ctxt.Andptr = ctxt.Andptr[1:]
-		}
 
-	case Zlitm_r:
-		for ; ; z++ {
-			op = int(o.op[z])
-			if op == 0 {
-				break
-			}
-			ctxt.Andptr[0] = byte(op)
-			ctxt.Andptr = ctxt.Andptr[1:]
-		}
-		asmand(ctxt, p, &p.From, &p.To)
-
-	case Zmb_r:
-		bytereg(&p.From, &p.Ft)
-		fallthrough
-
-		/* fall through */
-	case Zm_r:
-		ctxt.Andptr[0] = byte(op)
-		ctxt.Andptr = ctxt.Andptr[1:]
-
-		asmand(ctxt, p, &p.From, &p.To)
-
-	case Zm2_r:
-		ctxt.Andptr[0] = byte(op)
-		ctxt.Andptr = ctxt.Andptr[1:]
-		ctxt.Andptr[0] = byte(o.op[z+1])
-		ctxt.Andptr = ctxt.Andptr[1:]
-		asmand(ctxt, p, &p.From, &p.To)
-
-	case Zm_r_xm:
-		mediaop(ctxt, o, op, int(yt.zoffset), z)
-		asmand(ctxt, p, &p.From, &p.To)
-
-	case Zm_r_xm_nr:
-		ctxt.Rexflag = 0
-		mediaop(ctxt, o, op, int(yt.zoffset), z)
-		asmand(ctxt, p, &p.From, &p.To)
-
-	case Zm_r_i_xm:
-		mediaop(ctxt, o, op, int(yt.zoffset), z)
-		asmand(ctxt, p, &p.From, &p.To)
-		ctxt.Andptr[0] = byte(p.To.Offset)
-		ctxt.Andptr = ctxt.Andptr[1:]
-
-	case Zm_r_3d:
-		ctxt.Andptr[0] = 0x0f
-		ctxt.Andptr = ctxt.Andptr[1:]
-		ctxt.Andptr[0] = 0x0f
-		ctxt.Andptr = ctxt.Andptr[1:]
-		asmand(ctxt, p, &p.From, &p.To)
-		ctxt.Andptr[0] = byte(op)
-		ctxt.Andptr = ctxt.Andptr[1:]
-
-	case Zibm_r:
-		for {
-			tmp1 := z
-			z++
-			op = int(o.op[tmp1])
-			if op == 0 {
-				break
-			}
-			ctxt.Andptr[0] = byte(op)
-			ctxt.Andptr = ctxt.Andptr[1:]
-		}
-		asmand(ctxt, p, &p.From, &p.To)
-		ctxt.Andptr[0] = byte(p.To.Offset)
-		ctxt.Andptr = ctxt.Andptr[1:]
-
-	case Zaut_r:
-		ctxt.Andptr[0] = 0x8d
-		ctxt.Andptr = ctxt.Andptr[1:] /* leal */
-		if p.From.Type != obj.TYPE_ADDR {
-			ctxt.Diag("asmins: Zaut sb type ADDR")
-		}
-		p.From.Type = obj.TYPE_MEM
-		asmand(ctxt, p, &p.From, &p.To)
-		p.From.Type = obj.TYPE_ADDR
-
-	case Zm_o:
-		ctxt.Andptr[0] = byte(op)
-		ctxt.Andptr = ctxt.Andptr[1:]
-		asmando(ctxt, p, &p.From, int(o.op[z+1]))
-
-	case Zr_m:
-		ctxt.Andptr[0] = byte(op)
-		ctxt.Andptr = ctxt.Andptr[1:]
-		asmand(ctxt, p, &p.To, &p.From)
-
-	case Zr_m_xm:
-		mediaop(ctxt, o, op, int(yt.zoffset), z)
-		asmand(ctxt, p, &p.To, &p.From)
-
-	case Zr_m_xm_nr:
-		ctxt.Rexflag = 0
-		mediaop(ctxt, o, op, int(yt.zoffset), z)
-		asmand(ctxt, p, &p.To, &p.From)
-
-	case Zr_m_i_xm:
-		mediaop(ctxt, o, op, int(yt.zoffset), z)
-		asmand(ctxt, p, &p.To, &p.From)
-		ctxt.Andptr[0] = byte(p.From.Offset)
-		ctxt.Andptr = ctxt.Andptr[1:]
-
-	case Zo_m:
-		ctxt.Andptr[0] = byte(op)
-		ctxt.Andptr = ctxt.Andptr[1:]
-		asmando(ctxt, p, &p.To, int(o.op[z+1]))
-
-	case Zcallindreg:
-		r = obj.Addrel(ctxt.Cursym)
-		r.Off = int32(p.Pc)
-		r.Type = obj.R_CALLIND
-		r.Siz = 0
-		fallthrough
-
-		// fallthrough
-	case Zo_m64:
-		ctxt.Andptr[0] = byte(op)
-		ctxt.Andptr = ctxt.Andptr[1:]
-
-		asmandsz(ctxt, p, &p.To, int(o.op[z+1]), 0, 1)
-
-	case Zm_ibo:
-		ctxt.Andptr[0] = byte(op)
-		ctxt.Andptr = ctxt.Andptr[1:]
-		asmando(ctxt, p, &p.From, int(o.op[z+1]))
-		ctxt.Andptr[0] = byte(vaddr(ctxt, p, &p.To, nil))
-		ctxt.Andptr = ctxt.Andptr[1:]
-
-	case Zibo_m:
-		ctxt.Andptr[0] = byte(op)
-		ctxt.Andptr = ctxt.Andptr[1:]
-		asmando(ctxt, p, &p.To, int(o.op[z+1]))
-		ctxt.Andptr[0] = byte(vaddr(ctxt, p, &p.From, nil))
-		ctxt.Andptr = ctxt.Andptr[1:]
-
-	case Zibo_m_xm:
-		z = mediaop(ctxt, o, op, int(yt.zoffset), z)
-		asmando(ctxt, p, &p.To, int(o.op[z+1]))
-		ctxt.Andptr[0] = byte(vaddr(ctxt, p, &p.From, nil))
-		ctxt.Andptr = ctxt.Andptr[1:]
-
-	case Z_ib,
-		Zib_:
-		if yt.zcase == Zib_ {
-			a = &p.From
-		} else {
-			a = &p.To
-		}
-		ctxt.Andptr[0] = byte(op)
-		ctxt.Andptr = ctxt.Andptr[1:]
-		ctxt.Andptr[0] = byte(vaddr(ctxt, p, a, nil))
-		ctxt.Andptr = ctxt.Andptr[1:]
-
-	case Zib_rp:
-		ctxt.Rexflag |= regrex[p.To.Reg] & (Rxb | 0x40)
-		ctxt.Andptr[0] = byte(op + reg[p.To.Reg])
-		ctxt.Andptr = ctxt.Andptr[1:]
-		ctxt.Andptr[0] = byte(vaddr(ctxt, p, &p.From, nil))
-		ctxt.Andptr = ctxt.Andptr[1:]
-
-	case Zil_rp:
-		ctxt.Rexflag |= regrex[p.To.Reg] & Rxb
-		ctxt.Andptr[0] = byte(op + reg[p.To.Reg])
-		ctxt.Andptr = ctxt.Andptr[1:]
-		if o.prefix == Pe {
-			v = vaddr(ctxt, p, &p.From, nil)
-			ctxt.Andptr[0] = byte(v)
-			ctxt.Andptr = ctxt.Andptr[1:]
-			ctxt.Andptr[0] = byte(v >> 8)
-			ctxt.Andptr = ctxt.Andptr[1:]
-		} else {
-			relput4(ctxt, p, &p.From)
-		}
-
-	case Zo_iw:
-		ctxt.Andptr[0] = byte(op)
-		ctxt.Andptr = ctxt.Andptr[1:]
-		if p.From.Type != obj.TYPE_NONE {
-			v = vaddr(ctxt, p, &p.From, nil)
-			ctxt.Andptr[0] = byte(v)
-			ctxt.Andptr = ctxt.Andptr[1:]
-			ctxt.Andptr[0] = byte(v >> 8)
-			ctxt.Andptr = ctxt.Andptr[1:]
-		}
-
-	case Ziq_rp:
-		v = vaddr(ctxt, p, &p.From, &rel)
-		l = int(v >> 32)
-		if l == 0 && rel.Siz != 8 {
-			//p->mark |= 0100;
-			//print("zero: %llux %P\n", v, p);
-			ctxt.Rexflag &^= (0x40 | Rxw)
-
-			ctxt.Rexflag |= regrex[p.To.Reg] & Rxb
-			ctxt.Andptr[0] = byte(0xb8 + reg[p.To.Reg])
-			ctxt.Andptr = ctxt.Andptr[1:]
-			if rel.Type != 0 {
-				r = obj.Addrel(ctxt.Cursym)
-				*r = rel
-				r.Off = int32(p.Pc + int64(-cap(ctxt.Andptr)+cap(ctxt.And[:])))
-			}
-
-			put4(ctxt, int32(v))
-		} else if l == -1 && uint64(v)&(uint64(1)<<31) != 0 { /* sign extend */
-
-			//p->mark |= 0100;
-			//print("sign: %llux %P\n", v, p);
-			ctxt.Andptr[0] = 0xc7
-			ctxt.Andptr = ctxt.Andptr[1:]
-
-			asmando(ctxt, p, &p.To, 0)
-			put4(ctxt, int32(v)) /* need all 8 */
-		} else {
-			//print("all: %llux %P\n", v, p);
-			ctxt.Rexflag |= regrex[p.To.Reg] & Rxb
-
-			ctxt.Andptr[0] = byte(op + reg[p.To.Reg])
-			ctxt.Andptr = ctxt.Andptr[1:]
-			if rel.Type != 0 {
-				r = obj.Addrel(ctxt.Cursym)
-				*r = rel
-				r.Off = int32(p.Pc + int64(-cap(ctxt.Andptr)+cap(ctxt.And[:])))
-			}
-
-			put8(ctxt, v)
-		}
-
-	case Zib_rr:
-		ctxt.Andptr[0] = byte(op)
-		ctxt.Andptr = ctxt.Andptr[1:]
-		asmand(ctxt, p, &p.To, &p.To)
-		ctxt.Andptr[0] = byte(vaddr(ctxt, p, &p.From, nil))
-		ctxt.Andptr = ctxt.Andptr[1:]
-
-	case Z_il,
-		Zil_:
-		if yt.zcase == Zil_ {
-			a = &p.From
-		} else {
-			a = &p.To
-		}
-		ctxt.Andptr[0] = byte(op)
-		ctxt.Andptr = ctxt.Andptr[1:]
-		if o.prefix == Pe {
-			v = vaddr(ctxt, p, a, nil)
-			ctxt.Andptr[0] = byte(v)
-			ctxt.Andptr = ctxt.Andptr[1:]
-			ctxt.Andptr[0] = byte(v >> 8)
-			ctxt.Andptr = ctxt.Andptr[1:]
-		} else {
-			relput4(ctxt, p, a)
-		}
-
-	case Zm_ilo,
-		Zilo_m:
-		ctxt.Andptr[0] = byte(op)
-		ctxt.Andptr = ctxt.Andptr[1:]
-		if yt.zcase == Zilo_m {
-			a = &p.From
-			asmando(ctxt, p, &p.To, int(o.op[z+1]))
-		} else {
-			a = &p.To
-			asmando(ctxt, p, &p.From, int(o.op[z+1]))
-		}
-
-		if o.prefix == Pe {
-			v = vaddr(ctxt, p, a, nil)
-			ctxt.Andptr[0] = byte(v)
-			ctxt.Andptr = ctxt.Andptr[1:]
-			ctxt.Andptr[0] = byte(v >> 8)
-			ctxt.Andptr = ctxt.Andptr[1:]
-		} else {
-			relput4(ctxt, p, a)
-		}
-
-	case Zil_rr:
-		ctxt.Andptr[0] = byte(op)
-		ctxt.Andptr = ctxt.Andptr[1:]
-		asmand(ctxt, p, &p.To, &p.To)
-		if o.prefix == Pe {
-			v = vaddr(ctxt, p, &p.From, nil)
-			ctxt.Andptr[0] = byte(v)
-			ctxt.Andptr = ctxt.Andptr[1:]
-			ctxt.Andptr[0] = byte(v >> 8)
-			ctxt.Andptr = ctxt.Andptr[1:]
-		} else {
-			relput4(ctxt, p, &p.From)
-		}
-
-	case Z_rp:
-		ctxt.Rexflag |= regrex[p.To.Reg] & (Rxb | 0x40)
-		ctxt.Andptr[0] = byte(op + reg[p.To.Reg])
-		ctxt.Andptr = ctxt.Andptr[1:]
-
-	case Zrp_:
-		ctxt.Rexflag |= regrex[p.From.Reg] & (Rxb | 0x40)
-		ctxt.Andptr[0] = byte(op + reg[p.From.Reg])
-		ctxt.Andptr = ctxt.Andptr[1:]
-
-	case Zclr:
-		ctxt.Rexflag &^= Pw
-		ctxt.Andptr[0] = byte(op)
-		ctxt.Andptr = ctxt.Andptr[1:]
-		asmand(ctxt, p, &p.To, &p.To)
-
-	case Zcall:
-		if p.To.Sym == nil {
-			ctxt.Diag("call without target")
-			log.Fatalf("bad code")
-		}
-
-		ctxt.Andptr[0] = byte(op)
-		ctxt.Andptr = ctxt.Andptr[1:]
-		r = obj.Addrel(ctxt.Cursym)
-		r.Off = int32(p.Pc + int64(-cap(ctxt.Andptr)+cap(ctxt.And[:])))
-		r.Sym = p.To.Sym
-		r.Add = p.To.Offset
-		r.Type = obj.R_CALL
-		r.Siz = 4
-		put4(ctxt, 0)
-
-		// TODO: jump across functions needs reloc
-	case Zbr,
-		Zjmp,
-		Zloop:
-		if p.To.Sym != nil {
-			if yt.zcase != Zjmp {
-				ctxt.Diag("branch to ATEXT")
-				log.Fatalf("bad code")
-			}
-
-			ctxt.Andptr[0] = byte(o.op[z+1])
-			ctxt.Andptr = ctxt.Andptr[1:]
-			r = obj.Addrel(ctxt.Cursym)
-			r.Off = int32(p.Pc + int64(-cap(ctxt.Andptr)+cap(ctxt.And[:])))
-			r.Sym = p.To.Sym
-			r.Type = obj.R_PCREL
-			r.Siz = 4
-			put4(ctxt, 0)
-			break
-		}
-
-		// Assumes q is in this function.
-		// TODO: Check in input, preserve in brchain.
-
-		// Fill in backward jump now.
-		q = p.Pcond
-
-		if q == nil {
-			ctxt.Diag("jmp/branch/loop without target")
-			log.Fatalf("bad code")
-		}
-
-		if p.Back&1 != 0 {
-			v = q.Pc - (p.Pc + 2)
-			if v >= -128 {
-				if p.As == AJCXZL {
-					ctxt.Andptr[0] = 0x67
+			case Zlit:
+				for ; ; z++ {
+					op = int(o.op[z])
+					if op == 0 {
+						break
+					}
+					ctxt.Andptr[0] = byte(op)
 					ctxt.Andptr = ctxt.Andptr[1:]
 				}
+
+			case Zlitm_r:
+				for ; ; z++ {
+					op = int(o.op[z])
+					if op == 0 {
+						break
+					}
+					ctxt.Andptr[0] = byte(op)
+					ctxt.Andptr = ctxt.Andptr[1:]
+				}
+				asmand(ctxt, p, &p.From, &p.To)
+
+			case Zmb_r:
+				bytereg(&p.From, &p.Ft)
+				fallthrough
+
+				/* fall through */
+			case Zm_r:
+				ctxt.Andptr[0] = byte(op)
+				ctxt.Andptr = ctxt.Andptr[1:]
+
+				asmand(ctxt, p, &p.From, &p.To)
+
+			case Zm2_r:
+				ctxt.Andptr[0] = byte(op)
+				ctxt.Andptr = ctxt.Andptr[1:]
+				ctxt.Andptr[0] = byte(o.op[z+1])
+				ctxt.Andptr = ctxt.Andptr[1:]
+				asmand(ctxt, p, &p.From, &p.To)
+
+			case Zm_r_xm:
+				mediaop(ctxt, o, op, int(yt.zoffset), z)
+				asmand(ctxt, p, &p.From, &p.To)
+
+			case Zm_r_xm_nr:
+				ctxt.Rexflag = 0
+				mediaop(ctxt, o, op, int(yt.zoffset), z)
+				asmand(ctxt, p, &p.From, &p.To)
+
+			case Zm_r_i_xm:
+				mediaop(ctxt, o, op, int(yt.zoffset), z)
+				asmand(ctxt, p, &p.From, &p.From3)
+				ctxt.Andptr[0] = byte(p.To.Offset)
+				ctxt.Andptr = ctxt.Andptr[1:]
+
+			case Zm_r_3d:
+				ctxt.Andptr[0] = 0x0f
+				ctxt.Andptr = ctxt.Andptr[1:]
+				ctxt.Andptr[0] = 0x0f
+				ctxt.Andptr = ctxt.Andptr[1:]
+				asmand(ctxt, p, &p.From, &p.To)
+				ctxt.Andptr[0] = byte(op)
+				ctxt.Andptr = ctxt.Andptr[1:]
+
+			case Zibm_r:
+				for {
+					tmp1 := z
+					z++
+					op = int(o.op[tmp1])
+					if op == 0 {
+						break
+					}
+					ctxt.Andptr[0] = byte(op)
+					ctxt.Andptr = ctxt.Andptr[1:]
+				}
+				asmand(ctxt, p, &p.From3, &p.To)
+				ctxt.Andptr[0] = byte(p.From.Offset)
+				ctxt.Andptr = ctxt.Andptr[1:]
+
+			case Zaut_r:
+				ctxt.Andptr[0] = 0x8d
+				ctxt.Andptr = ctxt.Andptr[1:] /* leal */
+				if p.From.Type != obj.TYPE_ADDR {
+					ctxt.Diag("asmins: Zaut sb type ADDR")
+				}
+				p.From.Type = obj.TYPE_MEM
+				asmand(ctxt, p, &p.From, &p.To)
+				p.From.Type = obj.TYPE_ADDR
+
+			case Zm_o:
+				ctxt.Andptr[0] = byte(op)
+				ctxt.Andptr = ctxt.Andptr[1:]
+				asmando(ctxt, p, &p.From, int(o.op[z+1]))
+
+			case Zr_m:
+				ctxt.Andptr[0] = byte(op)
+				ctxt.Andptr = ctxt.Andptr[1:]
+				asmand(ctxt, p, &p.To, &p.From)
+
+			case Zr_m_xm:
+				mediaop(ctxt, o, op, int(yt.zoffset), z)
+				asmand(ctxt, p, &p.To, &p.From)
+
+			case Zr_m_xm_nr:
+				ctxt.Rexflag = 0
+				mediaop(ctxt, o, op, int(yt.zoffset), z)
+				asmand(ctxt, p, &p.To, &p.From)
+
+			case Zo_m:
+				ctxt.Andptr[0] = byte(op)
+				ctxt.Andptr = ctxt.Andptr[1:]
+				asmando(ctxt, p, &p.To, int(o.op[z+1]))
+
+			case Zcallindreg:
+				r = obj.Addrel(ctxt.Cursym)
+				r.Off = int32(p.Pc)
+				r.Type = obj.R_CALLIND
+				r.Siz = 0
+				fallthrough
+
+			case Zo_m64:
+				ctxt.Andptr[0] = byte(op)
+				ctxt.Andptr = ctxt.Andptr[1:]
+				asmandsz(ctxt, p, &p.To, int(o.op[z+1]), 0, 1)
+
+			case Zm_ibo:
+				ctxt.Andptr[0] = byte(op)
+				ctxt.Andptr = ctxt.Andptr[1:]
+				asmando(ctxt, p, &p.From, int(o.op[z+1]))
+				ctxt.Andptr[0] = byte(vaddr(ctxt, p, &p.To, nil))
+				ctxt.Andptr = ctxt.Andptr[1:]
+
+			case Zibo_m:
+				ctxt.Andptr[0] = byte(op)
+				ctxt.Andptr = ctxt.Andptr[1:]
+				asmando(ctxt, p, &p.To, int(o.op[z+1]))
+				ctxt.Andptr[0] = byte(vaddr(ctxt, p, &p.From, nil))
+				ctxt.Andptr = ctxt.Andptr[1:]
+
+			case Zibo_m_xm:
+				z = mediaop(ctxt, o, op, int(yt.zoffset), z)
+				asmando(ctxt, p, &p.To, int(o.op[z+1]))
+				ctxt.Andptr[0] = byte(vaddr(ctxt, p, &p.From, nil))
+				ctxt.Andptr = ctxt.Andptr[1:]
+
+			case Z_ib, Zib_:
+				if yt.zcase == Zib_ {
+					a = &p.From
+				} else {
+					a = &p.To
+				}
 				ctxt.Andptr[0] = byte(op)
 				ctxt.Andptr = ctxt.Andptr[1:]
-				ctxt.Andptr[0] = byte(v)
+				ctxt.Andptr[0] = byte(vaddr(ctxt, p, a, nil))
 				ctxt.Andptr = ctxt.Andptr[1:]
-			} else if yt.zcase == Zloop {
-				ctxt.Diag("loop too far: %v", p)
-			} else {
-				v -= 5 - 2
-				if yt.zcase == Zbr {
-					ctxt.Andptr[0] = 0x0f
+
+			case Zib_rp:
+				ctxt.Rexflag |= regrex[p.To.Reg] & (Rxb | 0x40)
+				ctxt.Andptr[0] = byte(op + reg[p.To.Reg])
+				ctxt.Andptr = ctxt.Andptr[1:]
+				ctxt.Andptr[0] = byte(vaddr(ctxt, p, &p.From, nil))
+				ctxt.Andptr = ctxt.Andptr[1:]
+
+			case Zil_rp:
+				ctxt.Rexflag |= regrex[p.To.Reg] & Rxb
+				ctxt.Andptr[0] = byte(op + reg[p.To.Reg])
+				ctxt.Andptr = ctxt.Andptr[1:]
+				if o.prefix == Pe {
+					v = vaddr(ctxt, p, &p.From, nil)
+					ctxt.Andptr[0] = byte(v)
 					ctxt.Andptr = ctxt.Andptr[1:]
-					v--
+					ctxt.Andptr[0] = byte(v >> 8)
+					ctxt.Andptr = ctxt.Andptr[1:]
+				} else {
+					relput4(ctxt, p, &p.From)
 				}
 
+			case Zo_iw:
+				ctxt.Andptr[0] = byte(op)
+				ctxt.Andptr = ctxt.Andptr[1:]
+				if p.From.Type != obj.TYPE_NONE {
+					v = vaddr(ctxt, p, &p.From, nil)
+					ctxt.Andptr[0] = byte(v)
+					ctxt.Andptr = ctxt.Andptr[1:]
+					ctxt.Andptr[0] = byte(v >> 8)
+					ctxt.Andptr = ctxt.Andptr[1:]
+				}
+
+			case Ziq_rp:
+				v = vaddr(ctxt, p, &p.From, &rel)
+				l = int(v >> 32)
+				if l == 0 && rel.Siz != 8 {
+					//p->mark |= 0100;
+					//print("zero: %llux %P\n", v, p);
+					ctxt.Rexflag &^= (0x40 | Rxw)
+
+					ctxt.Rexflag |= regrex[p.To.Reg] & Rxb
+					ctxt.Andptr[0] = byte(0xb8 + reg[p.To.Reg])
+					ctxt.Andptr = ctxt.Andptr[1:]
+					if rel.Type != 0 {
+						r = obj.Addrel(ctxt.Cursym)
+						*r = rel
+						r.Off = int32(p.Pc + int64(-cap(ctxt.Andptr)+cap(ctxt.And[:])))
+					}
+
+					put4(ctxt, int32(v))
+				} else if l == -1 && uint64(v)&(uint64(1)<<31) != 0 { /* sign extend */
+
+					//p->mark |= 0100;
+					//print("sign: %llux %P\n", v, p);
+					ctxt.Andptr[0] = 0xc7
+					ctxt.Andptr = ctxt.Andptr[1:]
+
+					asmando(ctxt, p, &p.To, 0)
+					put4(ctxt, int32(v)) /* need all 8 */
+				} else {
+					//print("all: %llux %P\n", v, p);
+					ctxt.Rexflag |= regrex[p.To.Reg] & Rxb
+
+					ctxt.Andptr[0] = byte(op + reg[p.To.Reg])
+					ctxt.Andptr = ctxt.Andptr[1:]
+					if rel.Type != 0 {
+						r = obj.Addrel(ctxt.Cursym)
+						*r = rel
+						r.Off = int32(p.Pc + int64(-cap(ctxt.Andptr)+cap(ctxt.And[:])))
+					}
+
+					put8(ctxt, v)
+				}
+
+			case Zib_rr:
+				ctxt.Andptr[0] = byte(op)
+				ctxt.Andptr = ctxt.Andptr[1:]
+				asmand(ctxt, p, &p.To, &p.To)
+				ctxt.Andptr[0] = byte(vaddr(ctxt, p, &p.From, nil))
+				ctxt.Andptr = ctxt.Andptr[1:]
+
+			case Z_il, Zil_:
+				if yt.zcase == Zil_ {
+					a = &p.From
+				} else {
+					a = &p.To
+				}
+				ctxt.Andptr[0] = byte(op)
+				ctxt.Andptr = ctxt.Andptr[1:]
+				if o.prefix == Pe {
+					v = vaddr(ctxt, p, a, nil)
+					ctxt.Andptr[0] = byte(v)
+					ctxt.Andptr = ctxt.Andptr[1:]
+					ctxt.Andptr[0] = byte(v >> 8)
+					ctxt.Andptr = ctxt.Andptr[1:]
+				} else {
+					relput4(ctxt, p, a)
+				}
+
+			case Zm_ilo, Zilo_m:
+				ctxt.Andptr[0] = byte(op)
+				ctxt.Andptr = ctxt.Andptr[1:]
+				if yt.zcase == Zilo_m {
+					a = &p.From
+					asmando(ctxt, p, &p.To, int(o.op[z+1]))
+				} else {
+					a = &p.To
+					asmando(ctxt, p, &p.From, int(o.op[z+1]))
+				}
+
+				if o.prefix == Pe {
+					v = vaddr(ctxt, p, a, nil)
+					ctxt.Andptr[0] = byte(v)
+					ctxt.Andptr = ctxt.Andptr[1:]
+					ctxt.Andptr[0] = byte(v >> 8)
+					ctxt.Andptr = ctxt.Andptr[1:]
+				} else {
+					relput4(ctxt, p, a)
+				}
+
+			case Zil_rr:
+				ctxt.Andptr[0] = byte(op)
+				ctxt.Andptr = ctxt.Andptr[1:]
+				asmand(ctxt, p, &p.To, &p.To)
+				if o.prefix == Pe {
+					v = vaddr(ctxt, p, &p.From, nil)
+					ctxt.Andptr[0] = byte(v)
+					ctxt.Andptr = ctxt.Andptr[1:]
+					ctxt.Andptr[0] = byte(v >> 8)
+					ctxt.Andptr = ctxt.Andptr[1:]
+				} else {
+					relput4(ctxt, p, &p.From)
+				}
+
+			case Z_rp:
+				ctxt.Rexflag |= regrex[p.To.Reg] & (Rxb | 0x40)
+				ctxt.Andptr[0] = byte(op + reg[p.To.Reg])
+				ctxt.Andptr = ctxt.Andptr[1:]
+
+			case Zrp_:
+				ctxt.Rexflag |= regrex[p.From.Reg] & (Rxb | 0x40)
+				ctxt.Andptr[0] = byte(op + reg[p.From.Reg])
+				ctxt.Andptr = ctxt.Andptr[1:]
+
+			case Zclr:
+				ctxt.Rexflag &^= Pw
+				ctxt.Andptr[0] = byte(op)
+				ctxt.Andptr = ctxt.Andptr[1:]
+				asmand(ctxt, p, &p.To, &p.To)
+
+			case Zcallcon, Zjmpcon:
+				if yt.zcase == Zcallcon {
+					ctxt.Andptr[0] = byte(op)
+					ctxt.Andptr = ctxt.Andptr[1:]
+				} else {
+					ctxt.Andptr[0] = byte(o.op[z+1])
+					ctxt.Andptr = ctxt.Andptr[1:]
+				}
+				r = obj.Addrel(ctxt.Cursym)
+				r.Off = int32(p.Pc + int64(-cap(ctxt.Andptr)+cap(ctxt.And[:])))
+				r.Type = obj.R_PCREL
+				r.Siz = 4
+				r.Add = p.To.Offset
+				put4(ctxt, 0)
+
+			case Zcallind:
+				ctxt.Andptr[0] = byte(op)
+				ctxt.Andptr = ctxt.Andptr[1:]
 				ctxt.Andptr[0] = byte(o.op[z+1])
 				ctxt.Andptr = ctxt.Andptr[1:]
+				r = obj.Addrel(ctxt.Cursym)
+				r.Off = int32(p.Pc + int64(-cap(ctxt.Andptr)+cap(ctxt.And[:])))
+				r.Type = obj.R_ADDR
+				r.Siz = 4
+				r.Add = p.To.Offset
+				r.Sym = p.To.Sym
+				put4(ctxt, 0)
+
+			case Zcall, Zcallduff:
+				if p.To.Sym == nil {
+					ctxt.Diag("call without target")
+					log.Fatalf("bad code")
+				}
+
+				if obj.Framepointer_enabled != 0 && yt.zcase == Zcallduff && p.Mode == 64 {
+					// Maintain BP around call, since duffcopy/duffzero can't do it
+					// (the call jumps into the middle of the function).
+					// This makes it possible to see call sites for duffcopy/duffzero in
+					// BP-based profiling tools like Linux perf (which is the
+					// whole point of obj.Framepointer_enabled).
+					// MOVQ BP, -16(SP)
+					// LEAQ -16(SP), BP
+					copy(ctxt.Andptr, bpduff1)
+					ctxt.Andptr = ctxt.Andptr[len(bpduff1):]
+				}
+				ctxt.Andptr[0] = byte(op)
+				ctxt.Andptr = ctxt.Andptr[1:]
+				r = obj.Addrel(ctxt.Cursym)
+				r.Off = int32(p.Pc + int64(-cap(ctxt.Andptr)+cap(ctxt.And[:])))
+				r.Sym = p.To.Sym
+				r.Add = p.To.Offset
+				r.Type = obj.R_CALL
+				r.Siz = 4
+				put4(ctxt, 0)
+
+				if obj.Framepointer_enabled != 0 && yt.zcase == Zcallduff && p.Mode == 64 {
+					// Pop BP pushed above.
+					// MOVQ 0(BP), BP
+					copy(ctxt.Andptr, bpduff2)
+					ctxt.Andptr = ctxt.Andptr[len(bpduff2):]
+				}
+
+			// TODO: jump across functions needs reloc
+			case Zbr, Zjmp, Zloop:
+				if p.To.Sym != nil {
+					if yt.zcase != Zjmp {
+						ctxt.Diag("branch to ATEXT")
+						log.Fatalf("bad code")
+					}
+
+					ctxt.Andptr[0] = byte(o.op[z+1])
+					ctxt.Andptr = ctxt.Andptr[1:]
+					r = obj.Addrel(ctxt.Cursym)
+					r.Off = int32(p.Pc + int64(-cap(ctxt.Andptr)+cap(ctxt.And[:])))
+					r.Sym = p.To.Sym
+					r.Type = obj.R_PCREL
+					r.Siz = 4
+					put4(ctxt, 0)
+					break
+				}
+
+				// Assumes q is in this function.
+				// TODO: Check in input, preserve in brchain.
+
+				// Fill in backward jump now.
+				q = p.Pcond
+
+				if q == nil {
+					ctxt.Diag("jmp/branch/loop without target")
+					log.Fatalf("bad code")
+				}
+
+				if p.Back&1 != 0 {
+					v = q.Pc - (p.Pc + 2)
+					if v >= -128 {
+						if p.As == AJCXZL {
+							ctxt.Andptr[0] = 0x67
+							ctxt.Andptr = ctxt.Andptr[1:]
+						}
+						ctxt.Andptr[0] = byte(op)
+						ctxt.Andptr = ctxt.Andptr[1:]
+						ctxt.Andptr[0] = byte(v)
+						ctxt.Andptr = ctxt.Andptr[1:]
+					} else if yt.zcase == Zloop {
+						ctxt.Diag("loop too far: %v", p)
+					} else {
+						v -= 5 - 2
+						if yt.zcase == Zbr {
+							ctxt.Andptr[0] = 0x0f
+							ctxt.Andptr = ctxt.Andptr[1:]
+							v--
+						}
+
+						ctxt.Andptr[0] = byte(o.op[z+1])
+						ctxt.Andptr = ctxt.Andptr[1:]
+						ctxt.Andptr[0] = byte(v)
+						ctxt.Andptr = ctxt.Andptr[1:]
+						ctxt.Andptr[0] = byte(v >> 8)
+						ctxt.Andptr = ctxt.Andptr[1:]
+						ctxt.Andptr[0] = byte(v >> 16)
+						ctxt.Andptr = ctxt.Andptr[1:]
+						ctxt.Andptr[0] = byte(v >> 24)
+						ctxt.Andptr = ctxt.Andptr[1:]
+					}
+
+					break
+				}
+
+				// Annotate target; will fill in later.
+				p.Forwd = q.Comefrom
+
+				q.Comefrom = p
+				if p.Back&2 != 0 { // short
+					if p.As == AJCXZL {
+						ctxt.Andptr[0] = 0x67
+						ctxt.Andptr = ctxt.Andptr[1:]
+					}
+					ctxt.Andptr[0] = byte(op)
+					ctxt.Andptr = ctxt.Andptr[1:]
+					ctxt.Andptr[0] = 0
+					ctxt.Andptr = ctxt.Andptr[1:]
+				} else if yt.zcase == Zloop {
+					ctxt.Diag("loop too far: %v", p)
+				} else {
+					if yt.zcase == Zbr {
+						ctxt.Andptr[0] = 0x0f
+						ctxt.Andptr = ctxt.Andptr[1:]
+					}
+					ctxt.Andptr[0] = byte(o.op[z+1])
+					ctxt.Andptr = ctxt.Andptr[1:]
+					ctxt.Andptr[0] = 0
+					ctxt.Andptr = ctxt.Andptr[1:]
+					ctxt.Andptr[0] = 0
+					ctxt.Andptr = ctxt.Andptr[1:]
+					ctxt.Andptr[0] = 0
+					ctxt.Andptr = ctxt.Andptr[1:]
+					ctxt.Andptr[0] = 0
+					ctxt.Andptr = ctxt.Andptr[1:]
+				}
+
+				break
+
+			/*
+				v = q->pc - p->pc - 2;
+				if((v >= -128 && v <= 127) || p->pc == -1 || q->pc == -1) {
+					*ctxt->andptr++ = op;
+					*ctxt->andptr++ = v;
+				} else {
+					v -= 5-2;
+					if(yt.zcase == Zbr) {
+						*ctxt->andptr++ = 0x0f;
+						v--;
+					}
+					*ctxt->andptr++ = o->op[z+1];
+					*ctxt->andptr++ = v;
+					*ctxt->andptr++ = v>>8;
+					*ctxt->andptr++ = v>>16;
+					*ctxt->andptr++ = v>>24;
+				}
+			*/
+
+			case Zbyte:
+				v = vaddr(ctxt, p, &p.From, &rel)
+				if rel.Siz != 0 {
+					rel.Siz = uint8(op)
+					r = obj.Addrel(ctxt.Cursym)
+					*r = rel
+					r.Off = int32(p.Pc + int64(-cap(ctxt.Andptr)+cap(ctxt.And[:])))
+				}
+
 				ctxt.Andptr[0] = byte(v)
 				ctxt.Andptr = ctxt.Andptr[1:]
-				ctxt.Andptr[0] = byte(v >> 8)
-				ctxt.Andptr = ctxt.Andptr[1:]
-				ctxt.Andptr[0] = byte(v >> 16)
-				ctxt.Andptr = ctxt.Andptr[1:]
-				ctxt.Andptr[0] = byte(v >> 24)
-				ctxt.Andptr = ctxt.Andptr[1:]
-			}
-
-			break
-		}
-
-		// Annotate target; will fill in later.
-		p.Forwd = q.Comefrom
-
-		q.Comefrom = p
-		if p.Back&2 != 0 { // short
-			if p.As == AJCXZL {
-				ctxt.Andptr[0] = 0x67
-				ctxt.Andptr = ctxt.Andptr[1:]
-			}
-			ctxt.Andptr[0] = byte(op)
-			ctxt.Andptr = ctxt.Andptr[1:]
-			ctxt.Andptr[0] = 0
-			ctxt.Andptr = ctxt.Andptr[1:]
-		} else if yt.zcase == Zloop {
-			ctxt.Diag("loop too far: %v", p)
-		} else {
-			if yt.zcase == Zbr {
-				ctxt.Andptr[0] = 0x0f
-				ctxt.Andptr = ctxt.Andptr[1:]
-			}
-			ctxt.Andptr[0] = byte(o.op[z+1])
-			ctxt.Andptr = ctxt.Andptr[1:]
-			ctxt.Andptr[0] = 0
-			ctxt.Andptr = ctxt.Andptr[1:]
-			ctxt.Andptr[0] = 0
-			ctxt.Andptr = ctxt.Andptr[1:]
-			ctxt.Andptr[0] = 0
-			ctxt.Andptr = ctxt.Andptr[1:]
-			ctxt.Andptr[0] = 0
-			ctxt.Andptr = ctxt.Andptr[1:]
-		}
-
-		break
-
-	/*
-		v = q->pc - p->pc - 2;
-		if((v >= -128 && v <= 127) || p->pc == -1 || q->pc == -1) {
-			*ctxt->andptr++ = op;
-			*ctxt->andptr++ = v;
-		} else {
-			v -= 5-2;
-			if(yt.zcase == Zbr) {
-				*ctxt->andptr++ = 0x0f;
-				v--;
-			}
-			*ctxt->andptr++ = o->op[z+1];
-			*ctxt->andptr++ = v;
-			*ctxt->andptr++ = v>>8;
-			*ctxt->andptr++ = v>>16;
-			*ctxt->andptr++ = v>>24;
-		}
-	*/
-
-	case Zbyte:
-		v = vaddr(ctxt, p, &p.From, &rel)
-		if rel.Siz != 0 {
-			rel.Siz = uint8(op)
-			r = obj.Addrel(ctxt.Cursym)
-			*r = rel
-			r.Off = int32(p.Pc + int64(-cap(ctxt.Andptr)+cap(ctxt.And[:])))
-		}
-
-		ctxt.Andptr[0] = byte(v)
-		ctxt.Andptr = ctxt.Andptr[1:]
-		if op > 1 {
-			ctxt.Andptr[0] = byte(v >> 8)
-			ctxt.Andptr = ctxt.Andptr[1:]
-			if op > 2 {
-				ctxt.Andptr[0] = byte(v >> 16)
-				ctxt.Andptr = ctxt.Andptr[1:]
-				ctxt.Andptr[0] = byte(v >> 24)
-				ctxt.Andptr = ctxt.Andptr[1:]
-				if op > 4 {
-					ctxt.Andptr[0] = byte(v >> 32)
+				if op > 1 {
+					ctxt.Andptr[0] = byte(v >> 8)
 					ctxt.Andptr = ctxt.Andptr[1:]
-					ctxt.Andptr[0] = byte(v >> 40)
-					ctxt.Andptr = ctxt.Andptr[1:]
-					ctxt.Andptr[0] = byte(v >> 48)
-					ctxt.Andptr = ctxt.Andptr[1:]
-					ctxt.Andptr[0] = byte(v >> 56)
-					ctxt.Andptr = ctxt.Andptr[1:]
+					if op > 2 {
+						ctxt.Andptr[0] = byte(v >> 16)
+						ctxt.Andptr = ctxt.Andptr[1:]
+						ctxt.Andptr[0] = byte(v >> 24)
+						ctxt.Andptr = ctxt.Andptr[1:]
+						if op > 4 {
+							ctxt.Andptr[0] = byte(v >> 32)
+							ctxt.Andptr = ctxt.Andptr[1:]
+							ctxt.Andptr[0] = byte(v >> 40)
+							ctxt.Andptr = ctxt.Andptr[1:]
+							ctxt.Andptr[0] = byte(v >> 48)
+							ctxt.Andptr = ctxt.Andptr[1:]
+							ctxt.Andptr[0] = byte(v >> 56)
+							ctxt.Andptr = ctxt.Andptr[1:]
+						}
+					}
 				}
 			}
+
+			return
 		}
+		z += int(yt.zoffset) + xo
 	}
-
-	return
-
-domov:
-	for mo = ymovtab; mo[0].as != 0; mo = mo[1:] {
+	for mo := ymovtab; mo[0].as != 0; mo = mo[1:] {
+		var pp obj.Prog
+		var t []byte
 		if p.As == mo[0].as {
-			if ycover[ft+int(mo[0].ft)] != 0 {
-				if ycover[tt+int(mo[0].tt)] != 0 {
-					t = mo[0].op[:]
-					goto mfound
+			if ycover[ft+int(mo[0].ft)] != 0 && ycover[f3t+int(mo[0].f3t)] != 0 && ycover[tt+int(mo[0].tt)] != 0 {
+				t = mo[0].op[:]
+				switch mo[0].code {
+				default:
+					ctxt.Diag("asmins: unknown mov %d %v", mo[0].code, p)
+
+				case 0: /* lit */
+					for z = 0; t[z] != E; z++ {
+						ctxt.Andptr[0] = t[z]
+						ctxt.Andptr = ctxt.Andptr[1:]
+					}
+
+				case 1: /* r,m */
+					ctxt.Andptr[0] = t[0]
+					ctxt.Andptr = ctxt.Andptr[1:]
+
+					asmando(ctxt, p, &p.To, int(t[1]))
+
+				case 2: /* m,r */
+					ctxt.Andptr[0] = t[0]
+					ctxt.Andptr = ctxt.Andptr[1:]
+
+					asmando(ctxt, p, &p.From, int(t[1]))
+
+				case 3: /* r,m - 2op */
+					ctxt.Andptr[0] = t[0]
+					ctxt.Andptr = ctxt.Andptr[1:]
+
+					ctxt.Andptr[0] = t[1]
+					ctxt.Andptr = ctxt.Andptr[1:]
+					asmando(ctxt, p, &p.To, int(t[2]))
+					ctxt.Rexflag |= regrex[p.From.Reg] & (Rxr | 0x40)
+
+				case 4: /* m,r - 2op */
+					ctxt.Andptr[0] = t[0]
+					ctxt.Andptr = ctxt.Andptr[1:]
+
+					ctxt.Andptr[0] = t[1]
+					ctxt.Andptr = ctxt.Andptr[1:]
+					asmando(ctxt, p, &p.From, int(t[2]))
+					ctxt.Rexflag |= regrex[p.To.Reg] & (Rxr | 0x40)
+
+				case 5: /* load full pointer, trash heap */
+					if t[0] != 0 {
+						ctxt.Andptr[0] = t[0]
+						ctxt.Andptr = ctxt.Andptr[1:]
+					}
+					switch p.To.Index {
+					default:
+						goto bad
+
+					case REG_DS:
+						ctxt.Andptr[0] = 0xc5
+						ctxt.Andptr = ctxt.Andptr[1:]
+
+					case REG_SS:
+						ctxt.Andptr[0] = 0x0f
+						ctxt.Andptr = ctxt.Andptr[1:]
+						ctxt.Andptr[0] = 0xb2
+						ctxt.Andptr = ctxt.Andptr[1:]
+
+					case REG_ES:
+						ctxt.Andptr[0] = 0xc4
+						ctxt.Andptr = ctxt.Andptr[1:]
+
+					case REG_FS:
+						ctxt.Andptr[0] = 0x0f
+						ctxt.Andptr = ctxt.Andptr[1:]
+						ctxt.Andptr[0] = 0xb4
+						ctxt.Andptr = ctxt.Andptr[1:]
+
+					case REG_GS:
+						ctxt.Andptr[0] = 0x0f
+						ctxt.Andptr = ctxt.Andptr[1:]
+						ctxt.Andptr[0] = 0xb5
+						ctxt.Andptr = ctxt.Andptr[1:]
+					}
+
+					asmand(ctxt, p, &p.From, &p.To)
+
+				case 6: /* double shift */
+					if t[0] == Pw {
+						if p.Mode != 64 {
+							ctxt.Diag("asmins: illegal 64: %v", p)
+						}
+						ctxt.Rexflag |= Pw
+						t = t[1:]
+					} else if t[0] == Pe {
+						ctxt.Andptr[0] = Pe
+						ctxt.Andptr = ctxt.Andptr[1:]
+						t = t[1:]
+					}
+
+					switch p.From.Type {
+					default:
+						goto bad
+
+					case obj.TYPE_CONST:
+						ctxt.Andptr[0] = 0x0f
+						ctxt.Andptr = ctxt.Andptr[1:]
+						ctxt.Andptr[0] = t[0]
+						ctxt.Andptr = ctxt.Andptr[1:]
+						asmandsz(ctxt, p, &p.To, reg[p.From3.Reg], regrex[p.From3.Reg], 0)
+						ctxt.Andptr[0] = byte(p.From.Offset)
+						ctxt.Andptr = ctxt.Andptr[1:]
+
+					case obj.TYPE_REG:
+						switch p.From.Reg {
+						default:
+							goto bad
+
+						case REG_CL, REG_CX:
+							ctxt.Andptr[0] = 0x0f
+							ctxt.Andptr = ctxt.Andptr[1:]
+							ctxt.Andptr[0] = t[1]
+							ctxt.Andptr = ctxt.Andptr[1:]
+							asmandsz(ctxt, p, &p.To, reg[p.From3.Reg], regrex[p.From3.Reg], 0)
+						}
+					}
+
+				// NOTE: The systems listed here are the ones that use the "TLS initial exec" model,
+				// where you load the TLS base register into a register and then index off that
+				// register to access the actual TLS variables. Systems that allow direct TLS access
+				// are handled in prefixof above and should not be listed here.
+				case 7: /* mov tls, r */
+					if p.Mode == 64 && p.As != AMOVQ || p.Mode == 32 && p.As != AMOVL {
+						ctxt.Diag("invalid load of TLS: %v", p)
+					}
+
+					if p.Mode == 32 {
+						// NOTE: The systems listed here are the ones that use the "TLS initial exec" model,
+						// where you load the TLS base register into a register and then index off that
+						// register to access the actual TLS variables. Systems that allow direct TLS access
+						// are handled in prefixof above and should not be listed here.
+						switch ctxt.Headtype {
+						default:
+							log.Fatalf("unknown TLS base location for %s", obj.Headstr(ctxt.Headtype))
+
+						case obj.Hlinux,
+							obj.Hnacl:
+							// ELF TLS base is 0(GS).
+							pp.From = p.From
+
+							pp.From.Type = obj.TYPE_MEM
+							pp.From.Reg = REG_GS
+							pp.From.Offset = 0
+							pp.From.Index = REG_NONE
+							pp.From.Scale = 0
+							ctxt.Andptr[0] = 0x65
+							ctxt.Andptr = ctxt.Andptr[1:] // GS
+							ctxt.Andptr[0] = 0x8B
+							ctxt.Andptr = ctxt.Andptr[1:]
+							asmand(ctxt, p, &pp.From, &p.To)
+
+						case obj.Hplan9:
+							if ctxt.Plan9privates == nil {
+								ctxt.Plan9privates = obj.Linklookup(ctxt, "_privates", 0)
+							}
+							pp.From = obj.Addr{}
+							pp.From.Type = obj.TYPE_MEM
+							pp.From.Name = obj.NAME_EXTERN
+							pp.From.Sym = ctxt.Plan9privates
+							pp.From.Offset = 0
+							pp.From.Index = REG_NONE
+							ctxt.Andptr[0] = 0x8B
+							ctxt.Andptr = ctxt.Andptr[1:]
+							asmand(ctxt, p, &pp.From, &p.To)
+
+						case obj.Hwindows:
+							// Windows TLS base is always 0x14(FS).
+							pp.From = p.From
+
+							pp.From.Type = obj.TYPE_MEM
+							pp.From.Reg = REG_FS
+							pp.From.Offset = 0x14
+							pp.From.Index = REG_NONE
+							pp.From.Scale = 0
+							ctxt.Andptr[0] = 0x64
+							ctxt.Andptr = ctxt.Andptr[1:] // FS
+							ctxt.Andptr[0] = 0x8B
+							ctxt.Andptr = ctxt.Andptr[1:]
+							asmand(ctxt, p, &pp.From, &p.To)
+						}
+						break
+					}
+
+					switch ctxt.Headtype {
+					default:
+						log.Fatalf("unknown TLS base location for %s", obj.Headstr(ctxt.Headtype))
+
+					case obj.Hlinux:
+						if ctxt.Flag_shared == 0 {
+							log.Fatalf("unknown TLS base location for linux without -shared")
+						}
+						// Note that this is not generating the same insn as the other cases.
+						//     MOV TLS, R_to
+						// becomes
+						//     movq g@gottpoff(%rip), R_to
+						// which is encoded as
+						//     movq 0(%rip), R_to
+						// and a R_TLS_IE reloc. This all assumes the only tls variable we access
+						// is g, which we can't check here, but will when we assemble the second
+						// instruction.
+						ctxt.Rexflag = Pw | (regrex[p.To.Reg] & Rxr)
+
+						ctxt.Andptr[0] = 0x8B
+						ctxt.Andptr = ctxt.Andptr[1:]
+						ctxt.Andptr[0] = byte(0x05 | (reg[p.To.Reg] << 3))
+						ctxt.Andptr = ctxt.Andptr[1:]
+						r = obj.Addrel(ctxt.Cursym)
+						r.Off = int32(p.Pc + int64(-cap(ctxt.Andptr)+cap(ctxt.And[:])))
+						r.Type = obj.R_TLS_IE
+						r.Siz = 4
+						r.Add = -4
+						put4(ctxt, 0)
+
+					case obj.Hplan9:
+						if ctxt.Plan9privates == nil {
+							ctxt.Plan9privates = obj.Linklookup(ctxt, "_privates", 0)
+						}
+						pp.From = obj.Addr{}
+						pp.From.Type = obj.TYPE_MEM
+						pp.From.Name = obj.NAME_EXTERN
+						pp.From.Sym = ctxt.Plan9privates
+						pp.From.Offset = 0
+						pp.From.Index = REG_NONE
+						ctxt.Rexflag |= Pw
+						ctxt.Andptr[0] = 0x8B
+						ctxt.Andptr = ctxt.Andptr[1:]
+						asmand(ctxt, p, &pp.From, &p.To)
+
+					case obj.Hsolaris: // TODO(rsc): Delete Hsolaris from list. Should not use this code. See progedit in obj6.c.
+						// TLS base is 0(FS).
+						pp.From = p.From
+
+						pp.From.Type = obj.TYPE_MEM
+						pp.From.Name = obj.NAME_NONE
+						pp.From.Reg = REG_NONE
+						pp.From.Offset = 0
+						pp.From.Index = REG_NONE
+						pp.From.Scale = 0
+						ctxt.Rexflag |= Pw
+						ctxt.Andptr[0] = 0x64
+						ctxt.Andptr = ctxt.Andptr[1:] // FS
+						ctxt.Andptr[0] = 0x8B
+						ctxt.Andptr = ctxt.Andptr[1:]
+						asmand(ctxt, p, &pp.From, &p.To)
+
+					case obj.Hwindows:
+						// Windows TLS base is always 0x28(GS).
+						pp.From = p.From
+
+						pp.From.Type = obj.TYPE_MEM
+						pp.From.Name = obj.NAME_NONE
+						pp.From.Reg = REG_GS
+						pp.From.Offset = 0x28
+						pp.From.Index = REG_NONE
+						pp.From.Scale = 0
+						ctxt.Rexflag |= Pw
+						ctxt.Andptr[0] = 0x65
+						ctxt.Andptr = ctxt.Andptr[1:] // GS
+						ctxt.Andptr[0] = 0x8B
+						ctxt.Andptr = ctxt.Andptr[1:]
+						asmand(ctxt, p, &pp.From, &p.To)
+					}
 				}
+				return
 			}
 		}
 	}
+	goto bad
 
 bad:
 	if p.Mode != 64 {
@@ -3412,10 +3910,37 @@
 		 * exchange registers and reissue the
 		 * instruction with the operands renamed.
 		 */
-		pp = *p
+		pp := *p
 
-		z = int(p.From.Reg)
+		unbytereg(&pp.From, &pp.Ft)
+		unbytereg(&pp.To, &pp.Tt)
+
+		z := int(p.From.Reg)
 		if p.From.Type == obj.TYPE_REG && z >= REG_BP && z <= REG_DI {
+			// TODO(rsc): Use this code for x86-64 too. It has bug fixes not present in the amd64 code base.
+			// For now, different to keep bit-for-bit compatibility.
+			if p.Mode == 32 {
+				breg := byteswapreg(ctxt, &p.To)
+				if breg != REG_AX {
+					ctxt.Andptr[0] = 0x87
+					ctxt.Andptr = ctxt.Andptr[1:] /* xchg lhs,bx */
+					asmando(ctxt, p, &p.From, reg[breg])
+					subreg(&pp, z, breg)
+					doasm(ctxt, &pp)
+					ctxt.Andptr[0] = 0x87
+					ctxt.Andptr = ctxt.Andptr[1:] /* xchg lhs,bx */
+					asmando(ctxt, p, &p.From, reg[breg])
+				} else {
+					ctxt.Andptr[0] = byte(0x90 + reg[z])
+					ctxt.Andptr = ctxt.Andptr[1:] /* xchg lsh,ax */
+					subreg(&pp, z, REG_AX)
+					doasm(ctxt, &pp)
+					ctxt.Andptr[0] = byte(0x90 + reg[z])
+					ctxt.Andptr = ctxt.Andptr[1:] /* xchg lsh,ax */
+				}
+				return
+			}
+
 			if isax(&p.To) || p.To.Type == obj.TYPE_NONE {
 				// We certainly don't want to exchange
 				// with AX if the op is MUL or DIV.
@@ -3435,12 +3960,35 @@
 				ctxt.Andptr[0] = byte(0x90 + reg[z])
 				ctxt.Andptr = ctxt.Andptr[1:] /* xchg lsh,ax */
 			}
-
 			return
 		}
 
 		z = int(p.To.Reg)
 		if p.To.Type == obj.TYPE_REG && z >= REG_BP && z <= REG_DI {
+			// TODO(rsc): Use this code for x86-64 too. It has bug fixes not present in the amd64 code base.
+			// For now, different to keep bit-for-bit compatibility.
+			if p.Mode == 32 {
+				breg := byteswapreg(ctxt, &p.From)
+				if breg != REG_AX {
+					ctxt.Andptr[0] = 0x87
+					ctxt.Andptr = ctxt.Andptr[1:] /* xchg rhs,bx */
+					asmando(ctxt, p, &p.To, reg[breg])
+					subreg(&pp, z, breg)
+					doasm(ctxt, &pp)
+					ctxt.Andptr[0] = 0x87
+					ctxt.Andptr = ctxt.Andptr[1:] /* xchg rhs,bx */
+					asmando(ctxt, p, &p.To, reg[breg])
+				} else {
+					ctxt.Andptr[0] = byte(0x90 + reg[z])
+					ctxt.Andptr = ctxt.Andptr[1:] /* xchg rsh,ax */
+					subreg(&pp, z, REG_AX)
+					doasm(ctxt, &pp)
+					ctxt.Andptr[0] = byte(0x90 + reg[z])
+					ctxt.Andptr = ctxt.Andptr[1:] /* xchg rsh,ax */
+				}
+				return
+			}
+
 			if isax(&p.From) {
 				ctxt.Andptr[0] = 0x87
 				ctxt.Andptr = ctxt.Andptr[1:] /* xchg rhs,bx */
@@ -3458,193 +4006,85 @@
 				ctxt.Andptr[0] = byte(0x90 + reg[z])
 				ctxt.Andptr = ctxt.Andptr[1:] /* xchg rsh,ax */
 			}
-
 			return
 		}
 	}
 
 	ctxt.Diag("doasm: notfound ft=%d tt=%d %v %d %d", p.Ft, p.Tt, p, oclass(ctxt, p, &p.From), oclass(ctxt, p, &p.To))
 	return
+}
 
-mfound:
-	switch mo[0].code {
-	default:
-		ctxt.Diag("asmins: unknown mov %d %v", mo[0].code, p)
+// byteswapreg returns a byte-addressable register (AX, BX, CX, DX)
+// which is not referenced in a.
+// If a is empty, it returns BX to account for MULB-like instructions
+// that might use DX and AX.
+func byteswapreg(ctxt *obj.Link, a *obj.Addr) int {
+	cand := 1
+	canc := cand
+	canb := canc
+	cana := canb
 
-	case 0: /* lit */
-		for z = 0; t[z] != E; z++ {
-			ctxt.Andptr[0] = t[z]
-			ctxt.Andptr = ctxt.Andptr[1:]
-		}
+	if a.Type == obj.TYPE_NONE {
+		cand = 0
+		cana = cand
+	}
 
-	case 1: /* r,m */
-		ctxt.Andptr[0] = t[0]
-		ctxt.Andptr = ctxt.Andptr[1:]
+	if a.Type == obj.TYPE_REG || ((a.Type == obj.TYPE_MEM || a.Type == obj.TYPE_ADDR) && a.Name == obj.NAME_NONE) {
+		switch a.Reg {
+		case REG_NONE:
+			cand = 0
+			cana = cand
 
-		asmando(ctxt, p, &p.To, int(t[1]))
+		case REG_AX, REG_AL, REG_AH:
+			cana = 0
 
-	case 2: /* m,r */
-		ctxt.Andptr[0] = t[0]
-		ctxt.Andptr = ctxt.Andptr[1:]
+		case REG_BX, REG_BL, REG_BH:
+			canb = 0
 
-		asmando(ctxt, p, &p.From, int(t[1]))
+		case REG_CX, REG_CL, REG_CH:
+			canc = 0
 
-	case 3: /* r,m - 2op */
-		ctxt.Andptr[0] = t[0]
-		ctxt.Andptr = ctxt.Andptr[1:]
-
-		ctxt.Andptr[0] = t[1]
-		ctxt.Andptr = ctxt.Andptr[1:]
-		asmando(ctxt, p, &p.To, int(t[2]))
-		ctxt.Rexflag |= regrex[p.From.Reg] & (Rxr | 0x40)
-
-	case 4: /* m,r - 2op */
-		ctxt.Andptr[0] = t[0]
-		ctxt.Andptr = ctxt.Andptr[1:]
-
-		ctxt.Andptr[0] = t[1]
-		ctxt.Andptr = ctxt.Andptr[1:]
-		asmando(ctxt, p, &p.From, int(t[2]))
-		ctxt.Rexflag |= regrex[p.To.Reg] & (Rxr | 0x40)
-
-	case 5: /* load full pointer, trash heap */
-		if t[0] != 0 {
-			ctxt.Andptr[0] = t[0]
-			ctxt.Andptr = ctxt.Andptr[1:]
-		}
-		switch p.To.Index {
-		default:
-			goto bad
-
-		case REG_DS:
-			ctxt.Andptr[0] = 0xc5
-			ctxt.Andptr = ctxt.Andptr[1:]
-
-		case REG_SS:
-			ctxt.Andptr[0] = 0x0f
-			ctxt.Andptr = ctxt.Andptr[1:]
-			ctxt.Andptr[0] = 0xb2
-			ctxt.Andptr = ctxt.Andptr[1:]
-
-		case REG_ES:
-			ctxt.Andptr[0] = 0xc4
-			ctxt.Andptr = ctxt.Andptr[1:]
-
-		case REG_FS:
-			ctxt.Andptr[0] = 0x0f
-			ctxt.Andptr = ctxt.Andptr[1:]
-			ctxt.Andptr[0] = 0xb4
-			ctxt.Andptr = ctxt.Andptr[1:]
-
-		case REG_GS:
-			ctxt.Andptr[0] = 0x0f
-			ctxt.Andptr = ctxt.Andptr[1:]
-			ctxt.Andptr[0] = 0xb5
-			ctxt.Andptr = ctxt.Andptr[1:]
-		}
-
-		asmand(ctxt, p, &p.From, &p.To)
-
-	case 6: /* double shift */
-		if t[0] == Pw {
-			if p.Mode != 64 {
-				ctxt.Diag("asmins: illegal 64: %v", p)
-			}
-			ctxt.Rexflag |= Pw
-			t = t[1:]
-		} else if t[0] == Pe {
-			ctxt.Andptr[0] = Pe
-			ctxt.Andptr = ctxt.Andptr[1:]
-			t = t[1:]
-		}
-
-		switch p.From.Type {
-		default:
-			goto bad
-
-		case obj.TYPE_CONST:
-			ctxt.Andptr[0] = 0x0f
-			ctxt.Andptr = ctxt.Andptr[1:]
-			ctxt.Andptr[0] = t[0]
-			ctxt.Andptr = ctxt.Andptr[1:]
-			asmandsz(ctxt, p, &p.To, reg[int(p.From.Index)], regrex[int(p.From.Index)], 0)
-			ctxt.Andptr[0] = byte(p.From.Offset)
-			ctxt.Andptr = ctxt.Andptr[1:]
-
-		case obj.TYPE_REG:
-			switch p.From.Reg {
-			default:
-				goto bad
-
-			case REG_CL,
-				REG_CX:
-				ctxt.Andptr[0] = 0x0f
-				ctxt.Andptr = ctxt.Andptr[1:]
-				ctxt.Andptr[0] = t[1]
-				ctxt.Andptr = ctxt.Andptr[1:]
-				asmandsz(ctxt, p, &p.To, reg[int(p.From.Index)], regrex[int(p.From.Index)], 0)
-			}
-		}
-
-		// NOTE: The systems listed here are the ones that use the "TLS initial exec" model,
-	// where you load the TLS base register into a register and then index off that
-	// register to access the actual TLS variables. Systems that allow direct TLS access
-	// are handled in prefixof above and should not be listed here.
-	case 7: /* mov tls, r */
-		switch ctxt.Headtype {
-		default:
-			log.Fatalf("unknown TLS base location for %s", obj.Headstr(ctxt.Headtype))
-
-		case obj.Hplan9:
-			if ctxt.Plan9privates == nil {
-				ctxt.Plan9privates = obj.Linklookup(ctxt, "_privates", 0)
-			}
-			pp.From = obj.Addr{}
-			pp.From.Type = obj.TYPE_MEM
-			pp.From.Name = obj.NAME_EXTERN
-			pp.From.Sym = ctxt.Plan9privates
-			pp.From.Offset = 0
-			pp.From.Index = REG_NONE
-			ctxt.Rexflag |= Pw
-			ctxt.Andptr[0] = 0x8B
-			ctxt.Andptr = ctxt.Andptr[1:]
-			asmand(ctxt, p, &pp.From, &p.To)
-
-			// TLS base is 0(FS).
-		case obj.Hsolaris: // TODO(rsc): Delete Hsolaris from list. Should not use this code. See progedit in obj6.c.
-			pp.From = p.From
-
-			pp.From.Type = obj.TYPE_MEM
-			pp.From.Name = obj.NAME_NONE
-			pp.From.Reg = REG_NONE
-			pp.From.Offset = 0
-			pp.From.Index = REG_NONE
-			pp.From.Scale = 0
-			ctxt.Rexflag |= Pw
-			ctxt.Andptr[0] = 0x64
-			ctxt.Andptr = ctxt.Andptr[1:] // FS
-			ctxt.Andptr[0] = 0x8B
-			ctxt.Andptr = ctxt.Andptr[1:]
-			asmand(ctxt, p, &pp.From, &p.To)
-
-			// Windows TLS base is always 0x28(GS).
-		case obj.Hwindows:
-			pp.From = p.From
-
-			pp.From.Type = obj.TYPE_MEM
-			pp.From.Name = obj.NAME_NONE
-			pp.From.Reg = REG_GS
-			pp.From.Offset = 0x28
-			pp.From.Index = REG_NONE
-			pp.From.Scale = 0
-			ctxt.Rexflag |= Pw
-			ctxt.Andptr[0] = 0x65
-			ctxt.Andptr = ctxt.Andptr[1:] // GS
-			ctxt.Andptr[0] = 0x8B
-			ctxt.Andptr = ctxt.Andptr[1:]
-			asmand(ctxt, p, &pp.From, &p.To)
+		case REG_DX, REG_DL, REG_DH:
+			cand = 0
 		}
 	}
+
+	if a.Type == obj.TYPE_MEM || a.Type == obj.TYPE_ADDR {
+		switch a.Index {
+		case REG_AX:
+			cana = 0
+
+		case REG_BX:
+			canb = 0
+
+		case REG_CX:
+			canc = 0
+
+		case REG_DX:
+			cand = 0
+		}
+	}
+
+	if cana != 0 {
+		return REG_AX
+	}
+	if canb != 0 {
+		return REG_BX
+	}
+	if canc != 0 {
+		return REG_CX
+	}
+	if cand != 0 {
+		return REG_DX
+	}
+
+	ctxt.Diag("impossible byte register")
+	log.Fatalf("bad code")
+	return 0
+}
+
+func isbadbyte(a *obj.Addr) bool {
+	return a.Type == obj.TYPE_REG && (REG_BP <= a.Reg && a.Reg <= REG_DI || REG_BPB <= a.Reg && a.Reg <= REG_DIB)
 }
 
 var naclret = []uint8{
@@ -3660,6 +4100,16 @@
 	0xe6, // JMP SI
 }
 
+var naclret8 = []uint8{
+	0x5d, // POPL BP
+	// 0x8b, 0x7d, 0x00, // MOVL (BP), DI - catch return to invalid address, for debugging
+	0x83,
+	0xe5,
+	0xe0, // ANDL $~31, BP
+	0xff,
+	0xe5, // JMP BP
+}
+
 var naclspfix = []uint8{0x4c, 0x01, 0xfc} // ADDQ R15, SP
 
 var naclbpfix = []uint8{0x4c, 0x01, 0xfd} // ADDQ R15, BP
@@ -3701,18 +4151,11 @@
 }
 
 func asmins(ctxt *obj.Link, p *obj.Prog) {
-	var i int
-	var n int
-	var np int
-	var c int
-	var and0 []byte
-	var r *obj.Reloc
-
 	ctxt.Andptr = ctxt.And[:]
 	ctxt.Asmode = int(p.Mode)
 
 	if p.As == obj.AUSEFIELD {
-		r = obj.Addrel(ctxt.Cursym)
+		r := obj.Addrel(ctxt.Cursym)
 		r.Off = 0
 		r.Siz = 0
 		r.Sym = p.From.Sym
@@ -3720,7 +4163,32 @@
 		return
 	}
 
-	if ctxt.Headtype == obj.Hnacl {
+	if ctxt.Headtype == obj.Hnacl && p.Mode == 32 {
+		switch p.As {
+		case obj.ARET:
+			copy(ctxt.Andptr, naclret8)
+			ctxt.Andptr = ctxt.Andptr[len(naclret8):]
+			return
+
+		case obj.ACALL,
+			obj.AJMP:
+			if p.To.Type == obj.TYPE_REG && REG_AX <= p.To.Reg && p.To.Reg <= REG_DI {
+				ctxt.Andptr[0] = 0x83
+				ctxt.Andptr = ctxt.Andptr[1:]
+				ctxt.Andptr[0] = byte(0xe0 | (p.To.Reg - REG_AX))
+				ctxt.Andptr = ctxt.Andptr[1:]
+				ctxt.Andptr[0] = 0xe0
+				ctxt.Andptr = ctxt.Andptr[1:]
+			}
+
+		case AINT:
+			ctxt.Andptr[0] = 0xf4
+			ctxt.Andptr = ctxt.Andptr[1:]
+			return
+		}
+	}
+
+	if ctxt.Headtype == obj.Hnacl && p.Mode == 64 {
 		if p.As == AREP {
 			ctxt.Rep++
 			return
@@ -3811,10 +4279,7 @@
 			copy(ctxt.Andptr, naclstos)
 			ctxt.Andptr = ctxt.Andptr[len(naclstos):]
 
-		case AMOVSB,
-			AMOVSW,
-			AMOVSL,
-			AMOVSQ:
+		case AMOVSB, AMOVSW, AMOVSL, AMOVSQ:
 			copy(ctxt.Andptr, naclmovs)
 			ctxt.Andptr = ctxt.Andptr[len(naclmovs):]
 		}
@@ -3839,7 +4304,7 @@
 	}
 
 	ctxt.Rexflag = 0
-	and0 = ctxt.Andptr
+	and0 := ctxt.Andptr
 	ctxt.Asmode = int(p.Mode)
 	doasm(ctxt, p)
 	if ctxt.Rexflag != 0 {
@@ -3851,9 +4316,11 @@
 		 * note that the handbook often misleadingly shows 66/f2/f3 in `opcode'.
 		 */
 		if p.Mode != 64 {
-			ctxt.Diag("asmins: illegal in mode %d: %v", p.Mode, p)
+			ctxt.Diag("asmins: illegal in mode %d: %v (%d %d)", p.Mode, p, p.Ft, p.Tt)
 		}
-		n = -cap(ctxt.Andptr) + cap(and0)
+		n := -cap(ctxt.Andptr) + cap(and0)
+		var c int
+		var np int
 		for np = 0; np < n; np++ {
 			c = int(and0[np])
 			if c != 0xf2 && c != 0xf3 && (c < 0x64 || c > 0x67) && c != 0x2e && c != 0x3e && c != 0x26 {
@@ -3866,8 +4333,9 @@
 		ctxt.Andptr = ctxt.Andptr[1:]
 	}
 
-	n = -cap(ctxt.Andptr) + cap(ctxt.And[:])
-	for i = len(ctxt.Cursym.R) - 1; i >= 0; i-- {
+	n := -cap(ctxt.Andptr) + cap(ctxt.And[:])
+	var r *obj.Reloc
+	for i := len(ctxt.Cursym.R) - 1; i >= 0; i-- {
 		r = &ctxt.Cursym.R[i:][0]
 		if int64(r.Off) < p.Pc {
 			break
@@ -3875,12 +4343,19 @@
 		if ctxt.Rexflag != 0 {
 			r.Off++
 		}
-		if r.Type == obj.R_PCREL || r.Type == obj.R_CALL {
+		if r.Type == obj.R_PCREL {
+			// PC-relative addressing is relative to the end of the instruction,
+			// but the relocations applied by the linker are relative to the end
+			// of the relocation. Because immediate instruction
+			// arguments can follow the PC-relative memory reference in the
+			// instruction encoding, the two may not coincide. In this case,
+			// adjust addend so that linker can keep relocating relative to the
+			// end of the relocation.
 			r.Add -= p.Pc + int64(n) - (int64(r.Off) + int64(r.Siz))
 		}
 	}
 
-	if ctxt.Headtype == obj.Hnacl && p.As != ACMPL && p.As != ACMPQ && p.To.Type == obj.TYPE_REG {
+	if p.Mode == 64 && ctxt.Headtype == obj.Hnacl && p.As != ACMPL && p.As != ACMPQ && p.To.Type == obj.TYPE_REG {
 		switch p.To.Reg {
 		case REG_SP:
 			copy(ctxt.Andptr, naclspfix)
diff --git a/src/cmd/internal/obj/x86/list6.go b/src/cmd/internal/obj/x86/list6.go
index 41c69c9..fc79b90 100644
--- a/src/cmd/internal/obj/x86/list6.go
+++ b/src/cmd/internal/obj/x86/list6.go
@@ -35,63 +35,6 @@
 	"fmt"
 )
 
-//
-// Format conversions
-//	%A int		Opcodes (instruction mnemonics)
-//
-//	%D Addr*	Addresses (instruction operands)
-//
-//	%P Prog*	Instructions
-//
-//	%R int		Registers
-//
-//	%$ char*	String constant addresses (for internal use only)
-
-const (
-	STRINGSZ = 1000
-)
-
-var bigP *obj.Prog
-
-func Pconv(p *obj.Prog) string {
-	var str string
-	var fp string
-
-	switch p.As {
-	case obj.ADATA:
-		str = fmt.Sprintf("%.5d (%v)\t%v\t%v/%d,%v",
-			p.Pc, p.Line(), Aconv(int(p.As)), obj.Dconv(p, &p.From), p.From3.Offset, obj.Dconv(p, &p.To))
-
-	case obj.ATEXT:
-		if p.From3.Offset != 0 {
-			str = fmt.Sprintf("%.5d (%v)\t%v\t%v,%d,%v",
-				p.Pc, p.Line(), Aconv(int(p.As)), obj.Dconv(p, &p.From), p.From3.Offset, obj.Dconv(p, &p.To))
-			break
-		}
-
-		str = fmt.Sprintf("%.5d (%v)\t%v\t%v,%v",
-			p.Pc, p.Line(), Aconv(int(p.As)), obj.Dconv(p, &p.From), obj.Dconv(p, &p.To))
-
-	default:
-		str = fmt.Sprintf("%.5d (%v)\t%v\t%v,%v",
-			p.Pc, p.Line(), Aconv(int(p.As)), obj.Dconv(p, &p.From), obj.Dconv(p, &p.To))
-
-		// TODO(rsc): This special case is for SHRQ $32, AX:DX, which encodes as
-		//	SHRQ $32(DX*0), AX
-		// Remove.
-		if (p.From.Type == obj.TYPE_REG || p.From.Type == obj.TYPE_CONST) && p.From.Index != REG_NONE {
-			str += fmt.Sprintf(":%v", Rconv(int(p.From.Index)))
-		}
-	}
-
-	fp += str
-	return fp
-}
-
-func Aconv(i int) string {
-	return Anames[i]
-}
-
 var Register = []string{
 	"AL", /* [D_AL] */
 	"CL",
@@ -210,11 +153,12 @@
 
 func init() {
 	obj.RegisterRegister(REG_AL, REG_AL+len(Register), Rconv)
+	obj.RegisterOpcode(obj.ABaseAMD64, Anames)
 }
 
 func Rconv(r int) string {
 	if REG_AL <= r && r-REG_AL < len(Register) {
-		return fmt.Sprintf("%s", Register[r-REG_AL])
+		return Register[r-REG_AL]
 	}
 	return fmt.Sprintf("Rgok(%d)", r-obj.RBaseAMD64)
 }
diff --git a/src/cmd/internal/obj/x86/obj6.go b/src/cmd/internal/obj/x86/obj6.go
index 63a82b0..3d9a4be 100644
--- a/src/cmd/internal/obj/x86/obj6.go
+++ b/src/cmd/internal/obj/x86/obj6.go
@@ -39,19 +39,46 @@
 )
 
 func canuselocaltls(ctxt *obj.Link) bool {
+	if ctxt.Arch.Regsize == 4 {
+		switch ctxt.Headtype {
+		case obj.Hlinux,
+			obj.Hnacl,
+			obj.Hplan9,
+			obj.Hwindows:
+			return false
+		}
+
+		return true
+	}
+
 	switch ctxt.Headtype {
 	case obj.Hplan9,
 		obj.Hwindows:
 		return false
+	case obj.Hlinux:
+		return ctxt.Flag_shared == 0
 	}
 
 	return true
 }
 
 func progedit(ctxt *obj.Link, p *obj.Prog) {
-	var literal string
-	var s *obj.LSym
-	var q *obj.Prog
+	// Maintain information about code generation mode.
+	if ctxt.Mode == 0 {
+		ctxt.Mode = ctxt.Arch.Regsize * 8
+	}
+	p.Mode = int8(ctxt.Mode)
+
+	switch p.As {
+	case AMODE:
+		if p.From.Type == obj.TYPE_CONST || (p.From.Type == obj.TYPE_MEM && p.From.Reg == REG_NONE) {
+			switch int(p.From.Offset) {
+			case 16, 32, 64:
+				ctxt.Mode = int(p.From.Offset)
+			}
+		}
+		obj.Nopout(p)
+	}
 
 	// Thread-local storage references use the TLS pseudo-register.
 	// As a register, TLS refers to the thread-local storage base, and it
@@ -121,7 +148,7 @@
 		//	MOVQ off(BX)(TLS*1), BX
 		// This allows the C compilers to emit references to m and g using the direct off(TLS) form.
 		if (p.As == AMOVQ || p.As == AMOVL) && p.From.Type == obj.TYPE_MEM && p.From.Reg == REG_TLS && p.To.Type == obj.TYPE_REG && REG_AX <= p.To.Reg && p.To.Reg <= REG_R15 {
-			q = obj.Appendp(ctxt, p)
+			q := obj.Appendp(ctxt, p)
 			q.As = p.As
 			q.From = p.From
 			q.From.Type = obj.TYPE_MEM
@@ -137,7 +164,7 @@
 	}
 
 	// TODO: Remove.
-	if ctxt.Headtype == obj.Hwindows || ctxt.Headtype == obj.Hplan9 {
+	if ctxt.Headtype == obj.Hwindows && p.Mode == 64 || ctxt.Headtype == obj.Hplan9 {
 		if p.From.Scale == 1 && p.From.Index == REG_TLS {
 			p.From.Scale = 2
 		}
@@ -146,47 +173,47 @@
 		}
 	}
 
-	if ctxt.Headtype == obj.Hnacl {
-		nacladdr(ctxt, p, &p.From)
-		nacladdr(ctxt, p, &p.To)
-	}
-
-	// Maintain information about code generation mode.
-	if ctxt.Mode == 0 {
-		ctxt.Mode = 64
-	}
-	p.Mode = int8(ctxt.Mode)
-
+	// Rewrite 0 to $0 in 3rd argment to CMPPS etc.
+	// That's what the tables expect.
 	switch p.As {
-	case AMODE:
-		if p.From.Type == obj.TYPE_CONST || (p.From.Type == obj.TYPE_MEM && p.From.Reg == REG_NONE) {
-			switch int(p.From.Offset) {
-			case 16,
-				32,
-				64:
-				ctxt.Mode = int(p.From.Offset)
-			}
+	case ACMPPD, ACMPPS, ACMPSD, ACMPSS:
+		if p.To.Type == obj.TYPE_MEM && p.To.Name == obj.NAME_NONE && p.To.Reg == REG_NONE && p.To.Index == REG_NONE && p.To.Sym == nil {
+			p.To.Type = obj.TYPE_CONST
 		}
-
-		obj.Nopout(p)
 	}
 
 	// Rewrite CALL/JMP/RET to symbol as TYPE_BRANCH.
 	switch p.As {
-	case obj.ACALL,
-		obj.AJMP,
-		obj.ARET:
+	case obj.ACALL, obj.AJMP, obj.ARET:
 		if p.To.Type == obj.TYPE_MEM && (p.To.Name == obj.NAME_EXTERN || p.To.Name == obj.NAME_STATIC) && p.To.Sym != nil {
 			p.To.Type = obj.TYPE_BRANCH
 		}
 	}
 
+	// 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)
+		nacladdr(ctxt, p, &p.To)
+	}
+
 	// Rewrite float constants to values stored in memory.
 	switch p.As {
 	// Convert AMOVSS $(0), Xx to AXORPS Xx, Xx
 	case AMOVSS:
 		if p.From.Type == obj.TYPE_FCONST {
-			if p.From.U.Dval == 0 {
+			if p.From.Val.(float64) == 0 {
 				if p.To.Type == obj.TYPE_REG && REG_X0 <= p.To.Reg && p.To.Reg <= REG_X15 {
 					p.As = AXORPS
 					p.From = p.To
@@ -196,8 +223,6 @@
 		}
 		fallthrough
 
-		// fallthrough
-
 	case AFMOVF,
 		AFADDF,
 		AFSUBF,
@@ -214,12 +239,10 @@
 		ACOMISS,
 		AUCOMISS:
 		if p.From.Type == obj.TYPE_FCONST {
-			var i32 uint32
-			var f32 float32
-			f32 = float32(p.From.U.Dval)
-			i32 = math.Float32bits(f32)
-			literal = fmt.Sprintf("$f32.%08x", i32)
-			s = obj.Linklookup(ctxt, literal, 0)
+			f32 := float32(p.From.Val.(float64))
+			i32 := math.Float32bits(f32)
+			literal := fmt.Sprintf("$f32.%08x", i32)
+			s := obj.Linklookup(ctxt, literal, 0)
 			if s.Type == 0 {
 				s.Type = obj.SRODATA
 				obj.Adduint32(ctxt, s, i32)
@@ -232,10 +255,10 @@
 			p.From.Offset = 0
 		}
 
-		// Convert AMOVSD $(0), Xx to AXORPS Xx, Xx
 	case AMOVSD:
+		// Convert AMOVSD $(0), Xx to AXORPS Xx, Xx
 		if p.From.Type == obj.TYPE_FCONST {
-			if p.From.U.Dval == 0 {
+			if p.From.Val.(float64) == 0 {
 				if p.To.Type == obj.TYPE_REG && REG_X0 <= p.To.Reg && p.To.Reg <= REG_X15 {
 					p.As = AXORPS
 					p.From = p.To
@@ -245,7 +268,6 @@
 		}
 		fallthrough
 
-		// fallthrough
 	case AFMOVD,
 		AFADDD,
 		AFSUBD,
@@ -262,10 +284,9 @@
 		ACOMISD,
 		AUCOMISD:
 		if p.From.Type == obj.TYPE_FCONST {
-			var i64 uint64
-			i64 = math.Float64bits(p.From.U.Dval)
-			literal = fmt.Sprintf("$f64.%016x", i64)
-			s = obj.Linklookup(ctxt, literal, 0)
+			i64 := math.Float64bits(p.From.Val.(float64))
+			literal := fmt.Sprintf("$f64.%016x", i64)
+			s := obj.Linklookup(ctxt, literal, 0)
 			if s.Type == 0 {
 				s.Type = obj.SRODATA
 				obj.Adduint64(ctxt, s, i64)
@@ -296,9 +317,7 @@
 	if a.Type == obj.TYPE_MEM && a.Name == obj.NAME_NONE {
 		switch a.Reg {
 		// all ok
-		case REG_BP,
-			REG_SP,
-			REG_R15:
+		case REG_BP, REG_SP, REG_R15:
 			break
 
 		default:
@@ -315,17 +334,6 @@
 }
 
 func preprocess(ctxt *obj.Link, cursym *obj.LSym) {
-	var p *obj.Prog
-	var q *obj.Prog
-	var p1 *obj.Prog
-	var p2 *obj.Prog
-	var autoffset int32
-	var deltasp int32
-	var a int
-	var pcsize int
-	var bpsize int
-	var textarg int64
-
 	if ctxt.Tlsg == nil {
 		ctxt.Tlsg = obj.Linklookup(ctxt, "runtime.tlsg", 0)
 	}
@@ -344,13 +352,14 @@
 		return
 	}
 
-	p = cursym.Text
-	autoffset = int32(p.To.Offset)
+	p := cursym.Text
+	autoffset := int32(p.To.Offset)
 	if autoffset < 0 {
 		autoffset = 0
 	}
 
-	if obj.Framepointer_enabled != 0 && autoffset > 0 {
+	var bpsize int
+	if p.Mode == 64 && obj.Framepointer_enabled != 0 && autoffset > 0 {
 		// Make room for to save a base pointer.  If autoffset == 0,
 		// this might do something special like a tail jump to
 		// another function, so in that case we omit this.
@@ -362,12 +371,18 @@
 		bpsize = 0
 	}
 
-	textarg = int64(p.To.U.Argsize)
+	textarg := int64(p.To.Val.(int32))
 	cursym.Args = int32(textarg)
 	cursym.Locals = int32(p.To.Offset)
 
-	if autoffset < obj.StackSmall && p.From3.Offset&obj.NOSPLIT == 0 {
-		for q = p; q != nil; q = q.Link {
+	// TODO(rsc): Remove.
+	if p.Mode == 32 && cursym.Locals < 0 {
+		cursym.Locals = 0
+	}
+
+	// TODO(rsc): Remove 'p.Mode == 64 &&'.
+	if p.Mode == 64 && autoffset < obj.StackSmall && p.From3.Offset&obj.NOSPLIT == 0 {
+		for q := p; q != nil; q = q.Link {
 			if q.As == obj.ACALL {
 				goto noleaf
 			}
@@ -380,12 +395,12 @@
 	noleaf:
 	}
 
-	q = nil
 	if p.From3.Offset&obj.NOSPLIT == 0 || (p.From3.Offset&obj.WRAPPER != 0) {
 		p = obj.Appendp(ctxt, p)
 		p = load_g_cx(ctxt, p) // load g into CX
 	}
 
+	var q *obj.Prog
 	if cursym.Text.From3.Offset&obj.NOSPLIT == 0 {
 		p = stacksplit(ctxt, p, autoffset, int32(textarg), cursym.Text.From3.Offset&obj.NEEDCTXT == 0, &q) // emit split check
 	}
@@ -415,7 +430,7 @@
 	if q != nil {
 		q.Pcond = p
 	}
-	deltasp = autoffset
+	deltasp := autoffset
 
 	if bpsize > 0 {
 		// Save caller's BP
@@ -465,13 +480,16 @@
 		p.From.Offset = 4 * int64(ctxt.Arch.Ptrsize) // G.panic
 		p.To.Type = obj.TYPE_REG
 		p.To.Reg = REG_BX
-		if ctxt.Headtype == obj.Hnacl {
+		if ctxt.Headtype == obj.Hnacl && p.Mode == 64 {
 			p.As = AMOVL
 			p.From.Type = obj.TYPE_MEM
 			p.From.Reg = REG_R15
 			p.From.Scale = 1
 			p.From.Index = REG_CX
 		}
+		if p.Mode == 32 {
+			p.As = AMOVL
+		}
 
 		p = obj.Appendp(ctxt, p)
 		p.As = ATESTQ
@@ -479,23 +497,23 @@
 		p.From.Reg = REG_BX
 		p.To.Type = obj.TYPE_REG
 		p.To.Reg = REG_BX
-		if ctxt.Headtype == obj.Hnacl {
+		if ctxt.Headtype == obj.Hnacl || p.Mode == 32 {
 			p.As = ATESTL
 		}
 
 		p = obj.Appendp(ctxt, p)
 		p.As = AJEQ
 		p.To.Type = obj.TYPE_BRANCH
-		p1 = p
+		p1 := p
 
 		p = obj.Appendp(ctxt, p)
 		p.As = ALEAQ
 		p.From.Type = obj.TYPE_MEM
 		p.From.Reg = REG_SP
-		p.From.Offset = int64(autoffset) + 8
+		p.From.Offset = int64(autoffset) + int64(ctxt.Arch.Regsize)
 		p.To.Type = obj.TYPE_REG
 		p.To.Reg = REG_DI
-		if ctxt.Headtype == obj.Hnacl {
+		if ctxt.Headtype == obj.Hnacl || p.Mode == 32 {
 			p.As = ALEAL
 		}
 
@@ -506,18 +524,21 @@
 		p.From.Offset = 0 // Panic.argp
 		p.To.Type = obj.TYPE_REG
 		p.To.Reg = REG_DI
-		if ctxt.Headtype == obj.Hnacl {
+		if ctxt.Headtype == obj.Hnacl && p.Mode == 64 {
 			p.As = ACMPL
 			p.From.Type = obj.TYPE_MEM
 			p.From.Reg = REG_R15
 			p.From.Scale = 1
 			p.From.Index = REG_BX
 		}
+		if p.Mode == 32 {
+			p.As = ACMPL
+		}
 
 		p = obj.Appendp(ctxt, p)
 		p.As = AJNE
 		p.To.Type = obj.TYPE_BRANCH
-		p2 = p
+		p2 := p
 
 		p = obj.Appendp(ctxt, p)
 		p.As = AMOVQ
@@ -526,13 +547,16 @@
 		p.To.Type = obj.TYPE_MEM
 		p.To.Reg = REG_BX
 		p.To.Offset = 0 // Panic.argp
-		if ctxt.Headtype == obj.Hnacl {
+		if ctxt.Headtype == obj.Hnacl && p.Mode == 64 {
 			p.As = AMOVL
 			p.To.Type = obj.TYPE_MEM
 			p.To.Reg = REG_R15
 			p.To.Scale = 1
 			p.To.Index = REG_BX
 		}
+		if p.Mode == 32 {
+			p.As = AMOVL
+		}
 
 		p = obj.Appendp(ctxt, p)
 		p.As = obj.ANOP
@@ -551,13 +575,19 @@
 		p.From.Reg = REG_SP
 		p.To.Type = obj.TYPE_REG
 		p.To.Reg = REG_DI
+		if p.Mode == 32 {
+			p.As = AMOVL
+		}
 
 		p = obj.Appendp(ctxt, p)
 		p.As = AMOVQ
 		p.From.Type = obj.TYPE_CONST
-		p.From.Offset = int64(autoffset) / 8
+		p.From.Offset = int64(autoffset) / int64(ctxt.Arch.Regsize)
 		p.To.Type = obj.TYPE_REG
 		p.To.Reg = REG_CX
+		if p.Mode == 32 {
+			p.As = AMOVL
+		}
 
 		p = obj.Appendp(ctxt, p)
 		p.As = AMOVQ
@@ -565,14 +595,22 @@
 		p.From.Offset = 0
 		p.To.Type = obj.TYPE_REG
 		p.To.Reg = REG_AX
+		if p.Mode == 32 {
+			p.As = AMOVL
+		}
 
 		p = obj.Appendp(ctxt, p)
 		p.As = AREP
 
 		p = obj.Appendp(ctxt, p)
 		p.As = ASTOSQ
+		if p.Mode == 32 {
+			p.As = ASTOSL
+		}
 	}
 
+	var a int
+	var pcsize int
 	for ; p != nil; p = p.Link {
 		pcsize = int(p.Mode) / 8
 		a = int(p.From.Name)
@@ -582,6 +620,13 @@
 		if a == obj.NAME_PARAM {
 			p.From.Offset += int64(deltasp) + int64(pcsize)
 		}
+		a = int(p.From3.Name)
+		if a == obj.NAME_AUTO {
+			p.From3.Offset += int64(deltasp) - int64(bpsize)
+		}
+		if a == obj.NAME_PARAM {
+			p.From3.Offset += int64(deltasp) + int64(pcsize)
+		}
 		a = int(p.To.Name)
 		if a == obj.NAME_AUTO {
 			p.To.Offset += int64(deltasp) - int64(bpsize)
@@ -594,38 +639,32 @@
 		default:
 			continue
 
-		case APUSHL,
-			APUSHFL:
+		case APUSHL, APUSHFL:
 			deltasp += 4
 			p.Spadj = 4
 			continue
 
-		case APUSHQ,
-			APUSHFQ:
+		case APUSHQ, APUSHFQ:
 			deltasp += 8
 			p.Spadj = 8
 			continue
 
-		case APUSHW,
-			APUSHFW:
+		case APUSHW, APUSHFW:
 			deltasp += 2
 			p.Spadj = 2
 			continue
 
-		case APOPL,
-			APOPFL:
+		case APOPL, APOPFL:
 			deltasp -= 4
 			p.Spadj = -4
 			continue
 
-		case APOPQ,
-			APOPFQ:
+		case APOPQ, APOPFQ:
 			deltasp -= 8
 			p.Spadj = -8
 			continue
 
-		case APOPW,
-			APOPFW:
+		case APOPW, APOPFW:
 			deltasp -= 2
 			p.Spadj = -2
 			continue
@@ -672,8 +711,8 @@
 	}
 }
 
-func indir_cx(ctxt *obj.Link, a *obj.Addr) {
-	if ctxt.Headtype == obj.Hnacl {
+func indir_cx(ctxt *obj.Link, p *obj.Prog, a *obj.Addr) {
+	if ctxt.Headtype == obj.Hnacl && p.Mode == 64 {
 		a.Type = obj.TYPE_MEM
 		a.Reg = REG_R15
 		a.Index = REG_CX
@@ -691,8 +730,6 @@
 // prologue (caller must call appendp first) and in the epilogue.
 // Returns last new instruction.
 func load_g_cx(ctxt *obj.Link, p *obj.Prog) *obj.Prog {
-	var next *obj.Prog
-
 	p.As = AMOVQ
 	if ctxt.Arch.Ptrsize == 4 {
 		p.As = AMOVL
@@ -703,7 +740,7 @@
 	p.To.Type = obj.TYPE_REG
 	p.To.Reg = REG_CX
 
-	next = p.Link
+	next := p.Link
 	progedit(ctxt, p)
 	for p.Link != next {
 		p = p.Link
@@ -723,26 +760,19 @@
 // On return, *jmpok is the instruction that should jump
 // to the stack frame allocation if no split is needed.
 func stacksplit(ctxt *obj.Link, p *obj.Prog, framesize int32, textarg int32, noctxt bool, jmpok **obj.Prog) *obj.Prog {
-	var q *obj.Prog
-	var q1 *obj.Prog
-	var cmp int
-	var lea int
-	var mov int
-	var sub int
+	cmp := ACMPQ
+	lea := ALEAQ
+	mov := AMOVQ
+	sub := ASUBQ
 
-	cmp = ACMPQ
-	lea = ALEAQ
-	mov = AMOVQ
-	sub = ASUBQ
-
-	if ctxt.Headtype == obj.Hnacl {
+	if ctxt.Headtype == obj.Hnacl || p.Mode == 32 {
 		cmp = ACMPL
 		lea = ALEAL
 		mov = AMOVL
 		sub = ASUBL
 	}
 
-	q1 = nil
+	var q1 *obj.Prog
 	if framesize <= obj.StackSmall {
 		// small stack: SP <= stackguard
 		//	CMPQ SP, stackguard
@@ -751,7 +781,7 @@
 		p.As = int16(cmp)
 		p.From.Type = obj.TYPE_REG
 		p.From.Reg = REG_SP
-		indir_cx(ctxt, &p.To)
+		indir_cx(ctxt, p, &p.To)
 		p.To.Offset = 2 * int64(ctxt.Arch.Ptrsize) // G.stackguard0
 		if ctxt.Cursym.Cfunc != 0 {
 			p.To.Offset = 3 * int64(ctxt.Arch.Ptrsize) // G.stackguard1
@@ -773,7 +803,7 @@
 		p.As = int16(cmp)
 		p.From.Type = obj.TYPE_REG
 		p.From.Reg = REG_AX
-		indir_cx(ctxt, &p.To)
+		indir_cx(ctxt, p, &p.To)
 		p.To.Offset = 2 * int64(ctxt.Arch.Ptrsize) // G.stackguard0
 		if ctxt.Cursym.Cfunc != 0 {
 			p.To.Offset = 3 * int64(ctxt.Arch.Ptrsize) // G.stackguard1
@@ -797,7 +827,7 @@
 		p = obj.Appendp(ctxt, p)
 
 		p.As = int16(mov)
-		indir_cx(ctxt, &p.From)
+		indir_cx(ctxt, p, &p.From)
 		p.From.Offset = 2 * int64(ctxt.Arch.Ptrsize) // G.stackguard0
 		if ctxt.Cursym.Cfunc != 0 {
 			p.From.Offset = 3 * int64(ctxt.Arch.Ptrsize) // G.stackguard1
@@ -811,6 +841,9 @@
 		p.From.Reg = REG_SI
 		p.To.Type = obj.TYPE_CONST
 		p.To.Offset = obj.StackPreempt
+		if p.Mode == 32 {
+			p.To.Offset = int64(uint32(obj.StackPreempt & (1<<32 - 1)))
+		}
 
 		p = obj.Appendp(ctxt, p)
 		p.As = AJEQ
@@ -845,7 +878,7 @@
 
 	p.As = AJHI
 	p.To.Type = obj.TYPE_BRANCH
-	q = p
+	q := p
 
 	p = obj.Appendp(ctxt, p)
 	p.As = obj.ACALL
@@ -873,13 +906,10 @@
 }
 
 func follow(ctxt *obj.Link, s *obj.LSym) {
-	var firstp *obj.Prog
-	var lastp *obj.Prog
-
 	ctxt.Cursym = s
 
-	firstp = ctxt.NewProg()
-	lastp = firstp
+	firstp := ctxt.NewProg()
+	lastp := firstp
 	xfol(ctxt, s.Text, &lastp)
 	lastp.Link = nil
 	s.Text = firstp.Link
@@ -922,7 +952,7 @@
 	return false
 }
 
-func relinv(a int) int {
+func relinv(a int16) int16 {
 	switch a {
 	case AJEQ:
 		return AJNE
@@ -958,7 +988,7 @@
 		return AJOS
 	}
 
-	log.Fatalf("unknown relation: %s", Anames[a])
+	log.Fatalf("unknown relation: %s", obj.Aconv(int(a)))
 	return 0
 }
 
@@ -991,7 +1021,7 @@
 		 */
 		i = 0
 		q = p
-		for ; i < 4; (func() { i++; q = q.Link })() {
+		for ; i < 4; i, q = i+1, q.Link {
 			if q == nil {
 				break
 			}
@@ -1028,7 +1058,7 @@
 					continue
 				}
 
-				q.As = int16(relinv(int(q.As)))
+				q.As = relinv(q.As)
 				p = q.Pcond
 				q.Pcond = q.Link
 				q.Link = p
@@ -1081,7 +1111,7 @@
 				 * expect conditional jump to be taken.
 				 * rewrite so that's the fall-through case.
 				 */
-				p.As = int16(relinv(a))
+				p.As = relinv(int16(a))
 
 				q = p.Link
 				p.Link = p.Pcond
@@ -1091,7 +1121,7 @@
 			q = p.Link
 			if q.Mark != 0 {
 				if a != ALOOP {
-					p.As = int16(relinv(a))
+					p.As = relinv(int16(a))
 					p.Link = p.Pcond
 					p.Pcond = q
 				}
@@ -1110,34 +1140,94 @@
 	goto loop
 }
 
+var unaryDst = map[int]bool{
+	ABSWAPL:    true,
+	ABSWAPQ:    true,
+	ACMPXCHG8B: true,
+	ADECB:      true,
+	ADECL:      true,
+	ADECQ:      true,
+	ADECW:      true,
+	AINCB:      true,
+	AINCL:      true,
+	AINCQ:      true,
+	AINCW:      true,
+	ANEGB:      true,
+	ANEGL:      true,
+	ANEGQ:      true,
+	ANEGW:      true,
+	ANOTB:      true,
+	ANOTL:      true,
+	ANOTQ:      true,
+	ANOTW:      true,
+	APOPL:      true,
+	APOPQ:      true,
+	APOPW:      true,
+	ASETCC:     true,
+	ASETCS:     true,
+	ASETEQ:     true,
+	ASETGE:     true,
+	ASETGT:     true,
+	ASETHI:     true,
+	ASETLE:     true,
+	ASETLS:     true,
+	ASETLT:     true,
+	ASETMI:     true,
+	ASETNE:     true,
+	ASETOC:     true,
+	ASETOS:     true,
+	ASETPC:     true,
+	ASETPL:     true,
+	ASETPS:     true,
+	AFFREE:     true,
+	AFLDENV:    true,
+	AFSAVE:     true,
+	AFSTCW:     true,
+	AFSTENV:    true,
+	AFSTSW:     true,
+	AFXSAVE:    true,
+	AFXSAVE64:  true,
+	ASTMXCSR:   true,
+}
+
 var Linkamd64 = obj.LinkArch{
-	Rconv:      Rconv,
 	ByteOrder:  binary.LittleEndian,
-	Pconv:      Pconv,
 	Name:       "amd64",
 	Thechar:    '6',
-	Endian:     obj.LittleEndian,
 	Preprocess: preprocess,
 	Assemble:   span6,
 	Follow:     follow,
 	Progedit:   progedit,
+	UnaryDst:   unaryDst,
 	Minlc:      1,
 	Ptrsize:    8,
 	Regsize:    8,
 }
 
 var Linkamd64p32 = obj.LinkArch{
-	Rconv:      Rconv,
 	ByteOrder:  binary.LittleEndian,
-	Pconv:      Pconv,
 	Name:       "amd64p32",
 	Thechar:    '6',
-	Endian:     obj.LittleEndian,
 	Preprocess: preprocess,
 	Assemble:   span6,
 	Follow:     follow,
 	Progedit:   progedit,
+	UnaryDst:   unaryDst,
 	Minlc:      1,
 	Ptrsize:    4,
 	Regsize:    8,
 }
+
+var Link386 = obj.LinkArch{
+	ByteOrder:  binary.LittleEndian,
+	Name:       "386",
+	Thechar:    '8',
+	Preprocess: preprocess,
+	Assemble:   span6,
+	Follow:     follow,
+	Progedit:   progedit,
+	UnaryDst:   unaryDst,
+	Minlc:      1,
+	Ptrsize:    4,
+	Regsize:    4,
+}
diff --git a/src/cmd/objdump/objdump_test.go b/src/cmd/objdump/objdump_test.go
index 63c0063..1846272 100644
--- a/src/cmd/objdump/objdump_test.go
+++ b/src/cmd/objdump/objdump_test.go
@@ -108,6 +108,8 @@
 	switch runtime.GOARCH {
 	case "ppc64", "ppc64le":
 		t.Skipf("skipping on %s, issue 9039", runtime.GOARCH)
+	case "arm64":
+		t.Skipf("skipping on %s, issue 10106", runtime.GOARCH)
 	}
 	testDisasm(t)
 }
@@ -120,6 +122,8 @@
 	switch runtime.GOARCH {
 	case "ppc64", "ppc64le":
 		t.Skipf("skipping on %s, no support for external linking, issue 9038", runtime.GOARCH)
+	case "arm64":
+		t.Skipf("skipping on %s, issue 10106", runtime.GOARCH)
 	}
 	testDisasm(t, "-ldflags=-linkmode=external")
 }
diff --git a/src/cmd/old5a/a.y b/src/cmd/old5a/a.y
index c1ca3be..0ef8ae90 100644
--- a/src/cmd/old5a/a.y
+++ b/src/cmd/old5a/a.y
@@ -376,28 +376,28 @@
 		$$ = nullgen;
 		$$.Type = obj.TYPE_TEXTSIZE;
 		$$.Offset = int64($1)
-		$$.U.Argsize = obj.ArgsSizeUnknown;
+		$$.Val = int32(obj.ArgsSizeUnknown)
 	}
 |	'-' LCONST
 	{
 		$$ = nullgen;
 		$$.Type = obj.TYPE_TEXTSIZE;
 		$$.Offset = -int64($2)
-		$$.U.Argsize = obj.ArgsSizeUnknown;
+		$$.Val = int32(obj.ArgsSizeUnknown)
 	}
 |	LCONST '-' LCONST
 	{
 		$$ = nullgen;
 		$$.Type = obj.TYPE_TEXTSIZE;
 		$$.Offset = int64($1)
-		$$.U.Argsize = int32($3);
+		$$.Val = int32($3);
 	}
 |	'-' LCONST '-' LCONST
 	{
 		$$ = nullgen;
 		$$.Type = obj.TYPE_TEXTSIZE;
 		$$.Offset = -int64($2)
-		$$.U.Argsize = int32($4);
+		$$.Val = int32($4);
 	}
 
 cond:
@@ -449,7 +449,7 @@
 	{
 		$$ = nullgen;
 		$$.Type = obj.TYPE_SCONST;
-		$$.U.Sval = $2
+		$$.Val = $2
 	}
 |	fcon
 
@@ -458,13 +458,13 @@
 	{
 		$$ = nullgen;
 		$$.Type = obj.TYPE_FCONST;
-		$$.U.Dval = $2;
+		$$.Val = $2;
 	}
 |	'$' '-' LFCONST
 	{
 		$$ = nullgen;
 		$$.Type = obj.TYPE_FCONST;
-		$$.U.Dval = -$3;
+		$$.Val = -$3;
 	}
 
 reglist:
diff --git a/src/cmd/old5a/y.go b/src/cmd/old5a/y.go
index a79f61d..9f5988f 100644
--- a/src/cmd/old5a/y.go
+++ b/src/cmd/old5a/y.go
@@ -981,7 +981,7 @@
 			yyVAL.addr = nullgen
 			yyVAL.addr.Type = obj.TYPE_TEXTSIZE
 			yyVAL.addr.Offset = int64(yyDollar[1].lval)
-			yyVAL.addr.U.Argsize = obj.ArgsSizeUnknown
+			yyVAL.addr.Val = int32(obj.ArgsSizeUnknown)
 		}
 	case 47:
 		yyDollar = yyS[yypt-2 : yypt+1]
@@ -990,7 +990,7 @@
 			yyVAL.addr = nullgen
 			yyVAL.addr.Type = obj.TYPE_TEXTSIZE
 			yyVAL.addr.Offset = -int64(yyDollar[2].lval)
-			yyVAL.addr.U.Argsize = obj.ArgsSizeUnknown
+			yyVAL.addr.Val = int32(obj.ArgsSizeUnknown)
 		}
 	case 48:
 		yyDollar = yyS[yypt-3 : yypt+1]
@@ -999,7 +999,7 @@
 			yyVAL.addr = nullgen
 			yyVAL.addr.Type = obj.TYPE_TEXTSIZE
 			yyVAL.addr.Offset = int64(yyDollar[1].lval)
-			yyVAL.addr.U.Argsize = int32(yyDollar[3].lval)
+			yyVAL.addr.Val = int32(yyDollar[3].lval)
 		}
 	case 49:
 		yyDollar = yyS[yypt-4 : yypt+1]
@@ -1008,7 +1008,7 @@
 			yyVAL.addr = nullgen
 			yyVAL.addr.Type = obj.TYPE_TEXTSIZE
 			yyVAL.addr.Offset = -int64(yyDollar[2].lval)
-			yyVAL.addr.U.Argsize = int32(yyDollar[4].lval)
+			yyVAL.addr.Val = int32(yyDollar[4].lval)
 		}
 	case 50:
 		yyDollar = yyS[yypt-0 : yypt+1]
@@ -1069,7 +1069,7 @@
 		{
 			yyVAL.addr = nullgen
 			yyVAL.addr.Type = obj.TYPE_SCONST
-			yyVAL.addr.U.Sval = yyDollar[2].sval
+			yyVAL.addr.Val = yyDollar[2].sval
 		}
 	case 60:
 		yyVAL.addr = yyS[yypt-0].addr
@@ -1079,7 +1079,7 @@
 		{
 			yyVAL.addr = nullgen
 			yyVAL.addr.Type = obj.TYPE_FCONST
-			yyVAL.addr.U.Dval = yyDollar[2].dval
+			yyVAL.addr.Val = yyDollar[2].dval
 		}
 	case 62:
 		yyDollar = yyS[yypt-3 : yypt+1]
@@ -1087,7 +1087,7 @@
 		{
 			yyVAL.addr = nullgen
 			yyVAL.addr.Type = obj.TYPE_FCONST
-			yyVAL.addr.U.Dval = -yyDollar[3].dval
+			yyVAL.addr.Val = -yyDollar[3].dval
 		}
 	case 63:
 		yyDollar = yyS[yypt-1 : yypt+1]
diff --git a/src/cmd/old6a/a.y b/src/cmd/old6a/a.y
index 671e79c..46da420 100644
--- a/src/cmd/old6a/a.y
+++ b/src/cmd/old6a/a.y
@@ -205,12 +205,12 @@
 	LTYPET mem ',' '$' textsize
 	{
 		asm.Settext($2.Sym);
-		outcode(obj.ATEXT, &Addr2{$2, $5})
+		outcode(obj.ATEXT, &Addr2{from: $2, to: $5})
 	}
 |	LTYPET mem ',' con ',' '$' textsize
 	{
 		asm.Settext($2.Sym);
-		outcode(obj.ATEXT, &Addr2{$2, $7})
+		outcode(obj.ATEXT, &Addr2{from: $2, to: $7})
 		if asm.Pass > 1 {
 			lastpc.From3.Type = obj.TYPE_CONST
 			lastpc.From3.Offset = $4
@@ -221,12 +221,12 @@
 	LTYPEG mem ',' imm
 	{
 		asm.Settext($2.Sym)
-		outcode(obj.AGLOBL, &Addr2{$2, $4})
+		outcode(obj.AGLOBL, &Addr2{from: $2, to: $4})
 	}
 |	LTYPEG mem ',' con ',' imm
 	{
 		asm.Settext($2.Sym)
-		outcode(obj.AGLOBL, &Addr2{$2, $6})
+		outcode(obj.AGLOBL, &Addr2{from: $2, to: $6})
 		if asm.Pass > 1 {
 			lastpc.From3.Type = obj.TYPE_CONST
 			lastpc.From3.Offset = $4
@@ -299,22 +299,20 @@
 	}
 
 spec8:	/* CMPPS/CMPPD */
-	reg ',' rem ',' con
+	rem ',' reg ',' con
 	{
 		$$.from = $1;
-		$$.to = $3;
+		$$.from3 = $3;
+		$$.to.Type = obj.TYPE_MEM; // to give library something to do
 		$$.to.Offset = $5;
 	}
 
 spec9:	/* shufl */
 	imm ',' rem ',' reg
 	{
-		$$.from = $3;
+		$$.from = $1;
+		$$.from3 = $3;
 		$$.to = $5;
-		if $1.Type != obj.TYPE_CONST {
-			yyerror("illegal constant");
-		}
-		$$.to.Offset = $1.Offset;
 	}
 
 spec10:	/* RET/RETF */
@@ -456,31 +454,31 @@
 	{
 		$$ = nullgen;
 		$$.Type = obj.TYPE_SCONST;
-		$$.U.Sval = ($2+"\x00\x00\x00\x00\x00\x00\x00\x00")[:8]
+		$$.Val = ($2+"\x00\x00\x00\x00\x00\x00\x00\x00")[:8]
 	}
 |	'$' LFCONST
 	{
 		$$ = nullgen;
 		$$.Type = obj.TYPE_FCONST;
-		$$.U.Dval = $2;
+		$$.Val = $2;
 	}
 |	'$' '(' LFCONST ')'
 	{
 		$$ = nullgen;
 		$$.Type = obj.TYPE_FCONST;
-		$$.U.Dval = $3;
+		$$.Val = $3;
 	}
 |	'$' '(' '-' LFCONST ')'
 	{
 		$$ = nullgen;
 		$$.Type = obj.TYPE_FCONST;
-		$$.U.Dval = -$4;
+		$$.Val = -$4;
 	}
 |	'$' '-' LFCONST
 	{
 		$$ = nullgen;
 		$$.Type = obj.TYPE_FCONST;
-		$$.U.Dval = -$3;
+		$$.Val = -$3;
 	}
 
 mem:
@@ -655,28 +653,28 @@
 		$$ = nullgen;
 		$$.Type = obj.TYPE_TEXTSIZE;
 		$$.Offset = $1;
-		$$.U.Argsize = obj.ArgsSizeUnknown;
+		$$.Val = int32(obj.ArgsSizeUnknown);
 	}
 |	'-' LCONST
 	{
 		$$ = nullgen;
 		$$.Type = obj.TYPE_TEXTSIZE;
 		$$.Offset = -$2;
-		$$.U.Argsize = obj.ArgsSizeUnknown;
+		$$.Val = int32(obj.ArgsSizeUnknown);
 	}
 |	LCONST '-' LCONST
 	{
 		$$ = nullgen;
 		$$.Type = obj.TYPE_TEXTSIZE;
 		$$.Offset = $1;
-		$$.U.Argsize = int32($3);
+		$$.Val = int32($3);
 	}
 |	'-' LCONST '-' LCONST
 	{
 		$$ = nullgen;
 		$$.Type = obj.TYPE_TEXTSIZE;
 		$$.Offset = -$2;
-		$$.U.Argsize = int32($4);
+		$$.Val = int32($4);
 	}
 
 expr:
diff --git a/src/cmd/old6a/lex.go b/src/cmd/old6a/lex.go
index 9e58446..c228ac7 100644
--- a/src/cmd/old6a/lex.go
+++ b/src/cmd/old6a/lex.go
@@ -941,8 +941,9 @@
 var lastpc *obj.Prog
 
 type Addr2 struct {
-	from obj.Addr
-	to   obj.Addr
+	from  obj.Addr
+	from3 obj.Addr
+	to    obj.Addr
 }
 
 func outcode(a int, g2 *Addr2) {
@@ -959,6 +960,7 @@
 	p.As = int16(a)
 	p.Lineno = stmtline
 	p.From = g2.from
+	p.From3 = g2.from3
 	p.To = g2.to
 	p.Pc = int64(asm.PC)
 
diff --git a/src/cmd/old6a/y.go b/src/cmd/old6a/y.go
index 730fb78..5738c56 100644
--- a/src/cmd/old6a/y.go
+++ b/src/cmd/old6a/y.go
@@ -129,29 +129,29 @@
 
 	52, 227, 41, 3, 80, 208, 269, 64, 123, 50,
 	51, 79, 54, 170, 268, 74, 267, 118, 85, 72,
-	83, 263, 73, 255, 253, 98, 241, 84, 81, 239,
-	237, 100, 102, 112, 221, 219, 112, 210, 209, 171,
-	240, 107, 234, 62, 211, 174, 143, 138, 65, 207,
-	111, 119, 115, 113, 112, 231, 67, 169, 120, 121,
-	122, 249, 230, 92, 94, 96, 128, 226, 225, 224,
-	104, 106, 74, 58, 57, 154, 136, 112, 129, 85,
-	153, 83, 151, 150, 139, 141, 149, 148, 84, 81,
-	140, 147, 142, 146, 145, 144, 63, 55, 58, 57,
-	137, 43, 45, 48, 44, 46, 49, 40, 135, 47,
-	69, 134, 56, 127, 155, 40, 34, 37, 53, 31,
-	59, 32, 55, 35, 33, 223, 176, 177, 222, 217,
+	83, 263, 73, 255, 253, 241, 239, 84, 81, 237,
+	221, 100, 102, 112, 219, 210, 112, 209, 171, 240,
+	234, 107, 211, 62, 174, 143, 138, 119, 65, 207,
+	111, 115, 249, 113, 112, 231, 67, 169, 120, 121,
+	122, 230, 226, 92, 94, 96, 128, 225, 224, 154,
+	104, 106, 74, 58, 57, 153, 136, 112, 129, 85,
+	151, 83, 150, 149, 139, 141, 148, 147, 84, 81,
+	140, 146, 142, 145, 137, 144, 63, 55, 58, 57,
+	135, 43, 45, 48, 44, 46, 49, 40, 134, 47,
+	69, 127, 56, 37, 155, 40, 35, 34, 53, 98,
+	59, 31, 55, 32, 33, 223, 176, 177, 222, 217,
 	60, 215, 220, 112, 120, 243, 114, 56, 74, 242,
 	216, 236, 183, 76, 173, 59, 58, 57, 256, 166,
-	168, 251, 252, 192, 194, 196, 167, 112, 112, 112,
-	112, 112, 195, 184, 112, 112, 112, 264, 58, 57,
-	55, 212, 257, 248, 197, 198, 199, 200, 201, 182,
-	120, 204, 205, 206, 218, 56, 42, 114, 152, 38,
-	65, 76, 55, 59, 190, 191, 184, 261, 260, 166,
-	168, 229, 258, 112, 112, 75, 167, 56, 89, 235,
-	36, 71, 65, 76, 238, 59, 108, 109, 254, 213,
-	232, 233, 125, 126, 228, 244, 247, 203, 245, 88,
-	124, 181, 125, 126, 246, 158, 159, 160, 175, 250,
-	202, 25, 185, 186, 187, 188, 189, 16, 15, 6,
+	168, 188, 184, 192, 194, 196, 167, 112, 112, 112,
+	112, 112, 195, 229, 112, 112, 112, 258, 58, 57,
+	55, 212, 251, 252, 197, 198, 199, 200, 201, 182,
+	120, 204, 205, 206, 218, 56, 228, 114, 264, 257,
+	65, 76, 55, 59, 190, 191, 184, 248, 38, 166,
+	168, 152, 42, 112, 112, 75, 167, 56, 36, 235,
+	261, 71, 65, 76, 238, 59, 124, 89, 125, 126,
+	232, 233, 158, 159, 160, 244, 260, 88, 245, 254,
+	213, 181, 108, 109, 246, 125, 126, 247, 203, 250,
+	175, 202, 185, 186, 187, 25, 189, 16, 15, 6,
 	110, 259, 7, 2, 1, 262, 156, 157, 158, 159,
 	160, 265, 266, 105, 9, 10, 11, 12, 13, 17,
 	28, 18, 14, 29, 30, 26, 19, 20, 21, 22,
@@ -190,40 +190,40 @@
 }
 var yyPact = []int{
 
-	-1000, -1000, 250, -1000, 70, -1000, 74, 66, 72, 65,
+	-1000, -1000, 250, -1000, 72, -1000, 74, 67, 65, 61,
 	374, 294, 294, 394, 159, -1000, -1000, 274, 354, 294,
-	294, 294, 314, -5, -5, -1000, 294, 294, 84, 488,
+	294, 294, 394, -5, -5, -1000, 294, 294, 84, 488,
 	488, -1000, 502, -1000, -1000, 502, -1000, -1000, -1000, 394,
 	-1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000,
-	-1000, -1000, -2, 428, -3, -1000, -1000, 502, 502, 502,
-	223, -1000, 61, -1000, -1000, 408, -1000, 59, -1000, 56,
-	-1000, 448, -1000, 48, -7, 213, 502, -1000, 334, -1000,
-	-1000, -1000, 64, -1000, -1000, -8, 223, -1000, -1000, -1000,
-	394, -1000, 42, -1000, 41, -1000, 39, -1000, 35, -1000,
-	34, -1000, -1000, -1000, 31, -1000, 30, 176, 28, 23,
-	250, 555, -1000, 555, -1000, 111, 2, -16, 282, 106,
-	-1000, -1000, -1000, -9, 230, 502, 502, -1000, -1000, -1000,
-	-1000, -1000, 476, 460, 394, 294, -1000, 448, 128, -1000,
-	-1000, -1000, -1000, 161, -9, 394, 394, 394, 394, 394,
+	-1000, -1000, -3, 428, -7, -1000, -1000, 502, 502, 502,
+	209, -1000, 59, -1000, -1000, 408, -1000, 56, -1000, 48,
+	-1000, 448, -1000, 42, -8, 226, 502, -1000, 334, -1000,
+	-1000, -1000, 64, -1000, -1000, -9, 209, -1000, -1000, -1000,
+	394, -1000, 41, -1000, 39, -1000, 35, -1000, 34, -1000,
+	31, -1000, -1000, -1000, 30, -1000, 28, 189, 23, 17,
+	250, 555, -1000, 555, -1000, 111, 2, -17, 282, 106,
+	-1000, -1000, -1000, -10, 232, 502, 502, -1000, -1000, -1000,
+	-1000, -1000, 476, 460, 394, 294, -1000, 448, 117, -1000,
+	-1000, -1000, -1000, 161, -10, 394, 394, 394, 314, 394,
 	294, 294, 502, 435, 137, -1000, 502, 502, 502, 502,
-	502, 233, 219, 502, 502, 502, -6, -17, -18, -10,
-	502, -1000, -1000, 208, 95, 213, -1000, -1000, -20, 89,
-	-1000, -1000, -1000, -1000, -21, 79, 76, -1000, 17, 16,
-	-1000, -1000, 15, 191, 10, -1000, 3, 224, 224, -1000,
-	-1000, -1000, 502, 502, 579, 572, 564, -12, 502, -1000,
-	-1000, 103, -25, 502, -26, -1000, -1000, -1000, -14, -1000,
-	-29, -1000, 101, 96, 502, 314, -5, -1000, 216, 140,
-	8, -5, 247, 247, 113, -31, 207, -1000, -32, -1000,
-	112, -1000, -1000, -1000, -1000, -1000, -1000, 139, 192, 191,
-	-1000, 187, 186, -1000, 502, -1000, -34, -1000, 134, -1000,
+	502, 234, 230, 502, 502, 502, -6, -18, -20, -12,
+	502, -1000, -1000, 219, 95, 226, -1000, -1000, -21, 89,
+	-1000, -1000, -1000, -1000, -25, 79, 76, -1000, 16, 15,
+	-1000, -1000, 10, 153, 9, -1000, 3, 211, 211, -1000,
+	-1000, -1000, 502, 502, 579, 572, 564, -14, 502, -1000,
+	-1000, 103, -26, 502, -29, -1000, -1000, -1000, -15, -1000,
+	-30, -1000, 101, 96, 502, 314, -5, -1000, 227, 164,
+	-1, -5, 247, 247, 134, -31, 218, -1000, -32, -1000,
+	112, -1000, -1000, -1000, -1000, -1000, -1000, 156, 157, 153,
+	-1000, 215, 199, -1000, 502, -1000, -34, -1000, 155, -1000,
 	502, 502, -39, -1000, -1000, -41, -49, -1000, -1000, -1000,
 }
 var yyPgo = []int{
 
-	0, 0, 17, 324, 8, 186, 7, 1, 2, 12,
-	4, 96, 43, 11, 9, 10, 210, 323, 189, 321,
+	0, 0, 17, 324, 8, 202, 7, 1, 2, 12,
+	4, 96, 43, 11, 9, 10, 208, 323, 198, 321,
 	318, 317, 310, 309, 308, 306, 305, 302, 301, 299,
-	297, 263, 254, 253, 3, 250, 249, 248, 247, 241,
+	297, 263, 254, 253, 3, 250, 249, 248, 247, 245,
 }
 var yyR1 = []int{
 
@@ -270,7 +270,7 @@
 	46, -19, -12, -11, -6, 53, -20, -12, -21, -11,
 	-17, 52, -10, -6, -1, 46, 54, -22, 52, -13,
 	-10, -15, 11, -8, -14, -1, 46, -23, -16, -18,
-	52, -24, -12, -25, -12, -26, -12, -27, -8, -28,
+	52, -24, -12, -25, -12, -26, -12, -27, -11, -28,
 	-6, -29, -6, -30, -12, -31, -12, -9, -5, -5,
 	-35, -2, -1, -2, -11, 54, 38, 45, -2, 54,
 	-1, -1, -1, -4, 7, 9, 10, 52, -1, -9,
@@ -279,7 +279,7 @@
 	52, 52, 12, 52, 52, -34, 9, 10, 11, 12,
 	13, 7, 8, 6, 5, 4, 38, 45, 39, 55,
 	11, 55, 55, 38, 54, 8, -1, -1, 43, 10,
-	43, -11, -12, -10, 35, -11, -11, -11, -11, -11,
+	43, -11, -12, -10, 35, -11, -11, -11, -8, -11,
 	-12, -12, -1, 53, -1, -6, -1, -2, -2, -2,
 	-2, -2, 7, 8, -2, -2, -2, 55, 11, 55,
 	55, 54, -1, 11, -3, 36, 45, 34, -4, 55,
@@ -836,14 +836,14 @@
 		//line a.y:206
 		{
 			asm.Settext(yyDollar[2].addr.Sym)
-			outcode(obj.ATEXT, &Addr2{yyDollar[2].addr, yyDollar[5].addr})
+			outcode(obj.ATEXT, &Addr2{from: yyDollar[2].addr, to: yyDollar[5].addr})
 		}
 	case 43:
 		yyDollar = yyS[yypt-7 : yypt+1]
 		//line a.y:211
 		{
 			asm.Settext(yyDollar[2].addr.Sym)
-			outcode(obj.ATEXT, &Addr2{yyDollar[2].addr, yyDollar[7].addr})
+			outcode(obj.ATEXT, &Addr2{from: yyDollar[2].addr, to: yyDollar[7].addr})
 			if asm.Pass > 1 {
 				lastpc.From3.Type = obj.TYPE_CONST
 				lastpc.From3.Offset = yyDollar[4].lval
@@ -854,14 +854,14 @@
 		//line a.y:222
 		{
 			asm.Settext(yyDollar[2].addr.Sym)
-			outcode(obj.AGLOBL, &Addr2{yyDollar[2].addr, yyDollar[4].addr})
+			outcode(obj.AGLOBL, &Addr2{from: yyDollar[2].addr, to: yyDollar[4].addr})
 		}
 	case 45:
 		yyDollar = yyS[yypt-6 : yypt+1]
 		//line a.y:227
 		{
 			asm.Settext(yyDollar[2].addr.Sym)
-			outcode(obj.AGLOBL, &Addr2{yyDollar[2].addr, yyDollar[6].addr})
+			outcode(obj.AGLOBL, &Addr2{from: yyDollar[2].addr, to: yyDollar[6].addr})
 			if asm.Pass > 1 {
 				lastpc.From3.Type = obj.TYPE_CONST
 				lastpc.From3.Offset = yyDollar[4].lval
@@ -947,37 +947,35 @@
 		//line a.y:303
 		{
 			yyVAL.addr2.from = yyDollar[1].addr
-			yyVAL.addr2.to = yyDollar[3].addr
+			yyVAL.addr2.from3 = yyDollar[3].addr
+			yyVAL.addr2.to.Type = obj.TYPE_MEM // to give library something to do
 			yyVAL.addr2.to.Offset = yyDollar[5].lval
 		}
 	case 58:
 		yyDollar = yyS[yypt-5 : yypt+1]
-		//line a.y:311
+		//line a.y:312
 		{
-			yyVAL.addr2.from = yyDollar[3].addr
+			yyVAL.addr2.from = yyDollar[1].addr
+			yyVAL.addr2.from3 = yyDollar[3].addr
 			yyVAL.addr2.to = yyDollar[5].addr
-			if yyDollar[1].addr.Type != obj.TYPE_CONST {
-				yyerror("illegal constant")
-			}
-			yyVAL.addr2.to.Offset = yyDollar[1].addr.Offset
 		}
 	case 59:
 		yyDollar = yyS[yypt-0 : yypt+1]
-		//line a.y:321
+		//line a.y:319
 		{
 			yyVAL.addr2.from = nullgen
 			yyVAL.addr2.to = nullgen
 		}
 	case 60:
 		yyDollar = yyS[yypt-1 : yypt+1]
-		//line a.y:326
+		//line a.y:324
 		{
 			yyVAL.addr2.from = yyDollar[1].addr
 			yyVAL.addr2.to = nullgen
 		}
 	case 61:
 		yyDollar = yyS[yypt-3 : yypt+1]
-		//line a.y:333
+		//line a.y:331
 		{
 			if yyDollar[1].addr.Type != obj.TYPE_CONST || yyDollar[3].addr.Type != obj.TYPE_CONST {
 				yyerror("arguments to asm.PCDATA must be integer constants")
@@ -987,7 +985,7 @@
 		}
 	case 62:
 		yyDollar = yyS[yypt-3 : yypt+1]
-		//line a.y:343
+		//line a.y:341
 		{
 			if yyDollar[1].addr.Type != obj.TYPE_CONST {
 				yyerror("index for FUNCDATA must be integer constant")
@@ -1008,13 +1006,13 @@
 		yyVAL.addr = yyS[yypt-0].addr
 	case 67:
 		yyDollar = yyS[yypt-2 : yypt+1]
-		//line a.y:362
+		//line a.y:360
 		{
 			yyVAL.addr = yyDollar[2].addr
 		}
 	case 68:
 		yyDollar = yyS[yypt-2 : yypt+1]
-		//line a.y:366
+		//line a.y:364
 		{
 			yyVAL.addr = yyDollar[2].addr
 		}
@@ -1028,7 +1026,7 @@
 		yyVAL.addr = yyS[yypt-0].addr
 	case 73:
 		yyDollar = yyS[yypt-4 : yypt+1]
-		//line a.y:378
+		//line a.y:376
 		{
 			yyVAL.addr = nullgen
 			yyVAL.addr.Type = obj.TYPE_BRANCH
@@ -1036,7 +1034,7 @@
 		}
 	case 74:
 		yyDollar = yyS[yypt-2 : yypt+1]
-		//line a.y:384
+		//line a.y:382
 		{
 			yyDollar[1].sym = asm.LabelLookup(yyDollar[1].sym)
 			yyVAL.addr = nullgen
@@ -1048,7 +1046,7 @@
 		}
 	case 75:
 		yyDollar = yyS[yypt-1 : yypt+1]
-		//line a.y:396
+		//line a.y:394
 		{
 			yyVAL.addr = nullgen
 			yyVAL.addr.Type = obj.TYPE_REG
@@ -1056,7 +1054,7 @@
 		}
 	case 76:
 		yyDollar = yyS[yypt-1 : yypt+1]
-		//line a.y:402
+		//line a.y:400
 		{
 			yyVAL.addr = nullgen
 			yyVAL.addr.Type = obj.TYPE_REG
@@ -1064,7 +1062,7 @@
 		}
 	case 77:
 		yyDollar = yyS[yypt-1 : yypt+1]
-		//line a.y:408
+		//line a.y:406
 		{
 			yyVAL.addr = nullgen
 			yyVAL.addr.Type = obj.TYPE_REG
@@ -1072,7 +1070,7 @@
 		}
 	case 78:
 		yyDollar = yyS[yypt-1 : yypt+1]
-		//line a.y:414
+		//line a.y:412
 		{
 			yyVAL.addr = nullgen
 			yyVAL.addr.Type = obj.TYPE_REG
@@ -1080,7 +1078,7 @@
 		}
 	case 79:
 		yyDollar = yyS[yypt-1 : yypt+1]
-		//line a.y:420
+		//line a.y:418
 		{
 			yyVAL.addr = nullgen
 			yyVAL.addr.Type = obj.TYPE_REG
@@ -1088,7 +1086,7 @@
 		}
 	case 80:
 		yyDollar = yyS[yypt-1 : yypt+1]
-		//line a.y:426
+		//line a.y:424
 		{
 			yyVAL.addr = nullgen
 			yyVAL.addr.Type = obj.TYPE_REG
@@ -1096,7 +1094,7 @@
 		}
 	case 81:
 		yyDollar = yyS[yypt-1 : yypt+1]
-		//line a.y:432
+		//line a.y:430
 		{
 			yyVAL.addr = nullgen
 			yyVAL.addr.Type = obj.TYPE_REG
@@ -1104,7 +1102,7 @@
 		}
 	case 82:
 		yyDollar = yyS[yypt-2 : yypt+1]
-		//line a.y:440
+		//line a.y:438
 		{
 			yyVAL.addr = nullgen
 			yyVAL.addr.Type = obj.TYPE_CONST
@@ -1112,7 +1110,7 @@
 		}
 	case 83:
 		yyDollar = yyS[yypt-2 : yypt+1]
-		//line a.y:446
+		//line a.y:444
 		{
 			yyVAL.addr = yyDollar[2].addr
 			yyVAL.addr.Type = obj.TYPE_ADDR
@@ -1124,43 +1122,43 @@
 		}
 	case 84:
 		yyDollar = yyS[yypt-2 : yypt+1]
-		//line a.y:455
+		//line a.y:453
 		{
 			yyVAL.addr = nullgen
 			yyVAL.addr.Type = obj.TYPE_SCONST
-			yyVAL.addr.U.Sval = (yyDollar[2].sval + "\x00\x00\x00\x00\x00\x00\x00\x00")[:8]
+			yyVAL.addr.Val = (yyDollar[2].sval + "\x00\x00\x00\x00\x00\x00\x00\x00")[:8]
 		}
 	case 85:
 		yyDollar = yyS[yypt-2 : yypt+1]
-		//line a.y:461
+		//line a.y:459
 		{
 			yyVAL.addr = nullgen
 			yyVAL.addr.Type = obj.TYPE_FCONST
-			yyVAL.addr.U.Dval = yyDollar[2].dval
+			yyVAL.addr.Val = yyDollar[2].dval
 		}
 	case 86:
 		yyDollar = yyS[yypt-4 : yypt+1]
-		//line a.y:467
+		//line a.y:465
 		{
 			yyVAL.addr = nullgen
 			yyVAL.addr.Type = obj.TYPE_FCONST
-			yyVAL.addr.U.Dval = yyDollar[3].dval
+			yyVAL.addr.Val = yyDollar[3].dval
 		}
 	case 87:
 		yyDollar = yyS[yypt-5 : yypt+1]
-		//line a.y:473
+		//line a.y:471
 		{
 			yyVAL.addr = nullgen
 			yyVAL.addr.Type = obj.TYPE_FCONST
-			yyVAL.addr.U.Dval = -yyDollar[4].dval
+			yyVAL.addr.Val = -yyDollar[4].dval
 		}
 	case 88:
 		yyDollar = yyS[yypt-3 : yypt+1]
-		//line a.y:479
+		//line a.y:477
 		{
 			yyVAL.addr = nullgen
 			yyVAL.addr.Type = obj.TYPE_FCONST
-			yyVAL.addr.U.Dval = -yyDollar[3].dval
+			yyVAL.addr.Val = -yyDollar[3].dval
 		}
 	case 89:
 		yyVAL.addr = yyS[yypt-0].addr
@@ -1168,7 +1166,7 @@
 		yyVAL.addr = yyS[yypt-0].addr
 	case 91:
 		yyDollar = yyS[yypt-1 : yypt+1]
-		//line a.y:491
+		//line a.y:489
 		{
 			yyVAL.addr = nullgen
 			yyVAL.addr.Type = obj.TYPE_MEM
@@ -1176,7 +1174,7 @@
 		}
 	case 92:
 		yyDollar = yyS[yypt-4 : yypt+1]
-		//line a.y:497
+		//line a.y:495
 		{
 			yyVAL.addr = nullgen
 			yyVAL.addr.Type = obj.TYPE_MEM
@@ -1185,7 +1183,7 @@
 		}
 	case 93:
 		yyDollar = yyS[yypt-4 : yypt+1]
-		//line a.y:504
+		//line a.y:502
 		{
 			yyVAL.addr = nullgen
 			yyVAL.addr.Type = obj.TYPE_MEM
@@ -1194,7 +1192,7 @@
 		}
 	case 94:
 		yyDollar = yyS[yypt-4 : yypt+1]
-		//line a.y:511
+		//line a.y:509
 		{
 			yyVAL.addr = nullgen
 			yyVAL.addr.Type = obj.TYPE_MEM
@@ -1203,7 +1201,7 @@
 		}
 	case 95:
 		yyDollar = yyS[yypt-6 : yypt+1]
-		//line a.y:518
+		//line a.y:516
 		{
 			yyVAL.addr = nullgen
 			yyVAL.addr.Type = obj.TYPE_MEM
@@ -1214,7 +1212,7 @@
 		}
 	case 96:
 		yyDollar = yyS[yypt-9 : yypt+1]
-		//line a.y:527
+		//line a.y:525
 		{
 			yyVAL.addr = nullgen
 			yyVAL.addr.Type = obj.TYPE_MEM
@@ -1226,7 +1224,7 @@
 		}
 	case 97:
 		yyDollar = yyS[yypt-9 : yypt+1]
-		//line a.y:537
+		//line a.y:535
 		{
 			yyVAL.addr = nullgen
 			yyVAL.addr.Type = obj.TYPE_MEM
@@ -1238,7 +1236,7 @@
 		}
 	case 98:
 		yyDollar = yyS[yypt-3 : yypt+1]
-		//line a.y:547
+		//line a.y:545
 		{
 			yyVAL.addr = nullgen
 			yyVAL.addr.Type = obj.TYPE_MEM
@@ -1246,7 +1244,7 @@
 		}
 	case 99:
 		yyDollar = yyS[yypt-3 : yypt+1]
-		//line a.y:553
+		//line a.y:551
 		{
 			yyVAL.addr = nullgen
 			yyVAL.addr.Type = obj.TYPE_MEM
@@ -1254,7 +1252,7 @@
 		}
 	case 100:
 		yyDollar = yyS[yypt-5 : yypt+1]
-		//line a.y:559
+		//line a.y:557
 		{
 			yyVAL.addr = nullgen
 			yyVAL.addr.Type = obj.TYPE_MEM
@@ -1264,7 +1262,7 @@
 		}
 	case 101:
 		yyDollar = yyS[yypt-8 : yypt+1]
-		//line a.y:567
+		//line a.y:565
 		{
 			yyVAL.addr = nullgen
 			yyVAL.addr.Type = obj.TYPE_MEM
@@ -1275,13 +1273,13 @@
 		}
 	case 102:
 		yyDollar = yyS[yypt-1 : yypt+1]
-		//line a.y:578
+		//line a.y:576
 		{
 			yyVAL.addr = yyDollar[1].addr
 		}
 	case 103:
 		yyDollar = yyS[yypt-6 : yypt+1]
-		//line a.y:582
+		//line a.y:580
 		{
 			yyVAL.addr = yyDollar[1].addr
 			yyVAL.addr.Index = int16(yyDollar[3].lval)
@@ -1290,7 +1288,7 @@
 		}
 	case 104:
 		yyDollar = yyS[yypt-5 : yypt+1]
-		//line a.y:591
+		//line a.y:589
 		{
 			yyVAL.addr = nullgen
 			yyVAL.addr.Type = obj.TYPE_MEM
@@ -1300,7 +1298,7 @@
 		}
 	case 105:
 		yyDollar = yyS[yypt-7 : yypt+1]
-		//line a.y:599
+		//line a.y:597
 		{
 			yyVAL.addr = nullgen
 			yyVAL.addr.Type = obj.TYPE_MEM
@@ -1310,19 +1308,19 @@
 		}
 	case 106:
 		yyDollar = yyS[yypt-0 : yypt+1]
-		//line a.y:608
+		//line a.y:606
 		{
 			yyVAL.lval = 0
 		}
 	case 107:
 		yyDollar = yyS[yypt-2 : yypt+1]
-		//line a.y:612
+		//line a.y:610
 		{
 			yyVAL.lval = yyDollar[2].lval
 		}
 	case 108:
 		yyDollar = yyS[yypt-2 : yypt+1]
-		//line a.y:616
+		//line a.y:614
 		{
 			yyVAL.lval = -yyDollar[2].lval
 		}
@@ -1330,7 +1328,7 @@
 		yyVAL.lval = yyS[yypt-0].lval
 	case 110:
 		yyDollar = yyS[yypt-1 : yypt+1]
-		//line a.y:623
+		//line a.y:621
 		{
 			yyVAL.lval = obj.NAME_AUTO
 		}
@@ -1340,129 +1338,129 @@
 		yyVAL.lval = yyS[yypt-0].lval
 	case 113:
 		yyDollar = yyS[yypt-1 : yypt+1]
-		//line a.y:631
+		//line a.y:629
 		{
 			yyVAL.lval = yyDollar[1].sym.Value
 		}
 	case 114:
 		yyDollar = yyS[yypt-2 : yypt+1]
-		//line a.y:635
+		//line a.y:633
 		{
 			yyVAL.lval = -yyDollar[2].lval
 		}
 	case 115:
 		yyDollar = yyS[yypt-2 : yypt+1]
-		//line a.y:639
+		//line a.y:637
 		{
 			yyVAL.lval = yyDollar[2].lval
 		}
 	case 116:
 		yyDollar = yyS[yypt-2 : yypt+1]
-		//line a.y:643
+		//line a.y:641
 		{
 			yyVAL.lval = ^yyDollar[2].lval
 		}
 	case 117:
 		yyDollar = yyS[yypt-3 : yypt+1]
-		//line a.y:647
+		//line a.y:645
 		{
 			yyVAL.lval = yyDollar[2].lval
 		}
 	case 118:
 		yyDollar = yyS[yypt-1 : yypt+1]
-		//line a.y:653
+		//line a.y:651
 		{
 			yyVAL.addr = nullgen
 			yyVAL.addr.Type = obj.TYPE_TEXTSIZE
 			yyVAL.addr.Offset = yyDollar[1].lval
-			yyVAL.addr.U.Argsize = obj.ArgsSizeUnknown
+			yyVAL.addr.Val = int32(obj.ArgsSizeUnknown)
 		}
 	case 119:
 		yyDollar = yyS[yypt-2 : yypt+1]
-		//line a.y:660
+		//line a.y:658
 		{
 			yyVAL.addr = nullgen
 			yyVAL.addr.Type = obj.TYPE_TEXTSIZE
 			yyVAL.addr.Offset = -yyDollar[2].lval
-			yyVAL.addr.U.Argsize = obj.ArgsSizeUnknown
+			yyVAL.addr.Val = int32(obj.ArgsSizeUnknown)
 		}
 	case 120:
 		yyDollar = yyS[yypt-3 : yypt+1]
-		//line a.y:667
+		//line a.y:665
 		{
 			yyVAL.addr = nullgen
 			yyVAL.addr.Type = obj.TYPE_TEXTSIZE
 			yyVAL.addr.Offset = yyDollar[1].lval
-			yyVAL.addr.U.Argsize = int32(yyDollar[3].lval)
+			yyVAL.addr.Val = int32(yyDollar[3].lval)
 		}
 	case 121:
 		yyDollar = yyS[yypt-4 : yypt+1]
-		//line a.y:674
+		//line a.y:672
 		{
 			yyVAL.addr = nullgen
 			yyVAL.addr.Type = obj.TYPE_TEXTSIZE
 			yyVAL.addr.Offset = -yyDollar[2].lval
-			yyVAL.addr.U.Argsize = int32(yyDollar[4].lval)
+			yyVAL.addr.Val = int32(yyDollar[4].lval)
 		}
 	case 122:
 		yyVAL.lval = yyS[yypt-0].lval
 	case 123:
 		yyDollar = yyS[yypt-3 : yypt+1]
-		//line a.y:684
+		//line a.y:682
 		{
 			yyVAL.lval = yyDollar[1].lval + yyDollar[3].lval
 		}
 	case 124:
 		yyDollar = yyS[yypt-3 : yypt+1]
-		//line a.y:688
+		//line a.y:686
 		{
 			yyVAL.lval = yyDollar[1].lval - yyDollar[3].lval
 		}
 	case 125:
 		yyDollar = yyS[yypt-3 : yypt+1]
-		//line a.y:692
+		//line a.y:690
 		{
 			yyVAL.lval = yyDollar[1].lval * yyDollar[3].lval
 		}
 	case 126:
 		yyDollar = yyS[yypt-3 : yypt+1]
-		//line a.y:696
+		//line a.y:694
 		{
 			yyVAL.lval = yyDollar[1].lval / yyDollar[3].lval
 		}
 	case 127:
 		yyDollar = yyS[yypt-3 : yypt+1]
-		//line a.y:700
+		//line a.y:698
 		{
 			yyVAL.lval = yyDollar[1].lval % yyDollar[3].lval
 		}
 	case 128:
 		yyDollar = yyS[yypt-4 : yypt+1]
-		//line a.y:704
+		//line a.y:702
 		{
 			yyVAL.lval = yyDollar[1].lval << uint(yyDollar[4].lval)
 		}
 	case 129:
 		yyDollar = yyS[yypt-4 : yypt+1]
-		//line a.y:708
+		//line a.y:706
 		{
 			yyVAL.lval = yyDollar[1].lval >> uint(yyDollar[4].lval)
 		}
 	case 130:
 		yyDollar = yyS[yypt-3 : yypt+1]
-		//line a.y:712
+		//line a.y:710
 		{
 			yyVAL.lval = yyDollar[1].lval & yyDollar[3].lval
 		}
 	case 131:
 		yyDollar = yyS[yypt-3 : yypt+1]
-		//line a.y:716
+		//line a.y:714
 		{
 			yyVAL.lval = yyDollar[1].lval ^ yyDollar[3].lval
 		}
 	case 132:
 		yyDollar = yyS[yypt-3 : yypt+1]
-		//line a.y:720
+		//line a.y:718
 		{
 			yyVAL.lval = yyDollar[1].lval | yyDollar[3].lval
 		}
diff --git a/src/cmd/old8a/a.y b/src/cmd/old8a/a.y
index 384d8e6..fc12580 100644
--- a/src/cmd/old8a/a.y
+++ b/src/cmd/old8a/a.y
@@ -34,7 +34,7 @@
 import (
 	"cmd/internal/asm"
 	"cmd/internal/obj"
-	. "cmd/internal/obj/i386"
+	. "cmd/internal/obj/x86"
 )
 %}
 
@@ -304,7 +304,7 @@
 	}
 
 spec9:	/* CMPPS/CMPPD */
-	reg ',' rem ',' con
+	rem ',' reg ',' con
 	{
 		$$.from = $1;
 		$$.to = $3;
@@ -445,31 +445,31 @@
 	{
 		$$ = nullgen;
 		$$.Type = obj.TYPE_SCONST;
-		$$.U.Sval = $2
+		$$.Val = $2
 	}
 |	'$' LFCONST
 	{
 		$$ = nullgen;
 		$$.Type = obj.TYPE_FCONST;
-		$$.U.Dval = $2;
+		$$.Val = $2;
 	}
 |	'$' '(' LFCONST ')'
 	{
 		$$ = nullgen;
 		$$.Type = obj.TYPE_FCONST;
-		$$.U.Dval = $3;
+		$$.Val = $3;
 	}
 |	'$' '(' '-' LFCONST ')'
 	{
 		$$ = nullgen;
 		$$.Type = obj.TYPE_FCONST;
-		$$.U.Dval = -$4;
+		$$.Val = -$4;
 	}
 |	'$' '-' LFCONST
 	{
 		$$ = nullgen;
 		$$.Type = obj.TYPE_FCONST;
-		$$.U.Dval = -$3;
+		$$.Val = -$3;
 	}
 
 textsize:
@@ -478,28 +478,28 @@
 		$$ = nullgen;
 		$$.Type = obj.TYPE_TEXTSIZE;
 		$$.Offset = $1;
-		$$.U.Argsize = obj.ArgsSizeUnknown;
+		$$.Val = int32(obj.ArgsSizeUnknown);
 	}
 |	'-' LCONST
 	{
 		$$ = nullgen;
 		$$.Type = obj.TYPE_TEXTSIZE;
 		$$.Offset = -$2;
-		$$.U.Argsize = obj.ArgsSizeUnknown;
+		$$.Val = int32(obj.ArgsSizeUnknown);
 	}
 |	LCONST '-' LCONST
 	{
 		$$ = nullgen;
 		$$.Type = obj.TYPE_TEXTSIZE;
 		$$.Offset = $1;
-		$$.U.Argsize = int32($3);
+		$$.Val = int32($3);
 	}
 |	'-' LCONST '-' LCONST
 	{
 		$$ = nullgen;
 		$$.Type = obj.TYPE_TEXTSIZE;
 		$$.Offset = -$2;
-		$$.U.Argsize = int32($4);
+		$$.Val = int32($4);
 	}
 
 
diff --git a/src/cmd/old8a/lex.go b/src/cmd/old8a/lex.go
index d4b8110..73b633b 100644
--- a/src/cmd/old8a/lex.go
+++ b/src/cmd/old8a/lex.go
@@ -35,7 +35,7 @@
 import (
 	"cmd/internal/asm"
 	"cmd/internal/obj"
-	"cmd/internal/obj/i386"
+	"cmd/internal/obj/x86"
 )
 
 var (
@@ -60,7 +60,7 @@
 
 	asm.Thechar = '8'
 	asm.Thestring = "386"
-	asm.Thelinkarch = &i386.Link386
+	asm.Thelinkarch = &x86.Link386
 
 	asm.Main()
 }
@@ -90,620 +90,620 @@
 	{"SB", LSB, obj.NAME_EXTERN},
 	{"FP", LFP, obj.NAME_PARAM},
 	{"PC", LPC, obj.TYPE_BRANCH},
-	{"AL", LBREG, i386.REG_AL},
-	{"CL", LBREG, i386.REG_CL},
-	{"DL", LBREG, i386.REG_DL},
-	{"BL", LBREG, i386.REG_BL},
-	{"AH", LBREG, i386.REG_AH},
-	{"CH", LBREG, i386.REG_CH},
-	{"DH", LBREG, i386.REG_DH},
-	{"BH", LBREG, i386.REG_BH},
-	{"AX", LLREG, i386.REG_AX},
-	{"CX", LLREG, i386.REG_CX},
-	{"DX", LLREG, i386.REG_DX},
-	{"BX", LLREG, i386.REG_BX},
+	{"AL", LBREG, x86.REG_AL},
+	{"CL", LBREG, x86.REG_CL},
+	{"DL", LBREG, x86.REG_DL},
+	{"BL", LBREG, x86.REG_BL},
+	{"AH", LBREG, x86.REG_AH},
+	{"CH", LBREG, x86.REG_CH},
+	{"DH", LBREG, x86.REG_DH},
+	{"BH", LBREG, x86.REG_BH},
+	{"AX", LLREG, x86.REG_AX},
+	{"CX", LLREG, x86.REG_CX},
+	{"DX", LLREG, x86.REG_DX},
+	{"BX", LLREG, x86.REG_BX},
 	/*	"SP",		LLREG,	REG_SP,	*/
-	{"BP", LLREG, i386.REG_BP},
-	{"SI", LLREG, i386.REG_SI},
-	{"DI", LLREG, i386.REG_DI},
-	{"F0", LFREG, i386.REG_F0 + 0},
-	{"F1", LFREG, i386.REG_F0 + 1},
-	{"F2", LFREG, i386.REG_F0 + 2},
-	{"F3", LFREG, i386.REG_F0 + 3},
-	{"F4", LFREG, i386.REG_F0 + 4},
-	{"F5", LFREG, i386.REG_F0 + 5},
-	{"F6", LFREG, i386.REG_F0 + 6},
-	{"F7", LFREG, i386.REG_F0 + 7},
-	{"X0", LXREG, i386.REG_X0 + 0},
-	{"X1", LXREG, i386.REG_X0 + 1},
-	{"X2", LXREG, i386.REG_X0 + 2},
-	{"X3", LXREG, i386.REG_X0 + 3},
-	{"X4", LXREG, i386.REG_X0 + 4},
-	{"X5", LXREG, i386.REG_X0 + 5},
-	{"X6", LXREG, i386.REG_X0 + 6},
-	{"X7", LXREG, i386.REG_X0 + 7},
-	{"CS", LSREG, i386.REG_CS},
-	{"SS", LSREG, i386.REG_SS},
-	{"DS", LSREG, i386.REG_DS},
-	{"ES", LSREG, i386.REG_ES},
-	{"FS", LSREG, i386.REG_FS},
-	{"GS", LSREG, i386.REG_GS},
-	{"TLS", LSREG, i386.REG_TLS},
-	{"GDTR", LBREG, i386.REG_GDTR},
-	{"IDTR", LBREG, i386.REG_IDTR},
-	{"LDTR", LBREG, i386.REG_LDTR},
-	{"MSW", LBREG, i386.REG_MSW},
-	{"TASK", LBREG, i386.REG_TASK},
-	{"CR0", LBREG, i386.REG_CR + 0},
-	{"CR1", LBREG, i386.REG_CR + 1},
-	{"CR2", LBREG, i386.REG_CR + 2},
-	{"CR3", LBREG, i386.REG_CR + 3},
-	{"CR4", LBREG, i386.REG_CR + 4},
-	{"CR5", LBREG, i386.REG_CR + 5},
-	{"CR6", LBREG, i386.REG_CR + 6},
-	{"CR7", LBREG, i386.REG_CR + 7},
-	{"DR0", LBREG, i386.REG_DR + 0},
-	{"DR1", LBREG, i386.REG_DR + 1},
-	{"DR2", LBREG, i386.REG_DR + 2},
-	{"DR3", LBREG, i386.REG_DR + 3},
-	{"DR4", LBREG, i386.REG_DR + 4},
-	{"DR5", LBREG, i386.REG_DR + 5},
-	{"DR6", LBREG, i386.REG_DR + 6},
-	{"DR7", LBREG, i386.REG_DR + 7},
-	{"TR0", LBREG, i386.REG_TR + 0},
-	{"TR1", LBREG, i386.REG_TR + 1},
-	{"TR2", LBREG, i386.REG_TR + 2},
-	{"TR3", LBREG, i386.REG_TR + 3},
-	{"TR4", LBREG, i386.REG_TR + 4},
-	{"TR5", LBREG, i386.REG_TR + 5},
-	{"TR6", LBREG, i386.REG_TR + 6},
-	{"TR7", LBREG, i386.REG_TR + 7},
-	{"AAA", LTYPE0, i386.AAAA},
-	{"AAD", LTYPE0, i386.AAAD},
-	{"AAM", LTYPE0, i386.AAAM},
-	{"AAS", LTYPE0, i386.AAAS},
-	{"ADCB", LTYPE3, i386.AADCB},
-	{"ADCL", LTYPE3, i386.AADCL},
-	{"ADCW", LTYPE3, i386.AADCW},
-	{"ADDB", LTYPE3, i386.AADDB},
-	{"ADDL", LTYPE3, i386.AADDL},
-	{"ADDW", LTYPE3, i386.AADDW},
-	{"ADJSP", LTYPE2, i386.AADJSP},
-	{"ANDB", LTYPE3, i386.AANDB},
-	{"ANDL", LTYPE3, i386.AANDL},
-	{"ANDW", LTYPE3, i386.AANDW},
-	{"ARPL", LTYPE3, i386.AARPL},
-	{"BOUNDL", LTYPE3, i386.ABOUNDL},
-	{"BOUNDW", LTYPE3, i386.ABOUNDW},
-	{"BSFL", LTYPE3, i386.ABSFL},
-	{"BSFW", LTYPE3, i386.ABSFW},
-	{"BSRL", LTYPE3, i386.ABSRL},
-	{"BSRW", LTYPE3, i386.ABSRW},
-	{"BSWAPL", LTYPE1, i386.ABSWAPL},
-	{"BTCL", LTYPE3, i386.ABTCL},
-	{"BTCW", LTYPE3, i386.ABTCW},
-	{"BTL", LTYPE3, i386.ABTL},
-	{"BTRL", LTYPE3, i386.ABTRL},
-	{"BTRW", LTYPE3, i386.ABTRW},
-	{"BTSL", LTYPE3, i386.ABTSL},
-	{"BTSW", LTYPE3, i386.ABTSW},
-	{"BTW", LTYPE3, i386.ABTW},
-	{"BYTE", LTYPE2, i386.ABYTE},
+	{"BP", LLREG, x86.REG_BP},
+	{"SI", LLREG, x86.REG_SI},
+	{"DI", LLREG, x86.REG_DI},
+	{"F0", LFREG, x86.REG_F0 + 0},
+	{"F1", LFREG, x86.REG_F0 + 1},
+	{"F2", LFREG, x86.REG_F0 + 2},
+	{"F3", LFREG, x86.REG_F0 + 3},
+	{"F4", LFREG, x86.REG_F0 + 4},
+	{"F5", LFREG, x86.REG_F0 + 5},
+	{"F6", LFREG, x86.REG_F0 + 6},
+	{"F7", LFREG, x86.REG_F0 + 7},
+	{"X0", LXREG, x86.REG_X0 + 0},
+	{"X1", LXREG, x86.REG_X0 + 1},
+	{"X2", LXREG, x86.REG_X0 + 2},
+	{"X3", LXREG, x86.REG_X0 + 3},
+	{"X4", LXREG, x86.REG_X0 + 4},
+	{"X5", LXREG, x86.REG_X0 + 5},
+	{"X6", LXREG, x86.REG_X0 + 6},
+	{"X7", LXREG, x86.REG_X0 + 7},
+	{"CS", LSREG, x86.REG_CS},
+	{"SS", LSREG, x86.REG_SS},
+	{"DS", LSREG, x86.REG_DS},
+	{"ES", LSREG, x86.REG_ES},
+	{"FS", LSREG, x86.REG_FS},
+	{"GS", LSREG, x86.REG_GS},
+	{"TLS", LSREG, x86.REG_TLS},
+	{"GDTR", LBREG, x86.REG_GDTR},
+	{"IDTR", LBREG, x86.REG_IDTR},
+	{"LDTR", LBREG, x86.REG_LDTR},
+	{"MSW", LBREG, x86.REG_MSW},
+	{"TASK", LBREG, x86.REG_TASK},
+	{"CR0", LBREG, x86.REG_CR + 0},
+	{"CR1", LBREG, x86.REG_CR + 1},
+	{"CR2", LBREG, x86.REG_CR + 2},
+	{"CR3", LBREG, x86.REG_CR + 3},
+	{"CR4", LBREG, x86.REG_CR + 4},
+	{"CR5", LBREG, x86.REG_CR + 5},
+	{"CR6", LBREG, x86.REG_CR + 6},
+	{"CR7", LBREG, x86.REG_CR + 7},
+	{"DR0", LBREG, x86.REG_DR + 0},
+	{"DR1", LBREG, x86.REG_DR + 1},
+	{"DR2", LBREG, x86.REG_DR + 2},
+	{"DR3", LBREG, x86.REG_DR + 3},
+	{"DR4", LBREG, x86.REG_DR + 4},
+	{"DR5", LBREG, x86.REG_DR + 5},
+	{"DR6", LBREG, x86.REG_DR + 6},
+	{"DR7", LBREG, x86.REG_DR + 7},
+	{"TR0", LBREG, x86.REG_TR + 0},
+	{"TR1", LBREG, x86.REG_TR + 1},
+	{"TR2", LBREG, x86.REG_TR + 2},
+	{"TR3", LBREG, x86.REG_TR + 3},
+	{"TR4", LBREG, x86.REG_TR + 4},
+	{"TR5", LBREG, x86.REG_TR + 5},
+	{"TR6", LBREG, x86.REG_TR + 6},
+	{"TR7", LBREG, x86.REG_TR + 7},
+	{"AAA", LTYPE0, x86.AAAA},
+	{"AAD", LTYPE0, x86.AAAD},
+	{"AAM", LTYPE0, x86.AAAM},
+	{"AAS", LTYPE0, x86.AAAS},
+	{"ADCB", LTYPE3, x86.AADCB},
+	{"ADCL", LTYPE3, x86.AADCL},
+	{"ADCW", LTYPE3, x86.AADCW},
+	{"ADDB", LTYPE3, x86.AADDB},
+	{"ADDL", LTYPE3, x86.AADDL},
+	{"ADDW", LTYPE3, x86.AADDW},
+	{"ADJSP", LTYPE2, x86.AADJSP},
+	{"ANDB", LTYPE3, x86.AANDB},
+	{"ANDL", LTYPE3, x86.AANDL},
+	{"ANDW", LTYPE3, x86.AANDW},
+	{"ARPL", LTYPE3, x86.AARPL},
+	{"BOUNDL", LTYPE3, x86.ABOUNDL},
+	{"BOUNDW", LTYPE3, x86.ABOUNDW},
+	{"BSFL", LTYPE3, x86.ABSFL},
+	{"BSFW", LTYPE3, x86.ABSFW},
+	{"BSRL", LTYPE3, x86.ABSRL},
+	{"BSRW", LTYPE3, x86.ABSRW},
+	{"BSWAPL", LTYPE1, x86.ABSWAPL},
+	{"BTCL", LTYPE3, x86.ABTCL},
+	{"BTCW", LTYPE3, x86.ABTCW},
+	{"BTL", LTYPE3, x86.ABTL},
+	{"BTRL", LTYPE3, x86.ABTRL},
+	{"BTRW", LTYPE3, x86.ABTRW},
+	{"BTSL", LTYPE3, x86.ABTSL},
+	{"BTSW", LTYPE3, x86.ABTSW},
+	{"BTW", LTYPE3, x86.ABTW},
+	{"BYTE", LTYPE2, x86.ABYTE},
 	{"CALL", LTYPEC, obj.ACALL},
-	{"CLC", LTYPE0, i386.ACLC},
-	{"CLD", LTYPE0, i386.ACLD},
-	{"CLI", LTYPE0, i386.ACLI},
-	{"CLTS", LTYPE0, i386.ACLTS},
-	{"CMC", LTYPE0, i386.ACMC},
-	{"CMPB", LTYPE4, i386.ACMPB},
-	{"CMPL", LTYPE4, i386.ACMPL},
-	{"CMPW", LTYPE4, i386.ACMPW},
-	{"CMPSB", LTYPE0, i386.ACMPSB},
-	{"CMPSL", LTYPE0, i386.ACMPSL},
-	{"CMPSW", LTYPE0, i386.ACMPSW},
-	{"CMPXCHG8B", LTYPE1, i386.ACMPXCHG8B},
-	{"CMPXCHGB", LTYPE3, i386.ACMPXCHGB},
-	{"CMPXCHGL", LTYPE3, i386.ACMPXCHGL},
-	{"CMPXCHGW", LTYPE3, i386.ACMPXCHGW},
-	{"CPUID", LTYPE0, i386.ACPUID},
-	{"DAA", LTYPE0, i386.ADAA},
-	{"DAS", LTYPE0, i386.ADAS},
+	{"CLC", LTYPE0, x86.ACLC},
+	{"CLD", LTYPE0, x86.ACLD},
+	{"CLI", LTYPE0, x86.ACLI},
+	{"CLTS", LTYPE0, x86.ACLTS},
+	{"CMC", LTYPE0, x86.ACMC},
+	{"CMPB", LTYPE4, x86.ACMPB},
+	{"CMPL", LTYPE4, x86.ACMPL},
+	{"CMPW", LTYPE4, x86.ACMPW},
+	{"CMPSB", LTYPE0, x86.ACMPSB},
+	{"CMPSL", LTYPE0, x86.ACMPSL},
+	{"CMPSW", LTYPE0, x86.ACMPSW},
+	{"CMPXCHG8B", LTYPE1, x86.ACMPXCHG8B},
+	{"CMPXCHGB", LTYPE3, x86.ACMPXCHGB},
+	{"CMPXCHGL", LTYPE3, x86.ACMPXCHGL},
+	{"CMPXCHGW", LTYPE3, x86.ACMPXCHGW},
+	{"CPUID", LTYPE0, x86.ACPUID},
+	{"DAA", LTYPE0, x86.ADAA},
+	{"DAS", LTYPE0, x86.ADAS},
 	{"DATA", LTYPED, obj.ADATA},
-	{"DECB", LTYPE1, i386.ADECB},
-	{"DECL", LTYPE1, i386.ADECL},
-	{"DECW", LTYPE1, i386.ADECW},
-	{"DIVB", LTYPE2, i386.ADIVB},
-	{"DIVL", LTYPE2, i386.ADIVL},
-	{"DIVW", LTYPE2, i386.ADIVW},
+	{"DECB", LTYPE1, x86.ADECB},
+	{"DECL", LTYPE1, x86.ADECL},
+	{"DECW", LTYPE1, x86.ADECW},
+	{"DIVB", LTYPE2, x86.ADIVB},
+	{"DIVL", LTYPE2, x86.ADIVL},
+	{"DIVW", LTYPE2, x86.ADIVW},
 	{"END", LTYPE0, obj.AEND},
-	{"ENTER", LTYPE2, i386.AENTER},
+	{"ENTER", LTYPE2, x86.AENTER},
 	{"GLOBL", LTYPEG, obj.AGLOBL},
-	{"HLT", LTYPE0, i386.AHLT},
-	{"IDIVB", LTYPE2, i386.AIDIVB},
-	{"IDIVL", LTYPE2, i386.AIDIVL},
-	{"IDIVW", LTYPE2, i386.AIDIVW},
-	{"IMULB", LTYPE2, i386.AIMULB},
-	{"IMULL", LTYPEI, i386.AIMULL},
-	{"IMULW", LTYPEI, i386.AIMULW},
-	{"INB", LTYPE0, i386.AINB},
-	{"INL", LTYPE0, i386.AINL},
-	{"INW", LTYPE0, i386.AINW},
-	{"INCB", LTYPE1, i386.AINCB},
-	{"INCL", LTYPE1, i386.AINCL},
-	{"INCW", LTYPE1, i386.AINCW},
-	{"INSB", LTYPE0, i386.AINSB},
-	{"INSL", LTYPE0, i386.AINSL},
-	{"INSW", LTYPE0, i386.AINSW},
-	{"INT", LTYPE2, i386.AINT},
-	{"INTO", LTYPE0, i386.AINTO},
-	{"IRETL", LTYPE0, i386.AIRETL},
-	{"IRETW", LTYPE0, i386.AIRETW},
-	{"JOS", LTYPER, i386.AJOS},  /* overflow set (OF = 1) */
-	{"JO", LTYPER, i386.AJOS},   /* alternate */
-	{"JOC", LTYPER, i386.AJOC},  /* overflow clear (OF = 0) */
-	{"JNO", LTYPER, i386.AJOC},  /* alternate */
-	{"JCS", LTYPER, i386.AJCS},  /* carry set (CF = 1) */
-	{"JB", LTYPER, i386.AJCS},   /* alternate */
-	{"JC", LTYPER, i386.AJCS},   /* alternate */
-	{"JNAE", LTYPER, i386.AJCS}, /* alternate */
-	{"JLO", LTYPER, i386.AJCS},  /* alternate */
-	{"JCC", LTYPER, i386.AJCC},  /* carry clear (CF = 0) */
-	{"JAE", LTYPER, i386.AJCC},  /* alternate */
-	{"JNB", LTYPER, i386.AJCC},  /* alternate */
-	{"JNC", LTYPER, i386.AJCC},  /* alternate */
-	{"JHS", LTYPER, i386.AJCC},  /* alternate */
-	{"JEQ", LTYPER, i386.AJEQ},  /* equal (ZF = 1) */
-	{"JE", LTYPER, i386.AJEQ},   /* alternate */
-	{"JZ", LTYPER, i386.AJEQ},   /* alternate */
-	{"JNE", LTYPER, i386.AJNE},  /* not equal (ZF = 0) */
-	{"JNZ", LTYPER, i386.AJNE},  /* alternate */
-	{"JLS", LTYPER, i386.AJLS},  /* lower or same (unsigned) (CF = 1 || ZF = 1) */
-	{"JBE", LTYPER, i386.AJLS},  /* alternate */
-	{"JNA", LTYPER, i386.AJLS},  /* alternate */
-	{"JHI", LTYPER, i386.AJHI},  /* higher (unsigned) (CF = 0 && ZF = 0) */
-	{"JA", LTYPER, i386.AJHI},   /* alternate */
-	{"JNBE", LTYPER, i386.AJHI}, /* alternate */
-	{"JMI", LTYPER, i386.AJMI},  /* negative (minus) (SF = 1) */
-	{"JS", LTYPER, i386.AJMI},   /* alternate */
-	{"JPL", LTYPER, i386.AJPL},  /* non-negative (plus) (SF = 0) */
-	{"JNS", LTYPER, i386.AJPL},  /* alternate */
-	{"JPS", LTYPER, i386.AJPS},  /* parity set (PF = 1) */
-	{"JP", LTYPER, i386.AJPS},   /* alternate */
-	{"JPE", LTYPER, i386.AJPS},  /* alternate */
-	{"JPC", LTYPER, i386.AJPC},  /* parity clear (PF = 0) */
-	{"JNP", LTYPER, i386.AJPC},  /* alternate */
-	{"JPO", LTYPER, i386.AJPC},  /* alternate */
-	{"JLT", LTYPER, i386.AJLT},  /* less than (signed) (SF != OF) */
-	{"JL", LTYPER, i386.AJLT},   /* alternate */
-	{"JNGE", LTYPER, i386.AJLT}, /* alternate */
-	{"JGE", LTYPER, i386.AJGE},  /* greater than or equal (signed) (SF = OF) */
-	{"JNL", LTYPER, i386.AJGE},  /* alternate */
-	{"JLE", LTYPER, i386.AJLE},  /* less than or equal (signed) (ZF = 1 || SF != OF) */
-	{"JNG", LTYPER, i386.AJLE},  /* alternate */
-	{"JGT", LTYPER, i386.AJGT},  /* greater than (signed) (ZF = 0 && SF = OF) */
-	{"JG", LTYPER, i386.AJGT},   /* alternate */
-	{"JNLE", LTYPER, i386.AJGT}, /* alternate */
-	{"JCXZL", LTYPER, i386.AJCXZL},
-	{"JCXZW", LTYPER, i386.AJCXZW},
+	{"HLT", LTYPE0, x86.AHLT},
+	{"IDIVB", LTYPE2, x86.AIDIVB},
+	{"IDIVL", LTYPE2, x86.AIDIVL},
+	{"IDIVW", LTYPE2, x86.AIDIVW},
+	{"IMULB", LTYPE2, x86.AIMULB},
+	{"IMULL", LTYPEI, x86.AIMULL},
+	{"IMULW", LTYPEI, x86.AIMULW},
+	{"INB", LTYPE0, x86.AINB},
+	{"INL", LTYPE0, x86.AINL},
+	{"INW", LTYPE0, x86.AINW},
+	{"INCB", LTYPE1, x86.AINCB},
+	{"INCL", LTYPE1, x86.AINCL},
+	{"INCW", LTYPE1, x86.AINCW},
+	{"INSB", LTYPE0, x86.AINSB},
+	{"INSL", LTYPE0, x86.AINSL},
+	{"INSW", LTYPE0, x86.AINSW},
+	{"INT", LTYPE2, x86.AINT},
+	{"INTO", LTYPE0, x86.AINTO},
+	{"IRETL", LTYPE0, x86.AIRETL},
+	{"IRETW", LTYPE0, x86.AIRETW},
+	{"JOS", LTYPER, x86.AJOS},  /* overflow set (OF = 1) */
+	{"JO", LTYPER, x86.AJOS},   /* alternate */
+	{"JOC", LTYPER, x86.AJOC},  /* overflow clear (OF = 0) */
+	{"JNO", LTYPER, x86.AJOC},  /* alternate */
+	{"JCS", LTYPER, x86.AJCS},  /* carry set (CF = 1) */
+	{"JB", LTYPER, x86.AJCS},   /* alternate */
+	{"JC", LTYPER, x86.AJCS},   /* alternate */
+	{"JNAE", LTYPER, x86.AJCS}, /* alternate */
+	{"JLO", LTYPER, x86.AJCS},  /* alternate */
+	{"JCC", LTYPER, x86.AJCC},  /* carry clear (CF = 0) */
+	{"JAE", LTYPER, x86.AJCC},  /* alternate */
+	{"JNB", LTYPER, x86.AJCC},  /* alternate */
+	{"JNC", LTYPER, x86.AJCC},  /* alternate */
+	{"JHS", LTYPER, x86.AJCC},  /* alternate */
+	{"JEQ", LTYPER, x86.AJEQ},  /* equal (ZF = 1) */
+	{"JE", LTYPER, x86.AJEQ},   /* alternate */
+	{"JZ", LTYPER, x86.AJEQ},   /* alternate */
+	{"JNE", LTYPER, x86.AJNE},  /* not equal (ZF = 0) */
+	{"JNZ", LTYPER, x86.AJNE},  /* alternate */
+	{"JLS", LTYPER, x86.AJLS},  /* lower or same (unsigned) (CF = 1 || ZF = 1) */
+	{"JBE", LTYPER, x86.AJLS},  /* alternate */
+	{"JNA", LTYPER, x86.AJLS},  /* alternate */
+	{"JHI", LTYPER, x86.AJHI},  /* higher (unsigned) (CF = 0 && ZF = 0) */
+	{"JA", LTYPER, x86.AJHI},   /* alternate */
+	{"JNBE", LTYPER, x86.AJHI}, /* alternate */
+	{"JMI", LTYPER, x86.AJMI},  /* negative (minus) (SF = 1) */
+	{"JS", LTYPER, x86.AJMI},   /* alternate */
+	{"JPL", LTYPER, x86.AJPL},  /* non-negative (plus) (SF = 0) */
+	{"JNS", LTYPER, x86.AJPL},  /* alternate */
+	{"JPS", LTYPER, x86.AJPS},  /* parity set (PF = 1) */
+	{"JP", LTYPER, x86.AJPS},   /* alternate */
+	{"JPE", LTYPER, x86.AJPS},  /* alternate */
+	{"JPC", LTYPER, x86.AJPC},  /* parity clear (PF = 0) */
+	{"JNP", LTYPER, x86.AJPC},  /* alternate */
+	{"JPO", LTYPER, x86.AJPC},  /* alternate */
+	{"JLT", LTYPER, x86.AJLT},  /* less than (signed) (SF != OF) */
+	{"JL", LTYPER, x86.AJLT},   /* alternate */
+	{"JNGE", LTYPER, x86.AJLT}, /* alternate */
+	{"JGE", LTYPER, x86.AJGE},  /* greater than or equal (signed) (SF = OF) */
+	{"JNL", LTYPER, x86.AJGE},  /* alternate */
+	{"JLE", LTYPER, x86.AJLE},  /* less than or equal (signed) (ZF = 1 || SF != OF) */
+	{"JNG", LTYPER, x86.AJLE},  /* alternate */
+	{"JGT", LTYPER, x86.AJGT},  /* greater than (signed) (ZF = 0 && SF = OF) */
+	{"JG", LTYPER, x86.AJGT},   /* alternate */
+	{"JNLE", LTYPER, x86.AJGT}, /* alternate */
+	{"JCXZL", LTYPER, x86.AJCXZL},
+	{"JCXZW", LTYPER, x86.AJCXZW},
 	{"JMP", LTYPEC, obj.AJMP},
-	{"LAHF", LTYPE0, i386.ALAHF},
-	{"LARL", LTYPE3, i386.ALARL},
-	{"LARW", LTYPE3, i386.ALARW},
-	{"LEAL", LTYPE3, i386.ALEAL},
-	{"LEAW", LTYPE3, i386.ALEAW},
-	{"LEAVEL", LTYPE0, i386.ALEAVEL},
-	{"LEAVEW", LTYPE0, i386.ALEAVEW},
-	{"LOCK", LTYPE0, i386.ALOCK},
-	{"LODSB", LTYPE0, i386.ALODSB},
-	{"LODSL", LTYPE0, i386.ALODSL},
-	{"LODSW", LTYPE0, i386.ALODSW},
-	{"LONG", LTYPE2, i386.ALONG},
-	{"LOOP", LTYPER, i386.ALOOP},
-	{"LOOPEQ", LTYPER, i386.ALOOPEQ},
-	{"LOOPNE", LTYPER, i386.ALOOPNE},
-	{"LSLL", LTYPE3, i386.ALSLL},
-	{"LSLW", LTYPE3, i386.ALSLW},
-	{"MOVB", LTYPE3, i386.AMOVB},
-	{"MOVL", LTYPEM, i386.AMOVL},
-	{"MOVW", LTYPEM, i386.AMOVW},
-	{"MOVQ", LTYPEM, i386.AMOVQ},
-	{"MOVBLSX", LTYPE3, i386.AMOVBLSX},
-	{"MOVBLZX", LTYPE3, i386.AMOVBLZX},
-	{"MOVBWSX", LTYPE3, i386.AMOVBWSX},
-	{"MOVBWZX", LTYPE3, i386.AMOVBWZX},
-	{"MOVWLSX", LTYPE3, i386.AMOVWLSX},
-	{"MOVWLZX", LTYPE3, i386.AMOVWLZX},
-	{"MOVSB", LTYPE0, i386.AMOVSB},
-	{"MOVSL", LTYPE0, i386.AMOVSL},
-	{"MOVSW", LTYPE0, i386.AMOVSW},
-	{"MULB", LTYPE2, i386.AMULB},
-	{"MULL", LTYPE2, i386.AMULL},
-	{"MULW", LTYPE2, i386.AMULW},
-	{"NEGB", LTYPE1, i386.ANEGB},
-	{"NEGL", LTYPE1, i386.ANEGL},
-	{"NEGW", LTYPE1, i386.ANEGW},
+	{"LAHF", LTYPE0, x86.ALAHF},
+	{"LARL", LTYPE3, x86.ALARL},
+	{"LARW", LTYPE3, x86.ALARW},
+	{"LEAL", LTYPE3, x86.ALEAL},
+	{"LEAW", LTYPE3, x86.ALEAW},
+	{"LEAVEL", LTYPE0, x86.ALEAVEL},
+	{"LEAVEW", LTYPE0, x86.ALEAVEW},
+	{"LOCK", LTYPE0, x86.ALOCK},
+	{"LODSB", LTYPE0, x86.ALODSB},
+	{"LODSL", LTYPE0, x86.ALODSL},
+	{"LODSW", LTYPE0, x86.ALODSW},
+	{"LONG", LTYPE2, x86.ALONG},
+	{"LOOP", LTYPER, x86.ALOOP},
+	{"LOOPEQ", LTYPER, x86.ALOOPEQ},
+	{"LOOPNE", LTYPER, x86.ALOOPNE},
+	{"LSLL", LTYPE3, x86.ALSLL},
+	{"LSLW", LTYPE3, x86.ALSLW},
+	{"MOVB", LTYPE3, x86.AMOVB},
+	{"MOVL", LTYPEM, x86.AMOVL},
+	{"MOVW", LTYPEM, x86.AMOVW},
+	{"MOVQ", LTYPEM, x86.AMOVQ},
+	{"MOVBLSX", LTYPE3, x86.AMOVBLSX},
+	{"MOVBLZX", LTYPE3, x86.AMOVBLZX},
+	{"MOVBWSX", LTYPE3, x86.AMOVBWSX},
+	{"MOVBWZX", LTYPE3, x86.AMOVBWZX},
+	{"MOVWLSX", LTYPE3, x86.AMOVWLSX},
+	{"MOVWLZX", LTYPE3, x86.AMOVWLZX},
+	{"MOVSB", LTYPE0, x86.AMOVSB},
+	{"MOVSL", LTYPE0, x86.AMOVSL},
+	{"MOVSW", LTYPE0, x86.AMOVSW},
+	{"MULB", LTYPE2, x86.AMULB},
+	{"MULL", LTYPE2, x86.AMULL},
+	{"MULW", LTYPE2, x86.AMULW},
+	{"NEGB", LTYPE1, x86.ANEGB},
+	{"NEGL", LTYPE1, x86.ANEGL},
+	{"NEGW", LTYPE1, x86.ANEGW},
 	{"NOP", LTYPEN, obj.ANOP},
-	{"NOTB", LTYPE1, i386.ANOTB},
-	{"NOTL", LTYPE1, i386.ANOTL},
-	{"NOTW", LTYPE1, i386.ANOTW},
-	{"ORB", LTYPE3, i386.AORB},
-	{"ORL", LTYPE3, i386.AORL},
-	{"ORW", LTYPE3, i386.AORW},
-	{"OUTB", LTYPE0, i386.AOUTB},
-	{"OUTL", LTYPE0, i386.AOUTL},
-	{"OUTW", LTYPE0, i386.AOUTW},
-	{"OUTSB", LTYPE0, i386.AOUTSB},
-	{"OUTSL", LTYPE0, i386.AOUTSL},
-	{"OUTSW", LTYPE0, i386.AOUTSW},
-	{"PAUSE", LTYPEN, i386.APAUSE},
-	{"PINSRD", LTYPEX, i386.APINSRD},
-	{"POPAL", LTYPE0, i386.APOPAL},
-	{"POPAW", LTYPE0, i386.APOPAW},
-	{"POPFL", LTYPE0, i386.APOPFL},
-	{"POPFW", LTYPE0, i386.APOPFW},
-	{"POPL", LTYPE1, i386.APOPL},
-	{"POPW", LTYPE1, i386.APOPW},
-	{"PUSHAL", LTYPE0, i386.APUSHAL},
-	{"PUSHAW", LTYPE0, i386.APUSHAW},
-	{"PUSHFL", LTYPE0, i386.APUSHFL},
-	{"PUSHFW", LTYPE0, i386.APUSHFW},
-	{"PUSHL", LTYPE2, i386.APUSHL},
-	{"PUSHW", LTYPE2, i386.APUSHW},
-	{"RCLB", LTYPE3, i386.ARCLB},
-	{"RCLL", LTYPE3, i386.ARCLL},
-	{"RCLW", LTYPE3, i386.ARCLW},
-	{"RCRB", LTYPE3, i386.ARCRB},
-	{"RCRL", LTYPE3, i386.ARCRL},
-	{"RCRW", LTYPE3, i386.ARCRW},
-	{"RDTSC", LTYPE0, i386.ARDTSC},
-	{"REP", LTYPE0, i386.AREP},
-	{"REPN", LTYPE0, i386.AREPN},
+	{"NOTB", LTYPE1, x86.ANOTB},
+	{"NOTL", LTYPE1, x86.ANOTL},
+	{"NOTW", LTYPE1, x86.ANOTW},
+	{"ORB", LTYPE3, x86.AORB},
+	{"ORL", LTYPE3, x86.AORL},
+	{"ORW", LTYPE3, x86.AORW},
+	{"OUTB", LTYPE0, x86.AOUTB},
+	{"OUTL", LTYPE0, x86.AOUTL},
+	{"OUTW", LTYPE0, x86.AOUTW},
+	{"OUTSB", LTYPE0, x86.AOUTSB},
+	{"OUTSL", LTYPE0, x86.AOUTSL},
+	{"OUTSW", LTYPE0, x86.AOUTSW},
+	{"PAUSE", LTYPEN, x86.APAUSE},
+	{"PINSRD", LTYPEX, x86.APINSRD},
+	{"POPAL", LTYPE0, x86.APOPAL},
+	{"POPAW", LTYPE0, x86.APOPAW},
+	{"POPFL", LTYPE0, x86.APOPFL},
+	{"POPFW", LTYPE0, x86.APOPFW},
+	{"POPL", LTYPE1, x86.APOPL},
+	{"POPW", LTYPE1, x86.APOPW},
+	{"PUSHAL", LTYPE0, x86.APUSHAL},
+	{"PUSHAW", LTYPE0, x86.APUSHAW},
+	{"PUSHFL", LTYPE0, x86.APUSHFL},
+	{"PUSHFW", LTYPE0, x86.APUSHFW},
+	{"PUSHL", LTYPE2, x86.APUSHL},
+	{"PUSHW", LTYPE2, x86.APUSHW},
+	{"RCLB", LTYPE3, x86.ARCLB},
+	{"RCLL", LTYPE3, x86.ARCLL},
+	{"RCLW", LTYPE3, x86.ARCLW},
+	{"RCRB", LTYPE3, x86.ARCRB},
+	{"RCRL", LTYPE3, x86.ARCRL},
+	{"RCRW", LTYPE3, x86.ARCRW},
+	{"RDTSC", LTYPE0, x86.ARDTSC},
+	{"REP", LTYPE0, x86.AREP},
+	{"REPN", LTYPE0, x86.AREPN},
 	{"RET", LTYPE0, obj.ARET},
-	{"ROLB", LTYPE3, i386.AROLB},
-	{"ROLL", LTYPE3, i386.AROLL},
-	{"ROLW", LTYPE3, i386.AROLW},
-	{"RORB", LTYPE3, i386.ARORB},
-	{"RORL", LTYPE3, i386.ARORL},
-	{"RORW", LTYPE3, i386.ARORW},
-	{"SAHF", LTYPE0, i386.ASAHF},
-	{"SALB", LTYPE3, i386.ASALB},
-	{"SALL", LTYPE3, i386.ASALL},
-	{"SALW", LTYPE3, i386.ASALW},
-	{"SARB", LTYPE3, i386.ASARB},
-	{"SARL", LTYPE3, i386.ASARL},
-	{"SARW", LTYPE3, i386.ASARW},
-	{"SBBB", LTYPE3, i386.ASBBB},
-	{"SBBL", LTYPE3, i386.ASBBL},
-	{"SBBW", LTYPE3, i386.ASBBW},
-	{"SCASB", LTYPE0, i386.ASCASB},
-	{"SCASL", LTYPE0, i386.ASCASL},
-	{"SCASW", LTYPE0, i386.ASCASW},
-	{"SETCC", LTYPE1, i386.ASETCC}, /* see JCC etc above for condition codes */
-	{"SETCS", LTYPE1, i386.ASETCS},
-	{"SETEQ", LTYPE1, i386.ASETEQ},
-	{"SETGE", LTYPE1, i386.ASETGE},
-	{"SETGT", LTYPE1, i386.ASETGT},
-	{"SETHI", LTYPE1, i386.ASETHI},
-	{"SETLE", LTYPE1, i386.ASETLE},
-	{"SETLS", LTYPE1, i386.ASETLS},
-	{"SETLT", LTYPE1, i386.ASETLT},
-	{"SETMI", LTYPE1, i386.ASETMI},
-	{"SETNE", LTYPE1, i386.ASETNE},
-	{"SETOC", LTYPE1, i386.ASETOC},
-	{"SETOS", LTYPE1, i386.ASETOS},
-	{"SETPC", LTYPE1, i386.ASETPC},
-	{"SETPL", LTYPE1, i386.ASETPL},
-	{"SETPS", LTYPE1, i386.ASETPS},
-	{"CDQ", LTYPE0, i386.ACDQ},
-	{"CWD", LTYPE0, i386.ACWD},
-	{"SHLB", LTYPE3, i386.ASHLB},
-	{"SHLL", LTYPES, i386.ASHLL},
-	{"SHLW", LTYPES, i386.ASHLW},
-	{"SHRB", LTYPE3, i386.ASHRB},
-	{"SHRL", LTYPES, i386.ASHRL},
-	{"SHRW", LTYPES, i386.ASHRW},
-	{"STC", LTYPE0, i386.ASTC},
-	{"STD", LTYPE0, i386.ASTD},
-	{"STI", LTYPE0, i386.ASTI},
-	{"STOSB", LTYPE0, i386.ASTOSB},
-	{"STOSL", LTYPE0, i386.ASTOSL},
-	{"STOSW", LTYPE0, i386.ASTOSW},
-	{"SUBB", LTYPE3, i386.ASUBB},
-	{"SUBL", LTYPE3, i386.ASUBL},
-	{"SUBW", LTYPE3, i386.ASUBW},
-	{"SYSCALL", LTYPE0, i386.ASYSCALL},
-	{"TESTB", LTYPE3, i386.ATESTB},
-	{"TESTL", LTYPE3, i386.ATESTL},
-	{"TESTW", LTYPE3, i386.ATESTW},
+	{"ROLB", LTYPE3, x86.AROLB},
+	{"ROLL", LTYPE3, x86.AROLL},
+	{"ROLW", LTYPE3, x86.AROLW},
+	{"RORB", LTYPE3, x86.ARORB},
+	{"RORL", LTYPE3, x86.ARORL},
+	{"RORW", LTYPE3, x86.ARORW},
+	{"SAHF", LTYPE0, x86.ASAHF},
+	{"SALB", LTYPE3, x86.ASALB},
+	{"SALL", LTYPE3, x86.ASALL},
+	{"SALW", LTYPE3, x86.ASALW},
+	{"SARB", LTYPE3, x86.ASARB},
+	{"SARL", LTYPE3, x86.ASARL},
+	{"SARW", LTYPE3, x86.ASARW},
+	{"SBBB", LTYPE3, x86.ASBBB},
+	{"SBBL", LTYPE3, x86.ASBBL},
+	{"SBBW", LTYPE3, x86.ASBBW},
+	{"SCASB", LTYPE0, x86.ASCASB},
+	{"SCASL", LTYPE0, x86.ASCASL},
+	{"SCASW", LTYPE0, x86.ASCASW},
+	{"SETCC", LTYPE1, x86.ASETCC}, /* see JCC etc above for condition codes */
+	{"SETCS", LTYPE1, x86.ASETCS},
+	{"SETEQ", LTYPE1, x86.ASETEQ},
+	{"SETGE", LTYPE1, x86.ASETGE},
+	{"SETGT", LTYPE1, x86.ASETGT},
+	{"SETHI", LTYPE1, x86.ASETHI},
+	{"SETLE", LTYPE1, x86.ASETLE},
+	{"SETLS", LTYPE1, x86.ASETLS},
+	{"SETLT", LTYPE1, x86.ASETLT},
+	{"SETMI", LTYPE1, x86.ASETMI},
+	{"SETNE", LTYPE1, x86.ASETNE},
+	{"SETOC", LTYPE1, x86.ASETOC},
+	{"SETOS", LTYPE1, x86.ASETOS},
+	{"SETPC", LTYPE1, x86.ASETPC},
+	{"SETPL", LTYPE1, x86.ASETPL},
+	{"SETPS", LTYPE1, x86.ASETPS},
+	{"CDQ", LTYPE0, x86.ACDQ},
+	{"CWD", LTYPE0, x86.ACWD},
+	{"SHLB", LTYPE3, x86.ASHLB},
+	{"SHLL", LTYPES, x86.ASHLL},
+	{"SHLW", LTYPES, x86.ASHLW},
+	{"SHRB", LTYPE3, x86.ASHRB},
+	{"SHRL", LTYPES, x86.ASHRL},
+	{"SHRW", LTYPES, x86.ASHRW},
+	{"STC", LTYPE0, x86.ASTC},
+	{"STD", LTYPE0, x86.ASTD},
+	{"STI", LTYPE0, x86.ASTI},
+	{"STOSB", LTYPE0, x86.ASTOSB},
+	{"STOSL", LTYPE0, x86.ASTOSL},
+	{"STOSW", LTYPE0, x86.ASTOSW},
+	{"SUBB", LTYPE3, x86.ASUBB},
+	{"SUBL", LTYPE3, x86.ASUBL},
+	{"SUBW", LTYPE3, x86.ASUBW},
+	{"SYSCALL", LTYPE0, x86.ASYSCALL},
+	{"TESTB", LTYPE3, x86.ATESTB},
+	{"TESTL", LTYPE3, x86.ATESTL},
+	{"TESTW", LTYPE3, x86.ATESTW},
 	{"TEXT", LTYPET, obj.ATEXT},
-	{"VERR", LTYPE2, i386.AVERR},
-	{"VERW", LTYPE2, i386.AVERW},
-	{"WAIT", LTYPE0, i386.AWAIT},
-	{"WORD", LTYPE2, i386.AWORD},
-	{"XADDB", LTYPE3, i386.AXADDB},
-	{"XADDL", LTYPE3, i386.AXADDL},
-	{"XADDW", LTYPE3, i386.AXADDW},
-	{"XCHGB", LTYPE3, i386.AXCHGB},
-	{"XCHGL", LTYPE3, i386.AXCHGL},
-	{"XCHGW", LTYPE3, i386.AXCHGW},
-	{"XLAT", LTYPE2, i386.AXLAT},
-	{"XORB", LTYPE3, i386.AXORB},
-	{"XORL", LTYPE3, i386.AXORL},
-	{"XORW", LTYPE3, i386.AXORW},
-	{"CMOVLCC", LTYPE3, i386.ACMOVLCC},
-	{"CMOVLCS", LTYPE3, i386.ACMOVLCS},
-	{"CMOVLEQ", LTYPE3, i386.ACMOVLEQ},
-	{"CMOVLGE", LTYPE3, i386.ACMOVLGE},
-	{"CMOVLGT", LTYPE3, i386.ACMOVLGT},
-	{"CMOVLHI", LTYPE3, i386.ACMOVLHI},
-	{"CMOVLLE", LTYPE3, i386.ACMOVLLE},
-	{"CMOVLLS", LTYPE3, i386.ACMOVLLS},
-	{"CMOVLLT", LTYPE3, i386.ACMOVLLT},
-	{"CMOVLMI", LTYPE3, i386.ACMOVLMI},
-	{"CMOVLNE", LTYPE3, i386.ACMOVLNE},
-	{"CMOVLOC", LTYPE3, i386.ACMOVLOC},
-	{"CMOVLOS", LTYPE3, i386.ACMOVLOS},
-	{"CMOVLPC", LTYPE3, i386.ACMOVLPC},
-	{"CMOVLPL", LTYPE3, i386.ACMOVLPL},
-	{"CMOVLPS", LTYPE3, i386.ACMOVLPS},
-	{"CMOVWCC", LTYPE3, i386.ACMOVWCC},
-	{"CMOVWCS", LTYPE3, i386.ACMOVWCS},
-	{"CMOVWEQ", LTYPE3, i386.ACMOVWEQ},
-	{"CMOVWGE", LTYPE3, i386.ACMOVWGE},
-	{"CMOVWGT", LTYPE3, i386.ACMOVWGT},
-	{"CMOVWHI", LTYPE3, i386.ACMOVWHI},
-	{"CMOVWLE", LTYPE3, i386.ACMOVWLE},
-	{"CMOVWLS", LTYPE3, i386.ACMOVWLS},
-	{"CMOVWLT", LTYPE3, i386.ACMOVWLT},
-	{"CMOVWMI", LTYPE3, i386.ACMOVWMI},
-	{"CMOVWNE", LTYPE3, i386.ACMOVWNE},
-	{"CMOVWOC", LTYPE3, i386.ACMOVWOC},
-	{"CMOVWOS", LTYPE3, i386.ACMOVWOS},
-	{"CMOVWPC", LTYPE3, i386.ACMOVWPC},
-	{"CMOVWPL", LTYPE3, i386.ACMOVWPL},
-	{"CMOVWPS", LTYPE3, i386.ACMOVWPS},
-	{"FMOVB", LTYPE3, i386.AFMOVB},
-	{"FMOVBP", LTYPE3, i386.AFMOVBP},
-	{"FMOVD", LTYPE3, i386.AFMOVD},
-	{"FMOVDP", LTYPE3, i386.AFMOVDP},
-	{"FMOVF", LTYPE3, i386.AFMOVF},
-	{"FMOVFP", LTYPE3, i386.AFMOVFP},
-	{"FMOVL", LTYPE3, i386.AFMOVL},
-	{"FMOVLP", LTYPE3, i386.AFMOVLP},
-	{"FMOVV", LTYPE3, i386.AFMOVV},
-	{"FMOVVP", LTYPE3, i386.AFMOVVP},
-	{"FMOVW", LTYPE3, i386.AFMOVW},
-	{"FMOVWP", LTYPE3, i386.AFMOVWP},
-	{"FMOVX", LTYPE3, i386.AFMOVX},
-	{"FMOVXP", LTYPE3, i386.AFMOVXP},
-	{"FCMOVCC", LTYPE3, i386.AFCMOVCC},
-	{"FCMOVCS", LTYPE3, i386.AFCMOVCS},
-	{"FCMOVEQ", LTYPE3, i386.AFCMOVEQ},
-	{"FCMOVHI", LTYPE3, i386.AFCMOVHI},
-	{"FCMOVLS", LTYPE3, i386.AFCMOVLS},
-	{"FCMOVNE", LTYPE3, i386.AFCMOVNE},
-	{"FCMOVNU", LTYPE3, i386.AFCMOVNU},
-	{"FCMOVUN", LTYPE3, i386.AFCMOVUN},
-	{"FCOMB", LTYPE3, i386.AFCOMB},
-	{"FCOMBP", LTYPE3, i386.AFCOMBP},
-	{"FCOMD", LTYPE3, i386.AFCOMD},
-	{"FCOMDP", LTYPE3, i386.AFCOMDP},
-	{"FCOMDPP", LTYPE3, i386.AFCOMDPP},
-	{"FCOMF", LTYPE3, i386.AFCOMF},
-	{"FCOMFP", LTYPE3, i386.AFCOMFP},
-	{"FCOMI", LTYPE3, i386.AFCOMI},
-	{"FCOMIP", LTYPE3, i386.AFCOMIP},
-	{"FCOML", LTYPE3, i386.AFCOML},
-	{"FCOMLP", LTYPE3, i386.AFCOMLP},
-	{"FCOMW", LTYPE3, i386.AFCOMW},
-	{"FCOMWP", LTYPE3, i386.AFCOMWP},
-	{"FUCOM", LTYPE3, i386.AFUCOM},
-	{"FUCOMI", LTYPE3, i386.AFUCOMI},
-	{"FUCOMIP", LTYPE3, i386.AFUCOMIP},
-	{"FUCOMP", LTYPE3, i386.AFUCOMP},
-	{"FUCOMPP", LTYPE3, i386.AFUCOMPP},
-	{"FADDW", LTYPE3, i386.AFADDW},
-	{"FADDL", LTYPE3, i386.AFADDL},
-	{"FADDF", LTYPE3, i386.AFADDF},
-	{"FADDD", LTYPE3, i386.AFADDD},
-	{"FADDDP", LTYPE3, i386.AFADDDP},
-	{"FSUBDP", LTYPE3, i386.AFSUBDP},
-	{"FSUBW", LTYPE3, i386.AFSUBW},
-	{"FSUBL", LTYPE3, i386.AFSUBL},
-	{"FSUBF", LTYPE3, i386.AFSUBF},
-	{"FSUBD", LTYPE3, i386.AFSUBD},
-	{"FSUBRDP", LTYPE3, i386.AFSUBRDP},
-	{"FSUBRW", LTYPE3, i386.AFSUBRW},
-	{"FSUBRL", LTYPE3, i386.AFSUBRL},
-	{"FSUBRF", LTYPE3, i386.AFSUBRF},
-	{"FSUBRD", LTYPE3, i386.AFSUBRD},
-	{"FMULDP", LTYPE3, i386.AFMULDP},
-	{"FMULW", LTYPE3, i386.AFMULW},
-	{"FMULL", LTYPE3, i386.AFMULL},
-	{"FMULF", LTYPE3, i386.AFMULF},
-	{"FMULD", LTYPE3, i386.AFMULD},
-	{"FDIVDP", LTYPE3, i386.AFDIVDP},
-	{"FDIVW", LTYPE3, i386.AFDIVW},
-	{"FDIVL", LTYPE3, i386.AFDIVL},
-	{"FDIVF", LTYPE3, i386.AFDIVF},
-	{"FDIVD", LTYPE3, i386.AFDIVD},
-	{"FDIVRDP", LTYPE3, i386.AFDIVRDP},
-	{"FDIVRW", LTYPE3, i386.AFDIVRW},
-	{"FDIVRL", LTYPE3, i386.AFDIVRL},
-	{"FDIVRF", LTYPE3, i386.AFDIVRF},
-	{"FDIVRD", LTYPE3, i386.AFDIVRD},
-	{"FXCHD", LTYPE3, i386.AFXCHD},
-	{"FFREE", LTYPE1, i386.AFFREE},
-	{"FLDCW", LTYPE2, i386.AFLDCW},
-	{"FLDENV", LTYPE1, i386.AFLDENV},
-	{"FRSTOR", LTYPE2, i386.AFRSTOR},
-	{"FSAVE", LTYPE1, i386.AFSAVE},
-	{"FSTCW", LTYPE1, i386.AFSTCW},
-	{"FSTENV", LTYPE1, i386.AFSTENV},
-	{"FSTSW", LTYPE1, i386.AFSTSW},
-	{"F2XM1", LTYPE0, i386.AF2XM1},
-	{"FABS", LTYPE0, i386.AFABS},
-	{"FCHS", LTYPE0, i386.AFCHS},
-	{"FCLEX", LTYPE0, i386.AFCLEX},
-	{"FCOS", LTYPE0, i386.AFCOS},
-	{"FDECSTP", LTYPE0, i386.AFDECSTP},
-	{"FINCSTP", LTYPE0, i386.AFINCSTP},
-	{"FINIT", LTYPE0, i386.AFINIT},
-	{"FLD1", LTYPE0, i386.AFLD1},
-	{"FLDL2E", LTYPE0, i386.AFLDL2E},
-	{"FLDL2T", LTYPE0, i386.AFLDL2T},
-	{"FLDLG2", LTYPE0, i386.AFLDLG2},
-	{"FLDLN2", LTYPE0, i386.AFLDLN2},
-	{"FLDPI", LTYPE0, i386.AFLDPI},
-	{"FLDZ", LTYPE0, i386.AFLDZ},
-	{"FNOP", LTYPE0, i386.AFNOP},
-	{"FPATAN", LTYPE0, i386.AFPATAN},
-	{"FPREM", LTYPE0, i386.AFPREM},
-	{"FPREM1", LTYPE0, i386.AFPREM1},
-	{"FPTAN", LTYPE0, i386.AFPTAN},
-	{"FRNDINT", LTYPE0, i386.AFRNDINT},
-	{"FSCALE", LTYPE0, i386.AFSCALE},
-	{"FSIN", LTYPE0, i386.AFSIN},
-	{"FSINCOS", LTYPE0, i386.AFSINCOS},
-	{"FSQRT", LTYPE0, i386.AFSQRT},
-	{"FTST", LTYPE0, i386.AFTST},
-	{"FXAM", LTYPE0, i386.AFXAM},
-	{"FXTRACT", LTYPE0, i386.AFXTRACT},
-	{"FYL2X", LTYPE0, i386.AFYL2X},
-	{"FYL2XP1", LTYPE0, i386.AFYL2XP1},
-	{"LFENCE", LTYPE0, i386.ALFENCE},
-	{"MFENCE", LTYPE0, i386.AMFENCE},
-	{"SFENCE", LTYPE0, i386.ASFENCE},
-	{"EMMS", LTYPE0, i386.AEMMS},
-	{"PREFETCHT0", LTYPE2, i386.APREFETCHT0},
-	{"PREFETCHT1", LTYPE2, i386.APREFETCHT1},
-	{"PREFETCHT2", LTYPE2, i386.APREFETCHT2},
-	{"PREFETCHNTA", LTYPE2, i386.APREFETCHNTA},
+	{"VERR", LTYPE2, x86.AVERR},
+	{"VERW", LTYPE2, x86.AVERW},
+	{"WAIT", LTYPE0, x86.AWAIT},
+	{"WORD", LTYPE2, x86.AWORD},
+	{"XADDB", LTYPE3, x86.AXADDB},
+	{"XADDL", LTYPE3, x86.AXADDL},
+	{"XADDW", LTYPE3, x86.AXADDW},
+	{"XCHGB", LTYPE3, x86.AXCHGB},
+	{"XCHGL", LTYPE3, x86.AXCHGL},
+	{"XCHGW", LTYPE3, x86.AXCHGW},
+	{"XLAT", LTYPE2, x86.AXLAT},
+	{"XORB", LTYPE3, x86.AXORB},
+	{"XORL", LTYPE3, x86.AXORL},
+	{"XORW", LTYPE3, x86.AXORW},
+	{"CMOVLCC", LTYPE3, x86.ACMOVLCC},
+	{"CMOVLCS", LTYPE3, x86.ACMOVLCS},
+	{"CMOVLEQ", LTYPE3, x86.ACMOVLEQ},
+	{"CMOVLGE", LTYPE3, x86.ACMOVLGE},
+	{"CMOVLGT", LTYPE3, x86.ACMOVLGT},
+	{"CMOVLHI", LTYPE3, x86.ACMOVLHI},
+	{"CMOVLLE", LTYPE3, x86.ACMOVLLE},
+	{"CMOVLLS", LTYPE3, x86.ACMOVLLS},
+	{"CMOVLLT", LTYPE3, x86.ACMOVLLT},
+	{"CMOVLMI", LTYPE3, x86.ACMOVLMI},
+	{"CMOVLNE", LTYPE3, x86.ACMOVLNE},
+	{"CMOVLOC", LTYPE3, x86.ACMOVLOC},
+	{"CMOVLOS", LTYPE3, x86.ACMOVLOS},
+	{"CMOVLPC", LTYPE3, x86.ACMOVLPC},
+	{"CMOVLPL", LTYPE3, x86.ACMOVLPL},
+	{"CMOVLPS", LTYPE3, x86.ACMOVLPS},
+	{"CMOVWCC", LTYPE3, x86.ACMOVWCC},
+	{"CMOVWCS", LTYPE3, x86.ACMOVWCS},
+	{"CMOVWEQ", LTYPE3, x86.ACMOVWEQ},
+	{"CMOVWGE", LTYPE3, x86.ACMOVWGE},
+	{"CMOVWGT", LTYPE3, x86.ACMOVWGT},
+	{"CMOVWHI", LTYPE3, x86.ACMOVWHI},
+	{"CMOVWLE", LTYPE3, x86.ACMOVWLE},
+	{"CMOVWLS", LTYPE3, x86.ACMOVWLS},
+	{"CMOVWLT", LTYPE3, x86.ACMOVWLT},
+	{"CMOVWMI", LTYPE3, x86.ACMOVWMI},
+	{"CMOVWNE", LTYPE3, x86.ACMOVWNE},
+	{"CMOVWOC", LTYPE3, x86.ACMOVWOC},
+	{"CMOVWOS", LTYPE3, x86.ACMOVWOS},
+	{"CMOVWPC", LTYPE3, x86.ACMOVWPC},
+	{"CMOVWPL", LTYPE3, x86.ACMOVWPL},
+	{"CMOVWPS", LTYPE3, x86.ACMOVWPS},
+	{"FMOVB", LTYPE3, x86.AFMOVB},
+	{"FMOVBP", LTYPE3, x86.AFMOVBP},
+	{"FMOVD", LTYPE3, x86.AFMOVD},
+	{"FMOVDP", LTYPE3, x86.AFMOVDP},
+	{"FMOVF", LTYPE3, x86.AFMOVF},
+	{"FMOVFP", LTYPE3, x86.AFMOVFP},
+	{"FMOVL", LTYPE3, x86.AFMOVL},
+	{"FMOVLP", LTYPE3, x86.AFMOVLP},
+	{"FMOVV", LTYPE3, x86.AFMOVV},
+	{"FMOVVP", LTYPE3, x86.AFMOVVP},
+	{"FMOVW", LTYPE3, x86.AFMOVW},
+	{"FMOVWP", LTYPE3, x86.AFMOVWP},
+	{"FMOVX", LTYPE3, x86.AFMOVX},
+	{"FMOVXP", LTYPE3, x86.AFMOVXP},
+	{"FCMOVCC", LTYPE3, x86.AFCMOVCC},
+	{"FCMOVCS", LTYPE3, x86.AFCMOVCS},
+	{"FCMOVEQ", LTYPE3, x86.AFCMOVEQ},
+	{"FCMOVHI", LTYPE3, x86.AFCMOVHI},
+	{"FCMOVLS", LTYPE3, x86.AFCMOVLS},
+	{"FCMOVNE", LTYPE3, x86.AFCMOVNE},
+	{"FCMOVNU", LTYPE3, x86.AFCMOVNU},
+	{"FCMOVUN", LTYPE3, x86.AFCMOVUN},
+	{"FCOMB", LTYPE3, x86.AFCOMB},
+	{"FCOMBP", LTYPE3, x86.AFCOMBP},
+	{"FCOMD", LTYPE3, x86.AFCOMD},
+	{"FCOMDP", LTYPE3, x86.AFCOMDP},
+	{"FCOMDPP", LTYPE3, x86.AFCOMDPP},
+	{"FCOMF", LTYPE3, x86.AFCOMF},
+	{"FCOMFP", LTYPE3, x86.AFCOMFP},
+	{"FCOMI", LTYPE3, x86.AFCOMI},
+	{"FCOMIP", LTYPE3, x86.AFCOMIP},
+	{"FCOML", LTYPE3, x86.AFCOML},
+	{"FCOMLP", LTYPE3, x86.AFCOMLP},
+	{"FCOMW", LTYPE3, x86.AFCOMW},
+	{"FCOMWP", LTYPE3, x86.AFCOMWP},
+	{"FUCOM", LTYPE3, x86.AFUCOM},
+	{"FUCOMI", LTYPE3, x86.AFUCOMI},
+	{"FUCOMIP", LTYPE3, x86.AFUCOMIP},
+	{"FUCOMP", LTYPE3, x86.AFUCOMP},
+	{"FUCOMPP", LTYPE3, x86.AFUCOMPP},
+	{"FADDW", LTYPE3, x86.AFADDW},
+	{"FADDL", LTYPE3, x86.AFADDL},
+	{"FADDF", LTYPE3, x86.AFADDF},
+	{"FADDD", LTYPE3, x86.AFADDD},
+	{"FADDDP", LTYPE3, x86.AFADDDP},
+	{"FSUBDP", LTYPE3, x86.AFSUBDP},
+	{"FSUBW", LTYPE3, x86.AFSUBW},
+	{"FSUBL", LTYPE3, x86.AFSUBL},
+	{"FSUBF", LTYPE3, x86.AFSUBF},
+	{"FSUBD", LTYPE3, x86.AFSUBD},
+	{"FSUBRDP", LTYPE3, x86.AFSUBRDP},
+	{"FSUBRW", LTYPE3, x86.AFSUBRW},
+	{"FSUBRL", LTYPE3, x86.AFSUBRL},
+	{"FSUBRF", LTYPE3, x86.AFSUBRF},
+	{"FSUBRD", LTYPE3, x86.AFSUBRD},
+	{"FMULDP", LTYPE3, x86.AFMULDP},
+	{"FMULW", LTYPE3, x86.AFMULW},
+	{"FMULL", LTYPE3, x86.AFMULL},
+	{"FMULF", LTYPE3, x86.AFMULF},
+	{"FMULD", LTYPE3, x86.AFMULD},
+	{"FDIVDP", LTYPE3, x86.AFDIVDP},
+	{"FDIVW", LTYPE3, x86.AFDIVW},
+	{"FDIVL", LTYPE3, x86.AFDIVL},
+	{"FDIVF", LTYPE3, x86.AFDIVF},
+	{"FDIVD", LTYPE3, x86.AFDIVD},
+	{"FDIVRDP", LTYPE3, x86.AFDIVRDP},
+	{"FDIVRW", LTYPE3, x86.AFDIVRW},
+	{"FDIVRL", LTYPE3, x86.AFDIVRL},
+	{"FDIVRF", LTYPE3, x86.AFDIVRF},
+	{"FDIVRD", LTYPE3, x86.AFDIVRD},
+	{"FXCHD", LTYPE3, x86.AFXCHD},
+	{"FFREE", LTYPE1, x86.AFFREE},
+	{"FLDCW", LTYPE2, x86.AFLDCW},
+	{"FLDENV", LTYPE1, x86.AFLDENV},
+	{"FRSTOR", LTYPE2, x86.AFRSTOR},
+	{"FSAVE", LTYPE1, x86.AFSAVE},
+	{"FSTCW", LTYPE1, x86.AFSTCW},
+	{"FSTENV", LTYPE1, x86.AFSTENV},
+	{"FSTSW", LTYPE1, x86.AFSTSW},
+	{"F2XM1", LTYPE0, x86.AF2XM1},
+	{"FABS", LTYPE0, x86.AFABS},
+	{"FCHS", LTYPE0, x86.AFCHS},
+	{"FCLEX", LTYPE0, x86.AFCLEX},
+	{"FCOS", LTYPE0, x86.AFCOS},
+	{"FDECSTP", LTYPE0, x86.AFDECSTP},
+	{"FINCSTP", LTYPE0, x86.AFINCSTP},
+	{"FINIT", LTYPE0, x86.AFINIT},
+	{"FLD1", LTYPE0, x86.AFLD1},
+	{"FLDL2E", LTYPE0, x86.AFLDL2E},
+	{"FLDL2T", LTYPE0, x86.AFLDL2T},
+	{"FLDLG2", LTYPE0, x86.AFLDLG2},
+	{"FLDLN2", LTYPE0, x86.AFLDLN2},
+	{"FLDPI", LTYPE0, x86.AFLDPI},
+	{"FLDZ", LTYPE0, x86.AFLDZ},
+	{"FNOP", LTYPE0, x86.AFNOP},
+	{"FPATAN", LTYPE0, x86.AFPATAN},
+	{"FPREM", LTYPE0, x86.AFPREM},
+	{"FPREM1", LTYPE0, x86.AFPREM1},
+	{"FPTAN", LTYPE0, x86.AFPTAN},
+	{"FRNDINT", LTYPE0, x86.AFRNDINT},
+	{"FSCALE", LTYPE0, x86.AFSCALE},
+	{"FSIN", LTYPE0, x86.AFSIN},
+	{"FSINCOS", LTYPE0, x86.AFSINCOS},
+	{"FSQRT", LTYPE0, x86.AFSQRT},
+	{"FTST", LTYPE0, x86.AFTST},
+	{"FXAM", LTYPE0, x86.AFXAM},
+	{"FXTRACT", LTYPE0, x86.AFXTRACT},
+	{"FYL2X", LTYPE0, x86.AFYL2X},
+	{"FYL2XP1", LTYPE0, x86.AFYL2XP1},
+	{"LFENCE", LTYPE0, x86.ALFENCE},
+	{"MFENCE", LTYPE0, x86.AMFENCE},
+	{"SFENCE", LTYPE0, x86.ASFENCE},
+	{"EMMS", LTYPE0, x86.AEMMS},
+	{"PREFETCHT0", LTYPE2, x86.APREFETCHT0},
+	{"PREFETCHT1", LTYPE2, x86.APREFETCHT1},
+	{"PREFETCHT2", LTYPE2, x86.APREFETCHT2},
+	{"PREFETCHNTA", LTYPE2, x86.APREFETCHNTA},
 	{"UNDEF", LTYPE0, obj.AUNDEF},
-	{"ADDPD", LTYPE3, i386.AADDPD},
-	{"ADDPS", LTYPE3, i386.AADDPS},
-	{"ADDSD", LTYPE3, i386.AADDSD},
-	{"ADDSS", LTYPE3, i386.AADDSS},
-	{"AESENC", LTYPE3, i386.AAESENC},
-	{"ANDNPD", LTYPE3, i386.AANDNPD},
-	{"ANDNPS", LTYPE3, i386.AANDNPS},
-	{"ANDPD", LTYPE3, i386.AANDPD},
-	{"ANDPS", LTYPE3, i386.AANDPS},
-	{"CMPPD", LTYPEXC, i386.ACMPPD},
-	{"CMPPS", LTYPEXC, i386.ACMPPS},
-	{"CMPSD", LTYPEXC, i386.ACMPSD},
-	{"CMPSS", LTYPEXC, i386.ACMPSS},
-	{"COMISD", LTYPE3, i386.ACOMISD},
-	{"COMISS", LTYPE3, i386.ACOMISS},
-	{"CVTPL2PD", LTYPE3, i386.ACVTPL2PD},
-	{"CVTPL2PS", LTYPE3, i386.ACVTPL2PS},
-	{"CVTPD2PL", LTYPE3, i386.ACVTPD2PL},
-	{"CVTPD2PS", LTYPE3, i386.ACVTPD2PS},
-	{"CVTPS2PL", LTYPE3, i386.ACVTPS2PL},
-	{"CVTPS2PD", LTYPE3, i386.ACVTPS2PD},
-	{"CVTSD2SL", LTYPE3, i386.ACVTSD2SL},
-	{"CVTSD2SS", LTYPE3, i386.ACVTSD2SS},
-	{"CVTSL2SD", LTYPE3, i386.ACVTSL2SD},
-	{"CVTSL2SS", LTYPE3, i386.ACVTSL2SS},
-	{"CVTSS2SD", LTYPE3, i386.ACVTSS2SD},
-	{"CVTSS2SL", LTYPE3, i386.ACVTSS2SL},
-	{"CVTTPD2PL", LTYPE3, i386.ACVTTPD2PL},
-	{"CVTTPS2PL", LTYPE3, i386.ACVTTPS2PL},
-	{"CVTTSD2SL", LTYPE3, i386.ACVTTSD2SL},
-	{"CVTTSS2SL", LTYPE3, i386.ACVTTSS2SL},
-	{"DIVPD", LTYPE3, i386.ADIVPD},
-	{"DIVPS", LTYPE3, i386.ADIVPS},
-	{"DIVSD", LTYPE3, i386.ADIVSD},
-	{"DIVSS", LTYPE3, i386.ADIVSS},
-	{"MASKMOVOU", LTYPE3, i386.AMASKMOVOU},
-	{"MASKMOVDQU", LTYPE3, i386.AMASKMOVOU}, /* syn */
-	{"MAXPD", LTYPE3, i386.AMAXPD},
-	{"MAXPS", LTYPE3, i386.AMAXPS},
-	{"MAXSD", LTYPE3, i386.AMAXSD},
-	{"MAXSS", LTYPE3, i386.AMAXSS},
-	{"MINPD", LTYPE3, i386.AMINPD},
-	{"MINPS", LTYPE3, i386.AMINPS},
-	{"MINSD", LTYPE3, i386.AMINSD},
-	{"MINSS", LTYPE3, i386.AMINSS},
-	{"MOVAPD", LTYPE3, i386.AMOVAPD},
-	{"MOVAPS", LTYPE3, i386.AMOVAPS},
-	{"MOVO", LTYPE3, i386.AMOVO},
-	{"MOVOA", LTYPE3, i386.AMOVO}, /* syn */
-	{"MOVOU", LTYPE3, i386.AMOVOU},
-	{"MOVHLPS", LTYPE3, i386.AMOVHLPS},
-	{"MOVHPD", LTYPE3, i386.AMOVHPD},
-	{"MOVHPS", LTYPE3, i386.AMOVHPS},
-	{"MOVLHPS", LTYPE3, i386.AMOVLHPS},
-	{"MOVLPD", LTYPE3, i386.AMOVLPD},
-	{"MOVLPS", LTYPE3, i386.AMOVLPS},
-	{"MOVMSKPD", LTYPE3, i386.AMOVMSKPD},
-	{"MOVMSKPS", LTYPE3, i386.AMOVMSKPS},
-	{"MOVNTO", LTYPE3, i386.AMOVNTO},
-	{"MOVNTDQ", LTYPE3, i386.AMOVNTO}, /* syn */
-	{"MOVNTPD", LTYPE3, i386.AMOVNTPD},
-	{"MOVNTPS", LTYPE3, i386.AMOVNTPS},
-	{"MOVSD", LTYPE3, i386.AMOVSD},
-	{"MOVSS", LTYPE3, i386.AMOVSS},
-	{"MOVUPD", LTYPE3, i386.AMOVUPD},
-	{"MOVUPS", LTYPE3, i386.AMOVUPS},
-	{"MULPD", LTYPE3, i386.AMULPD},
-	{"MULPS", LTYPE3, i386.AMULPS},
-	{"MULSD", LTYPE3, i386.AMULSD},
-	{"MULSS", LTYPE3, i386.AMULSS},
-	{"ORPD", LTYPE3, i386.AORPD},
-	{"ORPS", LTYPE3, i386.AORPS},
-	{"PADDQ", LTYPE3, i386.APADDQ},
-	{"PAND", LTYPE3, i386.APAND},
-	{"PCMPEQB", LTYPE3, i386.APCMPEQB},
-	{"PMAXSW", LTYPE3, i386.APMAXSW},
-	{"PMAXUB", LTYPE3, i386.APMAXUB},
-	{"PMINSW", LTYPE3, i386.APMINSW},
-	{"PMINUB", LTYPE3, i386.APMINUB},
-	{"PMOVMSKB", LTYPE3, i386.APMOVMSKB},
-	{"PSADBW", LTYPE3, i386.APSADBW},
-	{"PSHUFB", LTYPE3, i386.APSHUFB},
-	{"PSHUFHW", LTYPEX, i386.APSHUFHW},
-	{"PSHUFL", LTYPEX, i386.APSHUFL},
-	{"PSHUFLW", LTYPEX, i386.APSHUFLW},
-	{"PSUBB", LTYPE3, i386.APSUBB},
-	{"PSUBL", LTYPE3, i386.APSUBL},
-	{"PSUBQ", LTYPE3, i386.APSUBQ},
-	{"PSUBSB", LTYPE3, i386.APSUBSB},
-	{"PSUBSW", LTYPE3, i386.APSUBSW},
-	{"PSUBUSB", LTYPE3, i386.APSUBUSB},
-	{"PSUBUSW", LTYPE3, i386.APSUBUSW},
-	{"PSUBW", LTYPE3, i386.APSUBW},
-	{"PUNPCKHQDQ", LTYPE3, i386.APUNPCKHQDQ},
-	{"PUNPCKLQDQ", LTYPE3, i386.APUNPCKLQDQ},
-	{"PXOR", LTYPE3, i386.APXOR},
-	{"RCPPS", LTYPE3, i386.ARCPPS},
-	{"RCPSS", LTYPE3, i386.ARCPSS},
-	{"RSQRTPS", LTYPE3, i386.ARSQRTPS},
-	{"RSQRTSS", LTYPE3, i386.ARSQRTSS},
-	{"SQRTPD", LTYPE3, i386.ASQRTPD},
-	{"SQRTPS", LTYPE3, i386.ASQRTPS},
-	{"SQRTSD", LTYPE3, i386.ASQRTSD},
-	{"SQRTSS", LTYPE3, i386.ASQRTSS},
-	{"SUBPD", LTYPE3, i386.ASUBPD},
-	{"SUBPS", LTYPE3, i386.ASUBPS},
-	{"SUBSD", LTYPE3, i386.ASUBSD},
-	{"SUBSS", LTYPE3, i386.ASUBSS},
-	{"UCOMISD", LTYPE3, i386.AUCOMISD},
-	{"UCOMISS", LTYPE3, i386.AUCOMISS},
-	{"UNPCKHPD", LTYPE3, i386.AUNPCKHPD},
-	{"UNPCKHPS", LTYPE3, i386.AUNPCKHPS},
-	{"UNPCKLPD", LTYPE3, i386.AUNPCKLPD},
-	{"UNPCKLPS", LTYPE3, i386.AUNPCKLPS},
-	{"XORPD", LTYPE3, i386.AXORPD},
-	{"XORPS", LTYPE3, i386.AXORPS},
+	{"ADDPD", LTYPE3, x86.AADDPD},
+	{"ADDPS", LTYPE3, x86.AADDPS},
+	{"ADDSD", LTYPE3, x86.AADDSD},
+	{"ADDSS", LTYPE3, x86.AADDSS},
+	{"AESENC", LTYPE3, x86.AAESENC},
+	{"ANDNPD", LTYPE3, x86.AANDNPD},
+	{"ANDNPS", LTYPE3, x86.AANDNPS},
+	{"ANDPD", LTYPE3, x86.AANDPD},
+	{"ANDPS", LTYPE3, x86.AANDPS},
+	{"CMPPD", LTYPEXC, x86.ACMPPD},
+	{"CMPPS", LTYPEXC, x86.ACMPPS},
+	{"CMPSD", LTYPEXC, x86.ACMPSD},
+	{"CMPSS", LTYPEXC, x86.ACMPSS},
+	{"COMISD", LTYPE3, x86.ACOMISD},
+	{"COMISS", LTYPE3, x86.ACOMISS},
+	{"CVTPL2PD", LTYPE3, x86.ACVTPL2PD},
+	{"CVTPL2PS", LTYPE3, x86.ACVTPL2PS},
+	{"CVTPD2PL", LTYPE3, x86.ACVTPD2PL},
+	{"CVTPD2PS", LTYPE3, x86.ACVTPD2PS},
+	{"CVTPS2PL", LTYPE3, x86.ACVTPS2PL},
+	{"CVTPS2PD", LTYPE3, x86.ACVTPS2PD},
+	{"CVTSD2SL", LTYPE3, x86.ACVTSD2SL},
+	{"CVTSD2SS", LTYPE3, x86.ACVTSD2SS},
+	{"CVTSL2SD", LTYPE3, x86.ACVTSL2SD},
+	{"CVTSL2SS", LTYPE3, x86.ACVTSL2SS},
+	{"CVTSS2SD", LTYPE3, x86.ACVTSS2SD},
+	{"CVTSS2SL", LTYPE3, x86.ACVTSS2SL},
+	{"CVTTPD2PL", LTYPE3, x86.ACVTTPD2PL},
+	{"CVTTPS2PL", LTYPE3, x86.ACVTTPS2PL},
+	{"CVTTSD2SL", LTYPE3, x86.ACVTTSD2SL},
+	{"CVTTSS2SL", LTYPE3, x86.ACVTTSS2SL},
+	{"DIVPD", LTYPE3, x86.ADIVPD},
+	{"DIVPS", LTYPE3, x86.ADIVPS},
+	{"DIVSD", LTYPE3, x86.ADIVSD},
+	{"DIVSS", LTYPE3, x86.ADIVSS},
+	{"MASKMOVOU", LTYPE3, x86.AMASKMOVOU},
+	{"MASKMOVDQU", LTYPE3, x86.AMASKMOVOU}, /* syn */
+	{"MAXPD", LTYPE3, x86.AMAXPD},
+	{"MAXPS", LTYPE3, x86.AMAXPS},
+	{"MAXSD", LTYPE3, x86.AMAXSD},
+	{"MAXSS", LTYPE3, x86.AMAXSS},
+	{"MINPD", LTYPE3, x86.AMINPD},
+	{"MINPS", LTYPE3, x86.AMINPS},
+	{"MINSD", LTYPE3, x86.AMINSD},
+	{"MINSS", LTYPE3, x86.AMINSS},
+	{"MOVAPD", LTYPE3, x86.AMOVAPD},
+	{"MOVAPS", LTYPE3, x86.AMOVAPS},
+	{"MOVO", LTYPE3, x86.AMOVO},
+	{"MOVOA", LTYPE3, x86.AMOVO}, /* syn */
+	{"MOVOU", LTYPE3, x86.AMOVOU},
+	{"MOVHLPS", LTYPE3, x86.AMOVHLPS},
+	{"MOVHPD", LTYPE3, x86.AMOVHPD},
+	{"MOVHPS", LTYPE3, x86.AMOVHPS},
+	{"MOVLHPS", LTYPE3, x86.AMOVLHPS},
+	{"MOVLPD", LTYPE3, x86.AMOVLPD},
+	{"MOVLPS", LTYPE3, x86.AMOVLPS},
+	{"MOVMSKPD", LTYPE3, x86.AMOVMSKPD},
+	{"MOVMSKPS", LTYPE3, x86.AMOVMSKPS},
+	{"MOVNTO", LTYPE3, x86.AMOVNTO},
+	{"MOVNTDQ", LTYPE3, x86.AMOVNTO}, /* syn */
+	{"MOVNTPD", LTYPE3, x86.AMOVNTPD},
+	{"MOVNTPS", LTYPE3, x86.AMOVNTPS},
+	{"MOVSD", LTYPE3, x86.AMOVSD},
+	{"MOVSS", LTYPE3, x86.AMOVSS},
+	{"MOVUPD", LTYPE3, x86.AMOVUPD},
+	{"MOVUPS", LTYPE3, x86.AMOVUPS},
+	{"MULPD", LTYPE3, x86.AMULPD},
+	{"MULPS", LTYPE3, x86.AMULPS},
+	{"MULSD", LTYPE3, x86.AMULSD},
+	{"MULSS", LTYPE3, x86.AMULSS},
+	{"ORPD", LTYPE3, x86.AORPD},
+	{"ORPS", LTYPE3, x86.AORPS},
+	{"PADDQ", LTYPE3, x86.APADDQ},
+	{"PAND", LTYPE3, x86.APAND},
+	{"PCMPEQB", LTYPE3, x86.APCMPEQB},
+	{"PMAXSW", LTYPE3, x86.APMAXSW},
+	{"PMAXUB", LTYPE3, x86.APMAXUB},
+	{"PMINSW", LTYPE3, x86.APMINSW},
+	{"PMINUB", LTYPE3, x86.APMINUB},
+	{"PMOVMSKB", LTYPE3, x86.APMOVMSKB},
+	{"PSADBW", LTYPE3, x86.APSADBW},
+	{"PSHUFB", LTYPE3, x86.APSHUFB},
+	{"PSHUFHW", LTYPEX, x86.APSHUFHW},
+	{"PSHUFL", LTYPEX, x86.APSHUFL},
+	{"PSHUFLW", LTYPEX, x86.APSHUFLW},
+	{"PSUBB", LTYPE3, x86.APSUBB},
+	{"PSUBL", LTYPE3, x86.APSUBL},
+	{"PSUBQ", LTYPE3, x86.APSUBQ},
+	{"PSUBSB", LTYPE3, x86.APSUBSB},
+	{"PSUBSW", LTYPE3, x86.APSUBSW},
+	{"PSUBUSB", LTYPE3, x86.APSUBUSB},
+	{"PSUBUSW", LTYPE3, x86.APSUBUSW},
+	{"PSUBW", LTYPE3, x86.APSUBW},
+	{"PUNPCKHQDQ", LTYPE3, x86.APUNPCKHQDQ},
+	{"PUNPCKLQDQ", LTYPE3, x86.APUNPCKLQDQ},
+	{"PXOR", LTYPE3, x86.APXOR},
+	{"RCPPS", LTYPE3, x86.ARCPPS},
+	{"RCPSS", LTYPE3, x86.ARCPSS},
+	{"RSQRTPS", LTYPE3, x86.ARSQRTPS},
+	{"RSQRTSS", LTYPE3, x86.ARSQRTSS},
+	{"SQRTPD", LTYPE3, x86.ASQRTPD},
+	{"SQRTPS", LTYPE3, x86.ASQRTPS},
+	{"SQRTSD", LTYPE3, x86.ASQRTSD},
+	{"SQRTSS", LTYPE3, x86.ASQRTSS},
+	{"SUBPD", LTYPE3, x86.ASUBPD},
+	{"SUBPS", LTYPE3, x86.ASUBPS},
+	{"SUBSD", LTYPE3, x86.ASUBSD},
+	{"SUBSS", LTYPE3, x86.ASUBSS},
+	{"UCOMISD", LTYPE3, x86.AUCOMISD},
+	{"UCOMISS", LTYPE3, x86.AUCOMISS},
+	{"UNPCKHPD", LTYPE3, x86.AUNPCKHPD},
+	{"UNPCKHPS", LTYPE3, x86.AUNPCKHPS},
+	{"UNPCKLPD", LTYPE3, x86.AUNPCKLPD},
+	{"UNPCKLPS", LTYPE3, x86.AUNPCKLPS},
+	{"XORPD", LTYPE3, x86.AXORPD},
+	{"XORPS", LTYPE3, x86.AXORPS},
 	{"USEFIELD", LTYPEN, obj.AUSEFIELD},
 	{"PCDATA", LTYPEPC, obj.APCDATA},
 	{"FUNCDATA", LTYPEF, obj.AFUNCDATA},
 }
 
 func cinit() {
-	nullgen.Type = i386.REG_NONE
-	nullgen.Index = i386.REG_NONE
+	nullgen.Type = x86.REG_NONE
+	nullgen.Index = x86.REG_NONE
 }
 
 func checkscale(scale int16) {
diff --git a/src/cmd/old8a/y.go b/src/cmd/old8a/y.go
index 1975178..c727aca 100644
--- a/src/cmd/old8a/y.go
+++ b/src/cmd/old8a/y.go
@@ -7,7 +7,7 @@
 import (
 	"cmd/internal/asm"
 	"cmd/internal/obj"
-	. "cmd/internal/obj/i386"
+	. "cmd/internal/obj/x86"
 )
 
 //line a.y:41
@@ -123,103 +123,107 @@
 var yyTokenNames []string
 var yyStates []string
 
-const yyLast = 556
+const yyLast = 594
 
 var yyAct = []int{
 
-	50, 226, 120, 40, 48, 3, 268, 207, 62, 79,
-	77, 169, 49, 267, 266, 72, 60, 262, 84, 254,
-	52, 81, 82, 71, 70, 252, 83, 97, 115, 65,
-	80, 240, 109, 99, 238, 109, 91, 93, 95, 236,
-	220, 218, 101, 103, 209, 208, 170, 239, 104, 206,
-	233, 210, 109, 168, 173, 142, 117, 118, 119, 135,
-	108, 116, 112, 110, 125, 63, 248, 56, 55, 78,
-	72, 230, 229, 225, 224, 109, 136, 84, 223, 133,
-	81, 82, 140, 141, 126, 83, 153, 137, 143, 80,
-	53, 152, 150, 149, 42, 44, 47, 43, 45, 139,
-	61, 46, 85, 148, 54, 147, 146, 145, 76, 63,
-	51, 39, 57, 154, 67, 144, 134, 132, 131, 39,
-	124, 36, 34, 175, 176, 30, 222, 31, 33, 32,
-	109, 117, 221, 58, 242, 72, 241, 183, 235, 111,
-	165, 167, 140, 141, 182, 216, 166, 214, 172, 181,
-	250, 251, 191, 193, 195, 215, 109, 109, 109, 109,
-	109, 255, 194, 109, 109, 109, 189, 190, 165, 167,
-	211, 183, 56, 130, 166, 56, 55, 217, 263, 117,
-	256, 247, 37, 151, 196, 197, 198, 199, 200, 228,
-	111, 203, 204, 205, 260, 53, 41, 35, 53, 56,
-	55, 88, 109, 109, 128, 127, 259, 58, 234, 54,
-	73, 227, 54, 237, 253, 129, 87, 57, 74, 212,
-	57, 257, 53, 246, 243, 105, 106, 113, 244, 202,
-	231, 232, 180, 114, 245, 121, 54, 122, 123, 249,
-	122, 123, 74, 174, 57, 184, 185, 186, 187, 188,
-	258, 7, 201, 22, 261, 42, 44, 47, 43, 45,
-	264, 265, 46, 9, 10, 11, 12, 13, 17, 27,
-	18, 14, 28, 19, 20, 21, 29, 23, 24, 25,
-	26, 56, 55, 138, 163, 162, 160, 161, 155, 156,
-	157, 158, 159, 4, 16, 8, 15, 5, 56, 55,
-	6, 107, 56, 55, 53, 157, 158, 159, 42, 44,
-	47, 43, 45, 2, 1, 46, 85, 102, 54, 100,
-	98, 53, 96, 63, 51, 53, 57, 56, 55, 42,
-	44, 47, 43, 45, 94, 54, 46, 58, 92, 54,
-	63, 74, 90, 57, 63, 51, 86, 57, 56, 55,
-	53, 75, 66, 64, 42, 44, 47, 43, 45, 59,
-	68, 46, 58, 213, 54, 0, 0, 0, 89, 0,
-	51, 53, 57, 56, 55, 42, 44, 47, 43, 45,
-	0, 0, 46, 58, 0, 54, 0, 0, 0, 38,
-	0, 51, 0, 57, 56, 55, 53, 0, 0, 0,
-	42, 44, 47, 43, 45, 0, 0, 46, 58, 0,
-	54, 155, 156, 157, 158, 159, 51, 53, 57, 0,
-	0, 42, 44, 47, 43, 45, 0, 0, 46, 56,
-	55, 54, 0, 0, 0, 0, 0, 51, 0, 57,
+	50, 226, 40, 3, 79, 77, 120, 49, 62, 207,
+	268, 267, 48, 169, 266, 72, 60, 262, 84, 70,
+	81, 254, 252, 71, 240, 80, 83, 115, 238, 65,
+	82, 236, 109, 99, 220, 109, 91, 93, 95, 52,
+	218, 209, 101, 103, 208, 170, 239, 233, 210, 173,
+	63, 206, 109, 56, 55, 168, 117, 118, 119, 108,
+	142, 135, 110, 116, 125, 112, 248, 104, 230, 229,
+	72, 225, 224, 223, 133, 109, 53, 84, 153, 81,
+	136, 140, 137, 152, 80, 83, 61, 150, 73, 82,
+	54, 141, 143, 149, 69, 63, 74, 39, 57, 148,
+	67, 147, 146, 126, 145, 39, 144, 134, 132, 131,
+	97, 154, 124, 36, 30, 34, 31, 33, 139, 32,
+	222, 221, 58, 175, 176, 111, 216, 242, 214, 241,
+	109, 117, 56, 55, 183, 72, 215, 165, 167, 182,
+	235, 140, 172, 166, 250, 251, 255, 183, 263, 181,
+	187, 141, 191, 193, 195, 53, 109, 109, 109, 109,
+	109, 256, 194, 109, 109, 109, 189, 190, 247, 54,
+	211, 228, 56, 130, 63, 74, 111, 57, 37, 117,
+	35, 217, 41, 196, 197, 198, 199, 200, 165, 167,
+	203, 204, 205, 227, 166, 53, 151, 88, 121, 87,
+	122, 123, 109, 109, 128, 127, 260, 58, 234, 54,
+	259, 105, 106, 237, 253, 129, 212, 57, 180, 42,
+	44, 47, 43, 45, 243, 257, 46, 244, 246, 231,
+	232, 184, 185, 186, 245, 188, 157, 158, 159, 249,
 	164, 163, 162, 160, 161, 155, 156, 157, 158, 159,
-	56, 55, 53, 0, 56, 55, 0, 56, 55, 0,
-	0, 0, 0, 0, 73, 0, 54, 0, 0, 0,
-	69, 63, 74, 53, 57, 56, 55, 53, 56, 178,
-	53, 0, 219, 0, 0, 56, 55, 54, 0, 171,
-	0, 54, 58, 74, 54, 57, 192, 74, 53, 57,
-	51, 53, 57, 0, 0, 0, 0, 179, 53, 0,
-	177, 0, 54, 0, 0, 54, 0, 0, 74, 0,
-	57, 74, 54, 57, 0, 0, 0, 0, 74, 0,
-	57, 164, 163, 162, 160, 161, 155, 156, 157, 158,
-	159, 162, 160, 161, 155, 156, 157, 158, 159, 160,
-	161, 155, 156, 157, 158, 159,
+	258, 7, 122, 123, 261, 155, 156, 157, 158, 159,
+	264, 265, 202, 9, 10, 11, 12, 13, 17, 27,
+	18, 14, 28, 19, 20, 21, 29, 23, 24, 25,
+	26, 56, 55, 78, 174, 201, 22, 16, 15, 171,
+	6, 107, 2, 4, 1, 8, 102, 5, 100, 98,
+	96, 94, 92, 90, 53, 56, 55, 138, 42, 44,
+	47, 43, 45, 86, 75, 46, 85, 66, 54, 64,
+	59, 68, 76, 63, 51, 213, 57, 0, 53, 56,
+	55, 0, 42, 44, 47, 43, 45, 0, 0, 46,
+	85, 0, 54, 0, 0, 0, 0, 63, 51, 0,
+	57, 0, 53, 56, 55, 0, 42, 44, 47, 43,
+	45, 0, 0, 46, 58, 0, 54, 0, 0, 0,
+	0, 63, 51, 0, 57, 0, 53, 56, 55, 0,
+	42, 44, 47, 43, 45, 0, 0, 46, 58, 0,
+	54, 0, 0, 0, 89, 0, 51, 0, 57, 0,
+	53, 56, 55, 0, 42, 44, 47, 43, 45, 0,
+	0, 46, 58, 0, 54, 0, 0, 0, 38, 0,
+	51, 0, 57, 0, 53, 56, 55, 0, 42, 44,
+	47, 43, 45, 0, 0, 46, 58, 0, 54, 0,
+	0, 56, 55, 0, 51, 0, 57, 0, 53, 0,
+	56, 55, 42, 44, 47, 43, 45, 56, 55, 46,
+	0, 0, 54, 0, 53, 0, 56, 55, 51, 113,
+	57, 0, 0, 53, 0, 114, 0, 0, 54, 0,
+	53, 0, 219, 0, 74, 0, 57, 54, 0, 53,
+	56, 55, 0, 74, 54, 57, 0, 56, 178, 192,
+	74, 73, 57, 54, 0, 0, 0, 56, 55, 74,
+	0, 57, 0, 53, 56, 55, 0, 0, 0, 0,
+	53, 0, 179, 0, 0, 0, 0, 54, 0, 177,
+	53, 0, 0, 74, 54, 57, 0, 53, 0, 0,
+	74, 0, 57, 0, 54, 0, 0, 0, 0, 58,
+	74, 54, 57, 0, 0, 0, 0, 51, 0, 57,
+	164, 163, 162, 160, 161, 155, 156, 157, 158, 159,
+	163, 162, 160, 161, 155, 156, 157, 158, 159, 162,
+	160, 161, 155, 156, 157, 158, 159, 160, 161, 155,
+	156, 157, 158, 159,
 }
 var yyPact = []int{
 
-	-1000, -1000, 249, -1000, 78, -1000, 81, 80, 73, 71,
-	339, 293, 293, 364, 420, -1000, -1000, 58, 318, 293,
-	293, 293, -1000, 219, 14, 293, 293, 89, 448, 448,
-	-1000, 476, -1000, -1000, 476, -1000, -1000, -1000, 364, -1000,
+	-1000, -1000, 249, -1000, 67, -1000, 71, 69, 66, 63,
+	368, 320, 320, 392, 44, -1000, -1000, 272, 344, 320,
+	320, 320, -1000, 392, -1, 320, 320, 78, 505, 505,
+	-1000, 498, -1000, -1000, 498, -1000, -1000, -1000, 392, -1000,
 	-1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000,
-	10, 190, 9, -1000, -1000, 476, 476, 476, 228, -1000,
-	70, -1000, -1000, 163, -1000, 68, -1000, 67, -1000, 166,
-	-1000, 66, 7, 231, 476, -1000, 272, -1000, 364, -1000,
-	-1000, -1000, -1000, -1000, 3, 228, -1000, -1000, -1000, 364,
-	-1000, 65, -1000, 57, -1000, 56, -1000, 55, -1000, 53,
-	-1000, 43, -1000, 42, 171, 41, 36, 249, 527, -1000,
-	527, -1000, 131, 0, -7, 436, 111, -1000, -1000, -1000,
-	2, 235, 476, 476, -1000, -1000, -1000, -1000, -1000, 469,
-	466, 364, 293, -1000, 166, 137, -1000, -1000, 385, -1000,
-	-1000, -1000, 103, 2, 364, 364, 364, 364, 364, 293,
-	293, 476, 445, 289, -1000, 476, 476, 476, 476, 476,
-	245, 221, 476, 476, 476, -4, -8, -9, -1, 476,
-	-1000, -1000, 208, 112, 231, -1000, -1000, -12, 441, -1000,
-	-1000, -1000, -1000, -13, 85, 79, -1000, 28, 24, -1000,
-	-1000, 23, 179, 22, -1000, 21, 294, 294, -1000, -1000,
-	-1000, 476, 476, 542, 535, 279, -2, 476, -1000, -1000,
-	101, -14, 476, -19, -1000, -1000, -1000, -5, -1000, -22,
-	-1000, 99, 96, 476, 219, 14, -1000, 213, 149, 15,
-	14, 402, 402, 113, -28, 203, -1000, -34, -1000, 126,
-	-1000, -1000, -1000, -1000, -1000, -1000, 148, 211, 179, -1000,
-	195, 183, -1000, 476, -1000, -36, -1000, 146, -1000, 476,
-	476, -39, -1000, -1000, -40, -47, -1000, -1000, -1000,
+	13, 432, 11, -1000, -1000, 498, 498, 498, 191, -1000,
+	62, -1000, -1000, 163, -1000, 59, -1000, 58, -1000, 457,
+	-1000, 57, 9, 243, 498, -1000, 296, -1000, 392, -1000,
+	-1000, -1000, -1000, -1000, 8, 191, -1000, -1000, -1000, 392,
+	-1000, 56, -1000, 54, -1000, 52, -1000, 51, -1000, 49,
+	-1000, 43, -1000, 37, 184, 33, 28, 249, 556, -1000,
+	556, -1000, 151, 2, -8, 236, 105, -1000, -1000, -1000,
+	-3, 276, 498, 498, -1000, -1000, -1000, -1000, -1000, 488,
+	481, 392, 320, -1000, 457, 113, -1000, -1000, 416, -1000,
+	-1000, -1000, 100, -3, 392, 392, 392, 183, 392, 320,
+	320, 498, 448, 123, -1000, 498, 498, 498, 498, 498,
+	278, 254, 498, 498, 498, -2, -9, -12, -4, 498,
+	-1000, -1000, 205, 93, 243, -1000, -1000, -13, 441, -1000,
+	-1000, -1000, -1000, -19, 74, 73, -1000, 23, 22, -1000,
+	-1000, 21, 161, 19, -1000, 18, 225, 225, -1000, -1000,
+	-1000, 498, 498, 580, 573, 565, -5, 498, -1000, -1000,
+	103, -22, 498, -25, -1000, -1000, -1000, -6, -1000, -29,
+	-1000, 92, 89, 498, 183, -1, -1000, 218, 136, 15,
+	-1, 246, 246, 107, -31, 203, -1000, -32, -1000, 111,
+	-1000, -1000, -1000, -1000, -1000, -1000, 129, 215, 161, -1000,
+	199, 195, -1000, 498, -1000, -36, -1000, 116, -1000, 498,
+	498, -39, -1000, -1000, -42, -43, -1000, -1000, -1000,
 }
 var yyPgo = []int{
 
-	0, 0, 28, 363, 2, 196, 8, 3, 20, 9,
-	100, 16, 10, 4, 12, 1, 197, 360, 182, 359,
-	353, 352, 351, 346, 342, 338, 334, 322, 320, 319,
-	317, 314, 313, 5, 301, 300, 296, 294, 253,
+	0, 0, 27, 325, 6, 182, 8, 2, 39, 4,
+	86, 16, 5, 12, 7, 1, 180, 321, 178, 320,
+	319, 317, 314, 313, 303, 302, 301, 300, 299, 298,
+	296, 294, 292, 3, 291, 290, 288, 287, 286,
 }
 var yyR1 = []int{
 
@@ -266,7 +270,7 @@
 	-11, -10, -6, 51, -20, -11, -21, -10, -17, 50,
 	-9, -6, -1, 44, 52, -22, 50, -12, 11, -9,
 	-14, -7, -13, -6, -1, 44, -23, -16, -18, 50,
-	-24, -11, -25, -11, -26, -11, -27, -7, -28, -6,
+	-24, -11, -25, -11, -26, -11, -27, -10, -28, -6,
 	-29, -11, -30, -11, -8, -5, -5, -34, -2, -1,
 	-2, -10, 52, 37, 43, -2, 52, -1, -1, -1,
 	-4, 7, 9, 10, 50, -1, -8, 42, 41, 52,
@@ -275,7 +279,7 @@
 	50, 12, 50, 50, -33, 9, 10, 11, 12, 13,
 	7, 8, 6, 5, 4, 37, 43, 38, 53, 11,
 	53, 53, 37, 52, 8, -1, -1, 41, 10, 41,
-	-10, -11, -9, 34, -10, -10, -10, -10, -10, -11,
+	-10, -11, -9, 34, -10, -10, -10, -7, -10, -11,
 	-11, -1, 51, -1, -6, -1, -2, -2, -2, -2,
 	-2, 7, 8, -2, -2, -2, 53, 11, 53, 53,
 	52, -1, 11, -3, 35, 43, 33, -4, 53, 41,
@@ -1103,7 +1107,7 @@
 		{
 			yyVAL.addr = nullgen
 			yyVAL.addr.Type = obj.TYPE_SCONST
-			yyVAL.addr.U.Sval = yyDollar[2].sval
+			yyVAL.addr.Val = yyDollar[2].sval
 		}
 	case 83:
 		yyDollar = yyS[yypt-2 : yypt+1]
@@ -1111,7 +1115,7 @@
 		{
 			yyVAL.addr = nullgen
 			yyVAL.addr.Type = obj.TYPE_FCONST
-			yyVAL.addr.U.Dval = yyDollar[2].dval
+			yyVAL.addr.Val = yyDollar[2].dval
 		}
 	case 84:
 		yyDollar = yyS[yypt-4 : yypt+1]
@@ -1119,7 +1123,7 @@
 		{
 			yyVAL.addr = nullgen
 			yyVAL.addr.Type = obj.TYPE_FCONST
-			yyVAL.addr.U.Dval = yyDollar[3].dval
+			yyVAL.addr.Val = yyDollar[3].dval
 		}
 	case 85:
 		yyDollar = yyS[yypt-5 : yypt+1]
@@ -1127,7 +1131,7 @@
 		{
 			yyVAL.addr = nullgen
 			yyVAL.addr.Type = obj.TYPE_FCONST
-			yyVAL.addr.U.Dval = -yyDollar[4].dval
+			yyVAL.addr.Val = -yyDollar[4].dval
 		}
 	case 86:
 		yyDollar = yyS[yypt-3 : yypt+1]
@@ -1135,7 +1139,7 @@
 		{
 			yyVAL.addr = nullgen
 			yyVAL.addr.Type = obj.TYPE_FCONST
-			yyVAL.addr.U.Dval = -yyDollar[3].dval
+			yyVAL.addr.Val = -yyDollar[3].dval
 		}
 	case 87:
 		yyDollar = yyS[yypt-1 : yypt+1]
@@ -1144,7 +1148,7 @@
 			yyVAL.addr = nullgen
 			yyVAL.addr.Type = obj.TYPE_TEXTSIZE
 			yyVAL.addr.Offset = yyDollar[1].lval
-			yyVAL.addr.U.Argsize = obj.ArgsSizeUnknown
+			yyVAL.addr.Val = int32(obj.ArgsSizeUnknown)
 		}
 	case 88:
 		yyDollar = yyS[yypt-2 : yypt+1]
@@ -1153,7 +1157,7 @@
 			yyVAL.addr = nullgen
 			yyVAL.addr.Type = obj.TYPE_TEXTSIZE
 			yyVAL.addr.Offset = -yyDollar[2].lval
-			yyVAL.addr.U.Argsize = obj.ArgsSizeUnknown
+			yyVAL.addr.Val = int32(obj.ArgsSizeUnknown)
 		}
 	case 89:
 		yyDollar = yyS[yypt-3 : yypt+1]
@@ -1162,7 +1166,7 @@
 			yyVAL.addr = nullgen
 			yyVAL.addr.Type = obj.TYPE_TEXTSIZE
 			yyVAL.addr.Offset = yyDollar[1].lval
-			yyVAL.addr.U.Argsize = int32(yyDollar[3].lval)
+			yyVAL.addr.Val = int32(yyDollar[3].lval)
 		}
 	case 90:
 		yyDollar = yyS[yypt-4 : yypt+1]
@@ -1171,7 +1175,7 @@
 			yyVAL.addr = nullgen
 			yyVAL.addr.Type = obj.TYPE_TEXTSIZE
 			yyVAL.addr.Offset = -yyDollar[2].lval
-			yyVAL.addr.U.Argsize = int32(yyDollar[4].lval)
+			yyVAL.addr.Val = int32(yyDollar[4].lval)
 		}
 	case 91:
 		yyVAL.addr = yyS[yypt-0].addr
diff --git a/src/cmd/old9a/a.y b/src/cmd/old9a/a.y
index a6785df..bdcd84d 100644
--- a/src/cmd/old9a/a.y
+++ b/src/cmd/old9a/a.y
@@ -846,28 +846,28 @@
 		$$ = nullgen;
 		$$.Type = obj.TYPE_TEXTSIZE;
 		$$.Offset = int64($1)
-		$$.U.Argsize = obj.ArgsSizeUnknown;
+		$$.Val = int32(obj.ArgsSizeUnknown);
 	}
 |	'-' LCONST
 	{
 		$$ = nullgen;
 		$$.Type = obj.TYPE_TEXTSIZE;
 		$$.Offset = -int64($2)
-		$$.U.Argsize = obj.ArgsSizeUnknown;
+		$$.Val = int32(obj.ArgsSizeUnknown);
 	}
 |	LCONST '-' LCONST
 	{
 		$$ = nullgen;
 		$$.Type = obj.TYPE_TEXTSIZE;
 		$$.Offset = int64($1)
-		$$.U.Argsize = int32($3);
+		$$.Val = int32($3);
 	}
 |	'-' LCONST '-' LCONST
 	{
 		$$ = nullgen;
 		$$.Type = obj.TYPE_TEXTSIZE;
 		$$.Offset = -int64($2)
-		$$.U.Argsize = int32($4);
+		$$.Val = int32($4);
 	}
 
 ximm:
@@ -880,7 +880,7 @@
 	{
 		$$ = nullgen;
 		$$.Type = obj.TYPE_SCONST;
-		$$.U.Sval = $2
+		$$.Val = $2
 	}
 
 fimm:
@@ -888,13 +888,13 @@
 	{
 		$$ = nullgen;
 		$$.Type = obj.TYPE_FCONST;
-		$$.U.Dval = $2;
+		$$.Val = $2;
 	}
 |	'$' '-' LFCONST
 	{
 		$$ = nullgen;
 		$$.Type = obj.TYPE_FCONST;
-		$$.U.Dval = -$3;
+		$$.Val = -$3;
 	}
 
 imm:	'$' con
diff --git a/src/cmd/old9a/y.go b/src/cmd/old9a/y.go
index ecc9b9c..65f6126 100644
--- a/src/cmd/old9a/y.go
+++ b/src/cmd/old9a/y.go
@@ -1691,7 +1691,7 @@
 			yyVAL.addr = nullgen
 			yyVAL.addr.Type = obj.TYPE_TEXTSIZE
 			yyVAL.addr.Offset = int64(yyDollar[1].lval)
-			yyVAL.addr.U.Argsize = obj.ArgsSizeUnknown
+			yyVAL.addr.Val = int32(obj.ArgsSizeUnknown)
 		}
 	case 145:
 		yyDollar = yyS[yypt-2 : yypt+1]
@@ -1700,7 +1700,7 @@
 			yyVAL.addr = nullgen
 			yyVAL.addr.Type = obj.TYPE_TEXTSIZE
 			yyVAL.addr.Offset = -int64(yyDollar[2].lval)
-			yyVAL.addr.U.Argsize = obj.ArgsSizeUnknown
+			yyVAL.addr.Val = int32(obj.ArgsSizeUnknown)
 		}
 	case 146:
 		yyDollar = yyS[yypt-3 : yypt+1]
@@ -1709,7 +1709,7 @@
 			yyVAL.addr = nullgen
 			yyVAL.addr.Type = obj.TYPE_TEXTSIZE
 			yyVAL.addr.Offset = int64(yyDollar[1].lval)
-			yyVAL.addr.U.Argsize = int32(yyDollar[3].lval)
+			yyVAL.addr.Val = int32(yyDollar[3].lval)
 		}
 	case 147:
 		yyDollar = yyS[yypt-4 : yypt+1]
@@ -1718,7 +1718,7 @@
 			yyVAL.addr = nullgen
 			yyVAL.addr.Type = obj.TYPE_TEXTSIZE
 			yyVAL.addr.Offset = -int64(yyDollar[2].lval)
-			yyVAL.addr.U.Argsize = int32(yyDollar[4].lval)
+			yyVAL.addr.Val = int32(yyDollar[4].lval)
 		}
 	case 148:
 		yyDollar = yyS[yypt-2 : yypt+1]
@@ -1733,7 +1733,7 @@
 		{
 			yyVAL.addr = nullgen
 			yyVAL.addr.Type = obj.TYPE_SCONST
-			yyVAL.addr.U.Sval = yyDollar[2].sval
+			yyVAL.addr.Val = yyDollar[2].sval
 		}
 	case 150:
 		yyDollar = yyS[yypt-2 : yypt+1]
@@ -1741,7 +1741,7 @@
 		{
 			yyVAL.addr = nullgen
 			yyVAL.addr.Type = obj.TYPE_FCONST
-			yyVAL.addr.U.Dval = yyDollar[2].dval
+			yyVAL.addr.Val = yyDollar[2].dval
 		}
 	case 151:
 		yyDollar = yyS[yypt-3 : yypt+1]
@@ -1749,7 +1749,7 @@
 		{
 			yyVAL.addr = nullgen
 			yyVAL.addr.Type = obj.TYPE_FCONST
-			yyVAL.addr.U.Dval = -yyDollar[3].dval
+			yyVAL.addr.Val = -yyDollar[3].dval
 		}
 	case 152:
 		yyDollar = yyS[yypt-2 : yypt+1]
diff --git a/src/cmd/pprof/internal/profile/filter.go b/src/cmd/pprof/internal/profile/filter.go
index 903616a..1baa096 100644
--- a/src/cmd/pprof/internal/profile/filter.go
+++ b/src/cmd/pprof/internal/profile/filter.go
@@ -3,6 +3,7 @@
 // license that can be found in the LICENSE file.
 
 // Implements methods to filter samples from profiles.
+
 package profile
 
 import "regexp"
diff --git a/src/cmd/trace/goroutines.go b/src/cmd/trace/goroutines.go
index f8d1289..f5a4ddb 100644
--- a/src/cmd/trace/goroutines.go
+++ b/src/cmd/trace/goroutines.go
@@ -13,6 +13,7 @@
 	"net/http"
 	"sort"
 	"strconv"
+	"sync"
 )
 
 func init() {
@@ -42,34 +43,7 @@
 	l[i], l[j] = l[j], l[i]
 }
 
-// gdesc desribes a single goroutine.
-type gdesc struct {
-	ID         uint64
-	Name       string
-	PC         uint64
-	CreateTime int64
-	StartTime  int64
-	EndTime    int64
-	LastStart  int64
-
-	ExecTime      int64
-	SchedWaitTime int64
-	IOTime        int64
-	BlockTime     int64
-	SyscallTime   int64
-	GCTime        int64
-	SweepTime     int64
-	TotalTime     int64
-
-	blockNetTime     int64
-	blockSyncTime    int64
-	blockSyscallTime int64
-	blockSweepTime   int64
-	blockGCTime      int64
-	blockSchedTime   int64
-}
-
-type gdescList []*gdesc
+type gdescList []*trace.GDesc
 
 func (l gdescList) Len() int {
 	return len(l)
@@ -83,126 +57,16 @@
 	l[i], l[j] = l[j], l[i]
 }
 
-var gs = make(map[uint64]*gdesc)
+var (
+	gsInit sync.Once
+	gs     map[uint64]*trace.GDesc
+)
 
-// analyzeGoroutines generates list gdesc's from the trace and stores it in gs.
+// analyzeGoroutines generates statistics about execution of all goroutines and stores them in gs.
 func analyzeGoroutines(events []*trace.Event) {
-	if len(gs) > 0 { //!!! racy
-		return
-	}
-	var lastTs int64
-	var gcStartTime int64
-	for _, ev := range events {
-		lastTs = ev.Ts
-		switch ev.Type {
-		case trace.EvGoCreate:
-			g := &gdesc{CreateTime: ev.Ts}
-			g.blockSchedTime = ev.Ts
-			gs[ev.Args[0]] = g
-		case trace.EvGoStart:
-			g := gs[ev.G]
-			if g.PC == 0 {
-				g.PC = ev.Stk[0].PC
-				g.Name = ev.Stk[0].Fn
-			}
-			g.LastStart = ev.Ts
-			if g.StartTime == 0 {
-				g.StartTime = ev.Ts
-			}
-			if g.blockSchedTime != 0 {
-				g.SchedWaitTime += ev.Ts - g.blockSchedTime
-				g.blockSchedTime = 0
-			}
-		case trace.EvGoEnd, trace.EvGoStop:
-			g := gs[ev.G]
-			g.ExecTime += ev.Ts - g.LastStart
-			g.TotalTime = ev.Ts - g.CreateTime
-			g.EndTime = ev.Ts
-		case trace.EvGoBlockSend, trace.EvGoBlockRecv, trace.EvGoBlockSelect,
-			trace.EvGoBlockSync, trace.EvGoBlockCond:
-			g := gs[ev.G]
-			g.ExecTime += ev.Ts - g.LastStart
-			g.blockSyncTime = ev.Ts
-		case trace.EvGoSched, trace.EvGoPreempt:
-			g := gs[ev.G]
-			g.ExecTime += ev.Ts - g.LastStart
-			g.blockSchedTime = ev.Ts
-		case trace.EvGoSleep, trace.EvGoBlock:
-			g := gs[ev.G]
-			g.ExecTime += ev.Ts - g.LastStart
-		case trace.EvGoBlockNet:
-			g := gs[ev.G]
-			g.ExecTime += ev.Ts - g.LastStart
-			g.blockNetTime = ev.Ts
-		case trace.EvGoUnblock:
-			g := gs[ev.Args[0]]
-			if g.blockNetTime != 0 {
-				g.IOTime += ev.Ts - g.blockNetTime
-				g.blockNetTime = 0
-			}
-			if g.blockSyncTime != 0 {
-				g.BlockTime += ev.Ts - g.blockSyncTime
-				g.blockSyncTime = 0
-			}
-			g.blockSchedTime = ev.Ts
-		case trace.EvGoSysBlock:
-			g := gs[ev.G]
-			g.ExecTime += ev.Ts - g.LastStart
-			g.blockSyscallTime = ev.Ts
-		case trace.EvGoSysExit:
-			g := gs[ev.G]
-			if g.blockSyscallTime != 0 {
-				g.SyscallTime += ev.Ts - g.blockSyscallTime
-				g.blockSyscallTime = 0
-			}
-			g.blockSchedTime = ev.Ts
-		case trace.EvGCSweepStart:
-			g := gs[ev.G]
-			if g != nil {
-				// Sweep can happen during GC on system goroutine.
-				g.blockSweepTime = ev.Ts
-			}
-		case trace.EvGCSweepDone:
-			g := gs[ev.G]
-			if g != nil && g.blockSweepTime != 0 {
-				g.SweepTime += ev.Ts - g.blockSweepTime
-				g.blockSweepTime = 0
-			}
-		case trace.EvGCStart:
-			gcStartTime = ev.Ts
-		case trace.EvGCDone:
-			for _, g := range gs {
-				if g.EndTime == 0 {
-					g.GCTime += ev.Ts - gcStartTime
-				}
-			}
-		}
-	}
-
-	for _, g := range gs {
-		if g.TotalTime == 0 {
-			g.TotalTime = lastTs - g.CreateTime
-		}
-		if g.EndTime == 0 {
-			g.EndTime = lastTs
-		}
-		if g.blockNetTime != 0 {
-			g.IOTime += lastTs - g.blockNetTime
-			g.blockNetTime = 0
-		}
-		if g.blockSyncTime != 0 {
-			g.BlockTime += lastTs - g.blockSyncTime
-			g.blockSyncTime = 0
-		}
-		if g.blockSyscallTime != 0 {
-			g.SyscallTime += lastTs - g.blockSyscallTime
-			g.blockSyscallTime = 0
-		}
-		if g.blockSchedTime != 0 {
-			g.SchedWaitTime += lastTs - g.blockSchedTime
-			g.blockSchedTime = 0
-		}
-	}
+	gsInit.Do(func() {
+		gs = trace.GoroutineStats(events)
+	})
 }
 
 // httpGoroutines serves list of goroutine groups.
@@ -256,11 +120,10 @@
 	}
 	analyzeGoroutines(events)
 	var glist gdescList
-	for gid, g := range gs {
+	for _, g := range gs {
 		if g.PC != pc || g.ExecTime == 0 {
 			continue
 		}
-		g.ID = gid
 		glist = append(glist, g)
 	}
 	sort.Sort(glist)
@@ -303,26 +166,3 @@
 </body>
 </html>
 `))
-
-// relatedGoroutines finds set of related goroutines that we need to include
-// into trace for goroutine goid.
-func relatedGoroutines(events []*trace.Event, goid uint64) map[uint64]bool {
-	// BFS of depth 2 over "unblock" edges
-	// (what goroutines unblock goroutine goid?).
-	gmap := make(map[uint64]bool)
-	gmap[goid] = true
-	for i := 0; i < 2; i++ {
-		gmap1 := make(map[uint64]bool)
-		for g := range gmap {
-			gmap1[g] = true
-		}
-		for _, ev := range events {
-			if ev.Type == trace.EvGoUnblock && gmap[ev.Args[0]] {
-				gmap1[ev.G] = true
-			}
-		}
-		gmap = gmap1
-	}
-	gmap[0] = true // for GC events
-	return gmap
-}
diff --git a/src/cmd/trace/trace.go b/src/cmd/trace/trace.go
index 8f8ef14..16a20ae 100644
--- a/src/cmd/trace/trace.go
+++ b/src/cmd/trace/trace.go
@@ -90,7 +90,7 @@
 		params.startTime = g.StartTime
 		params.endTime = g.EndTime
 		params.maing = goid
-		params.gs = relatedGoroutines(events, goid)
+		params.gs = trace.RelatedGoroutines(events, goid)
 	}
 
 	err = json.NewEncoder(w).Encode(generateTrace(params))
@@ -343,12 +343,12 @@
 
 func (ctx *traceContext) emitSlice(ev *trace.Event, name string) {
 	ctx.emit(&ViewerEvent{
-		Name:  name,
-		Phase: "X",
-		Time:  ctx.time(ev),
-		Dur:   ctx.time(ev.Link) - ctx.time(ev),
-		Tid:   ctx.proc(ev),
-		//Stack: ctx.stack(ev.Stk),
+		Name:     name,
+		Phase:    "X",
+		Time:     ctx.time(ev),
+		Dur:      ctx.time(ev.Link) - ctx.time(ev),
+		Tid:      ctx.proc(ev),
+		Stack:    ctx.stack(ev.Stk),
 		EndStack: ctx.stack(ev.Link.Stk),
 	})
 }
@@ -391,7 +391,14 @@
 }
 
 func (ctx *traceContext) emitInstant(ev *trace.Event, name string) {
-	ctx.emit(&ViewerEvent{Name: name, Phase: "I", Scope: "t", Time: ctx.time(ev), Tid: ctx.proc(ev), Stack: ctx.stack(ev.Stk)})
+	var arg interface{}
+	if ev.Type == trace.EvProcStart {
+		type Arg struct {
+			ThreadID uint64
+		}
+		arg = &Arg{ev.Args[0]}
+	}
+	ctx.emit(&ViewerEvent{Name: name, Phase: "I", Scope: "t", Time: ctx.time(ev), Tid: ctx.proc(ev), Stack: ctx.stack(ev.Stk), Arg: arg})
 }
 
 func (ctx *traceContext) emitArrow(ev *trace.Event, name string) {
diff --git a/src/cmd/yacc/doc.go b/src/cmd/yacc/doc.go
index 7839dcf..328d87b 100644
--- a/src/cmd/yacc/doc.go
+++ b/src/cmd/yacc/doc.go
@@ -20,7 +20,7 @@
 Adepts of the original yacc will have no trouble adapting to this
 form of the tool.
 
-The directory $GOROOT/cmd/yacc/testdata/expr is a yacc program
+The directory $GOROOT/src/cmd/yacc/testdata/expr is a yacc program
 for a very simple expression parser. See expr.y and main.go in that
 directory for examples of how to write and build yacc programs.
 
diff --git a/src/cmd/yacc/testdata/expr/expr.y b/src/cmd/yacc/testdata/expr/expr.y
index 721b1c9..bb8e9bf 100644
--- a/src/cmd/yacc/testdata/expr/expr.y
+++ b/src/cmd/yacc/testdata/expr/expr.y
@@ -56,29 +56,29 @@
 	}
 |	'-' expr
 	{
-		$$.Neg($2)
+		$$ = $2.Neg($2)
 	}
 
 expr1:
 	expr2
 |	expr1 '+' expr2
 	{
-		$$.Add($1, $3)
+		$$ = $1.Add($1, $3)
 	}
 |	expr1 '-' expr2
 	{
-		$$.Sub($1, $3)
+		$$ = $1.Sub($1, $3)
 	}
 
 expr2:
 	expr3
 |	expr2 '*' expr3
 	{
-		$$.Mul($1, $3)
+		$$ = $1.Mul($1, $3)
 	}
 |	expr2 '/' expr3
 	{
-		$$.Quo($1, $3)
+		$$ = $1.Quo($1, $3)
 	}
 
 expr3:
diff --git a/src/compress/flate/deflate.go b/src/compress/flate/deflate.go
index 8c79df0..169a0c7 100644
--- a/src/compress/flate/deflate.go
+++ b/src/compress/flate/deflate.go
@@ -24,7 +24,7 @@
 	maxMatchLength     = 258 // The longest match for the compressor
 	minOffsetSize      = 1   // The shortest offset that makes any sense
 
-	// The maximum number of tokens we put into a single flat block, just too
+	// The maximum number of tokens we put into a single flat block, just to
 	// stop things from getting too large.
 	maxFlateBlockTokens = 1 << 14
 	maxStoreBlockSize   = 65535
diff --git a/src/crypto/crypto.go b/src/crypto/crypto.go
index 59b23e9..183a4bd 100644
--- a/src/crypto/crypto.go
+++ b/src/crypto/crypto.go
@@ -124,3 +124,19 @@
 	// hashing was done.
 	HashFunc() Hash
 }
+
+// Decrypter is an interface for an opaque private key that can be used for
+// asymmetric decryption operations. For example, an RSA key kept in a hardware
+// module.
+type Decrypter interface {
+	// Public returns the public key corresponding to the opaque,
+	// private key.
+	Public() PublicKey
+
+	// Decrypt decrypts msg. The opts argument should be appropriate for
+	// the primitive used. See the documentation in each implementation for
+	// details.
+	Decrypt(rand io.Reader, msg []byte, opts DecrypterOpts) (plaintext []byte, err error)
+}
+
+type DecrypterOpts interface{}
diff --git a/src/crypto/ecdsa/ecdsa.go b/src/crypto/ecdsa/ecdsa.go
index 5990201..d003f9d 100644
--- a/src/crypto/ecdsa/ecdsa.go
+++ b/src/crypto/ecdsa/ecdsa.go
@@ -140,7 +140,7 @@
 		entropylen = 32
 	}
 	entropy := make([]byte, entropylen)
-	_, err = rand.Read(entropy)
+	_, err = io.ReadFull(rand, entropy)
 	if err != nil {
 		return
 	}
diff --git a/src/crypto/elliptic/elliptic.go b/src/crypto/elliptic/elliptic.go
index fa987ac..396bb5c 100644
--- a/src/crypto/elliptic/elliptic.go
+++ b/src/crypto/elliptic/elliptic.go
@@ -24,7 +24,7 @@
 type Curve interface {
 	// Params returns the parameters for the curve.
 	Params() *CurveParams
-	// IsOnCurve returns true if the given (x,y) lies on the curve.
+	// IsOnCurve reports whether the given (x,y) lies on the curve.
 	IsOnCurve(x, y *big.Int) bool
 	// Add returns the sum of (x1,y1) and (x2,y2)
 	Add(x1, y1, x2, y2 *big.Int) (x, y *big.Int)
diff --git a/src/crypto/hmac/hmac.go b/src/crypto/hmac/hmac.go
index b6f4919..e0cc1d6 100644
--- a/src/crypto/hmac/hmac.go
+++ b/src/crypto/hmac/hmac.go
@@ -11,7 +11,7 @@
 Receivers should be careful to use Equal to compare MACs in order to avoid
 timing side-channels:
 
-	// CheckMAC returns true if messageMAC is a valid HMAC tag for message.
+	// CheckMAC reports whether messageMAC is a valid HMAC tag for message.
 	func CheckMAC(message, messageMAC, key []byte) bool {
 		mac := hmac.New(sha256.New, key)
 		mac.Write(message)
diff --git a/src/crypto/rsa/pkcs1v15.go b/src/crypto/rsa/pkcs1v15.go
index 59e8bb5..34037b0 100644
--- a/src/crypto/rsa/pkcs1v15.go
+++ b/src/crypto/rsa/pkcs1v15.go
@@ -14,6 +14,16 @@
 
 // This file implements encryption and decryption using PKCS#1 v1.5 padding.
 
+// PKCS1v15DecrypterOpts is for passing options to PKCS#1 v1.5 decryption using
+// the crypto.Decrypter interface.
+type PKCS1v15DecryptOptions struct {
+	// SessionKeyLen is the length of the session key that is being
+	// decrypted. If not zero, then a padding error during decryption will
+	// cause a random plaintext of this length to be returned rather than
+	// an error. These alternatives happen in constant time.
+	SessionKeyLen int
+}
+
 // EncryptPKCS1v15 encrypts the given message with RSA and the padding scheme from PKCS#1 v1.5.
 // The message must be no longer than the length of the public modulus minus 11 bytes.
 // WARNING: use of this function to encrypt plaintexts other than session keys
diff --git a/src/crypto/rsa/pkcs1v15_test.go b/src/crypto/rsa/pkcs1v15_test.go
index 2dc5dbc..8925375 100644
--- a/src/crypto/rsa/pkcs1v15_test.go
+++ b/src/crypto/rsa/pkcs1v15_test.go
@@ -51,14 +51,25 @@
 }
 
 func TestDecryptPKCS1v15(t *testing.T) {
-	for i, test := range decryptPKCS1v15Tests {
-		out, err := DecryptPKCS1v15(nil, rsaPrivateKey, decodeBase64(test.in))
-		if err != nil {
-			t.Errorf("#%d error decrypting", i)
-		}
-		want := []byte(test.out)
-		if !bytes.Equal(out, want) {
-			t.Errorf("#%d got:%#v want:%#v", i, out, want)
+	decryptionFuncs := []func([]byte) ([]byte, error){
+		func(ciphertext []byte) (plaintext []byte, err error) {
+			return DecryptPKCS1v15(nil, rsaPrivateKey, ciphertext)
+		},
+		func(ciphertext []byte) (plaintext []byte, err error) {
+			return rsaPrivateKey.Decrypt(nil, ciphertext, nil)
+		},
+	}
+
+	for _, decryptFunc := range decryptionFuncs {
+		for i, test := range decryptPKCS1v15Tests {
+			out, err := decryptFunc(decodeBase64(test.in))
+			if err != nil {
+				t.Errorf("#%d error decrypting", i)
+			}
+			want := []byte(test.out)
+			if !bytes.Equal(out, want) {
+				t.Errorf("#%d got:%#v want:%#v", i, out, want)
+			}
 		}
 	}
 }
@@ -138,6 +149,22 @@
 	}
 }
 
+func TestEncryptPKCS1v15DecrypterSessionKey(t *testing.T) {
+	for i, test := range decryptPKCS1v15SessionKeyTests {
+		plaintext, err := rsaPrivateKey.Decrypt(rand.Reader, decodeBase64(test.in), &PKCS1v15DecryptOptions{SessionKeyLen: 4})
+		if err != nil {
+			t.Fatalf("#%d: error decrypting: %s", i, err)
+		}
+		if len(plaintext) != 4 {
+			t.Fatalf("#%d: incorrect length plaintext: got %d, want 4", i, len(plaintext))
+		}
+
+		if test.out != "FAIL" && !bytes.Equal(plaintext, []byte(test.out)) {
+			t.Errorf("#%d: incorrect plaintext: got %x, want %x", plaintext, test.out)
+		}
+	}
+}
+
 func TestNonZeroRandomBytes(t *testing.T) {
 	random := rand.Reader
 
diff --git a/src/crypto/rsa/rsa.go b/src/crypto/rsa/rsa.go
index 2170446..99fa94e 100644
--- a/src/crypto/rsa/rsa.go
+++ b/src/crypto/rsa/rsa.go
@@ -24,6 +24,16 @@
 	E int      // public exponent
 }
 
+// OAEPOptions is an interface for passing options to OAEP decryption using the
+// crypto.Decrypter interface.
+type OAEPOptions struct {
+	// Hash is the hash function that will be used when generating the mask.
+	Hash crypto.Hash
+	// Label is an arbitrary byte string that must be equal to the value
+	// used when encrypting.
+	Label []byte
+}
+
 var (
 	errPublicModulus       = errors.New("crypto/rsa: missing public modulus")
 	errPublicExponentSmall = errors.New("crypto/rsa: public exponent too small")
@@ -77,6 +87,37 @@
 	return SignPKCS1v15(rand, priv, opts.HashFunc(), msg)
 }
 
+// Decrypt decrypts ciphertext with priv. If opts is nil or of type
+// *PKCS1v15DecryptOptions then PKCS#1 v1.5 decryption is performed. Otherwise
+// opts must have type *OAEPOptions and OAEP decryption is done.
+func (priv *PrivateKey) Decrypt(rand io.Reader, ciphertext []byte, opts crypto.DecrypterOpts) (plaintext []byte, err error) {
+	if opts == nil {
+		return DecryptPKCS1v15(rand, priv, ciphertext)
+	}
+
+	switch opts := opts.(type) {
+	case *OAEPOptions:
+		return DecryptOAEP(opts.Hash.New(), rand, priv, ciphertext, opts.Label)
+
+	case *PKCS1v15DecryptOptions:
+		if l := opts.SessionKeyLen; l > 0 {
+			plaintext = make([]byte, l)
+			if _, err := io.ReadFull(rand, plaintext); err != nil {
+				return nil, err
+			}
+			if err := DecryptPKCS1v15SessionKey(rand, priv, ciphertext, plaintext); err != nil {
+				return nil, err
+			}
+			return plaintext, nil
+		} else {
+			return DecryptPKCS1v15(rand, priv, ciphertext)
+		}
+
+	default:
+		return nil, errors.New("crypto/rsa: invalid options for Decrypt")
+	}
+}
+
 type PrecomputedValues struct {
 	Dp, Dq *big.Int // D mod (P-1) (or mod Q-1)
 	Qinv   *big.Int // Q^-1 mod P
diff --git a/src/crypto/tls/cipher_suites.go b/src/crypto/tls/cipher_suites.go
index 4b4695a..b315436 100644
--- a/src/crypto/tls/cipher_suites.go
+++ b/src/crypto/tls/cipher_suites.go
@@ -49,6 +49,9 @@
 	// suiteTLS12 indicates that the cipher suite should only be advertised
 	// and accepted when using TLS 1.2.
 	suiteTLS12
+	// suiteDefaultOff indicates that this cipher suite is not included by
+	// default.
+	suiteDefaultOff
 )
 
 // A cipherSuite is a specific combination of key agreement, cipher and MAC
@@ -75,13 +78,13 @@
 	{TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, 16, 0, 4, ecdheECDSAKA, suiteECDHE | suiteECDSA | suiteTLS12, nil, nil, aeadAESGCM, crypto.SHA256},
 	{TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, 32, 0, 4, ecdheRSAKA, suiteECDHE | suiteTLS12, nil, nil, aeadAESGCM, crypto.SHA384},
 	{TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, 32, 0, 4, ecdheECDSAKA, suiteECDHE | suiteECDSA | suiteTLS12, nil, nil, aeadAESGCM, crypto.SHA384},
-	{TLS_ECDHE_RSA_WITH_RC4_128_SHA, 16, 20, 0, ecdheRSAKA, suiteECDHE, cipherRC4, macSHA1, nil, crypto.SHA256},
-	{TLS_ECDHE_ECDSA_WITH_RC4_128_SHA, 16, 20, 0, ecdheECDSAKA, suiteECDHE | suiteECDSA, cipherRC4, macSHA1, nil, crypto.SHA256},
+	{TLS_ECDHE_RSA_WITH_RC4_128_SHA, 16, 20, 0, ecdheRSAKA, suiteECDHE | suiteDefaultOff, cipherRC4, macSHA1, nil, crypto.SHA256},
+	{TLS_ECDHE_ECDSA_WITH_RC4_128_SHA, 16, 20, 0, ecdheECDSAKA, suiteECDHE | suiteECDSA | suiteDefaultOff, cipherRC4, macSHA1, nil, crypto.SHA256},
 	{TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, 16, 20, 16, ecdheRSAKA, suiteECDHE, cipherAES, macSHA1, nil, crypto.SHA256},
 	{TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, 16, 20, 16, ecdheECDSAKA, suiteECDHE | suiteECDSA, cipherAES, macSHA1, nil, crypto.SHA256},
 	{TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA, 32, 20, 16, ecdheRSAKA, suiteECDHE, cipherAES, macSHA1, nil, crypto.SHA256},
 	{TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA, 32, 20, 16, ecdheECDSAKA, suiteECDHE | suiteECDSA, cipherAES, macSHA1, nil, crypto.SHA256},
-	{TLS_RSA_WITH_RC4_128_SHA, 16, 20, 0, rsaKA, 0, cipherRC4, macSHA1, nil, crypto.SHA256},
+	{TLS_RSA_WITH_RC4_128_SHA, 16, 20, 0, rsaKA, suiteDefaultOff, cipherRC4, macSHA1, nil, crypto.SHA256},
 	{TLS_RSA_WITH_AES_128_CBC_SHA, 16, 20, 16, rsaKA, 0, cipherAES, macSHA1, nil, crypto.SHA256},
 	{TLS_RSA_WITH_AES_256_CBC_SHA, 32, 20, 16, rsaKA, 0, cipherAES, macSHA1, nil, crypto.SHA256},
 	{TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA, 24, 20, 8, ecdheRSAKA, suiteECDHE, cipher3DES, macSHA1, nil, crypto.SHA256},
diff --git a/src/crypto/tls/common.go b/src/crypto/tls/common.go
index e3c6004..584a361 100644
--- a/src/crypto/tls/common.go
+++ b/src/crypto/tls/common.go
@@ -123,6 +123,7 @@
 const (
 	hashSHA1   uint8 = 2
 	hashSHA256 uint8 = 4
+	hashSHA384 uint8 = 5
 )
 
 // Signature algorithms for TLS 1.2 (See RFC 5246, section A.4.1)
@@ -330,7 +331,7 @@
 	ClientSessionCache ClientSessionCache
 
 	// MinVersion contains the minimum SSL/TLS version that is acceptable.
-	// If zero, then SSLv3 is taken as the minimum.
+	// If zero, then TLS 1.0 is taken as the minimum.
 	MinVersion uint16
 
 	// MaxVersion contains the maximum SSL/TLS version that is acceptable.
@@ -610,9 +611,12 @@
 }
 
 func initDefaultCipherSuites() {
-	varDefaultCipherSuites = make([]uint16, len(cipherSuites))
-	for i, suite := range cipherSuites {
-		varDefaultCipherSuites[i] = suite.id
+	varDefaultCipherSuites = make([]uint16, 0, len(cipherSuites))
+	for _, suite := range cipherSuites {
+		if suite.flags&suiteDefaultOff != 0 {
+			continue
+		}
+		varDefaultCipherSuites = append(varDefaultCipherSuites, suite.id)
 	}
 }
 
diff --git a/src/crypto/tls/handshake_client_test.go b/src/crypto/tls/handshake_client_test.go
index 96b63cd..7388d29 100644
--- a/src/crypto/tls/handshake_client_test.go
+++ b/src/crypto/tls/handshake_client_test.go
@@ -344,6 +344,16 @@
 
 	runClientTestTLS10(t, test)
 	runClientTestTLS12(t, test)
+
+	test = &clientTest{
+		name:    "ClientCert-RSA-AES256-GCM-SHA384",
+		command: []string{"openssl", "s_server", "-cipher", "ECDHE-RSA-AES256-GCM-SHA384", "-verify", "1"},
+		config:  &config,
+		cert:    testRSACertificate,
+		key:     testRSAPrivateKey,
+	}
+
+	runClientTestTLS12(t, test)
 }
 
 func TestHandshakeClientCertECDSA(t *testing.T) {
diff --git a/src/crypto/tls/handshake_server.go b/src/crypto/tls/handshake_server.go
index c87da50..c7c1f1e 100644
--- a/src/crypto/tls/handshake_server.go
+++ b/src/crypto/tls/handshake_server.go
@@ -229,7 +229,7 @@
 			// The client is doing a fallback connection.
 			if hs.clientHello.vers < c.config.maxVersion() {
 				c.sendAlert(alertInappropriateFallback)
-				return false, errors.New("tls: client using inppropriate protocol fallback")
+				return false, errors.New("tls: client using inappropriate protocol fallback")
 			}
 			break
 		}
@@ -238,7 +238,7 @@
 	return false, nil
 }
 
-// checkForResumption returns true if we should perform resumption on this connection.
+// checkForResumption reports whether we should perform resumption on this connection.
 func (hs *serverHandshakeState) checkForResumption() bool {
 	c := hs.c
 
diff --git a/src/crypto/tls/handshake_server_test.go b/src/crypto/tls/handshake_server_test.go
index 46a90d3..af5cadb 100644
--- a/src/crypto/tls/handshake_server_test.go
+++ b/src/crypto/tls/handshake_server_test.go
@@ -37,6 +37,15 @@
 
 var testConfig *Config
 
+func allCipherSuites() []uint16 {
+	ids := make([]uint16, len(cipherSuites))
+	for i, suite := range cipherSuites {
+		ids[i] = suite.id
+	}
+
+	return ids
+}
+
 func init() {
 	testConfig = &Config{
 		Time:               func() time.Time { return time.Unix(0, 0) },
@@ -45,6 +54,7 @@
 		InsecureSkipVerify: true,
 		MinVersion:         VersionSSL30,
 		MaxVersion:         VersionTLS12,
+		CipherSuites:       allCipherSuites(),
 	}
 	testConfig.Certificates[0].Certificate = [][]byte{testRSACertificate}
 	testConfig.Certificates[0].PrivateKey = testRSAPrivateKey
@@ -53,7 +63,7 @@
 	testConfig.BuildNameToCertificate()
 }
 
-func testClientHelloFailure(t *testing.T, m handshakeMessage, expectedSubStr string) {
+func testClientHelloFailure(t *testing.T, serverConfig *Config, m handshakeMessage, expectedSubStr string) {
 	// Create in-memory network connection,
 	// send message to server.  Should return
 	// expected error.
@@ -66,7 +76,7 @@
 		cli.writeRecord(recordTypeHandshake, m.marshal())
 		c.Close()
 	}()
-	err := Server(s, testConfig).Handshake()
+	err := Server(s, serverConfig).Handshake()
 	s.Close()
 	if err == nil || !strings.Contains(err.Error(), expectedSubStr) {
 		t.Errorf("Got error: %s; expected to match substring '%s'", err, expectedSubStr)
@@ -74,14 +84,14 @@
 }
 
 func TestSimpleError(t *testing.T) {
-	testClientHelloFailure(t, &serverHelloDoneMsg{}, "unexpected handshake message")
+	testClientHelloFailure(t, testConfig, &serverHelloDoneMsg{}, "unexpected handshake message")
 }
 
 var badProtocolVersions = []uint16{0x0000, 0x0005, 0x0100, 0x0105, 0x0200, 0x0205}
 
 func TestRejectBadProtocolVersion(t *testing.T) {
 	for _, v := range badProtocolVersions {
-		testClientHelloFailure(t, &clientHelloMsg{vers: v}, "unsupported, maximum protocol version")
+		testClientHelloFailure(t, testConfig, &clientHelloMsg{vers: v}, "unsupported, maximum protocol version")
 	}
 }
 
@@ -91,7 +101,7 @@
 		cipherSuites:       []uint16{0xff00},
 		compressionMethods: []uint8{0},
 	}
-	testClientHelloFailure(t, clientHello, "no cipher suite supported by both client and server")
+	testClientHelloFailure(t, testConfig, clientHello, "no cipher suite supported by both client and server")
 }
 
 func TestNoCompressionOverlap(t *testing.T) {
@@ -100,7 +110,20 @@
 		cipherSuites:       []uint16{TLS_RSA_WITH_RC4_128_SHA},
 		compressionMethods: []uint8{0xff},
 	}
-	testClientHelloFailure(t, clientHello, "client does not support uncompressed connections")
+	testClientHelloFailure(t, testConfig, clientHello, "client does not support uncompressed connections")
+}
+
+func TestNoRC4ByDefault(t *testing.T) {
+	clientHello := &clientHelloMsg{
+		vers:               0x0301,
+		cipherSuites:       []uint16{TLS_RSA_WITH_RC4_128_SHA},
+		compressionMethods: []uint8{0},
+	}
+	serverConfig := *testConfig
+	// Reset the enabled cipher suites to nil in order to test the
+	// defaults.
+	serverConfig.CipherSuites = nil
+	testClientHelloFailure(t, &serverConfig, clientHello, "no cipher suite supported by both client and server")
 }
 
 func TestRenegotiationExtension(t *testing.T) {
@@ -780,7 +803,7 @@
 		config: serverConfig,
 		// OpenSSL 1.0.1j is needed for the -fallback_scsv option.
 		command: []string{"openssl", "s_client", "-fallback_scsv"},
-		expectHandshakeErrorIncluding: "inppropriate protocol fallback",
+		expectHandshakeErrorIncluding: "inappropriate protocol fallback",
 	}
 	runServerTestTLS11(t, test)
 }
diff --git a/src/crypto/tls/prf.go b/src/crypto/tls/prf.go
index 58eb97f..d2f9e28 100644
--- a/src/crypto/tls/prf.go
+++ b/src/crypto/tls/prf.go
@@ -10,6 +10,7 @@
 	"crypto/md5"
 	"crypto/sha1"
 	"hash"
+	"strconv"
 )
 
 // Split a premaster secret in two as specified in RFC 4346, section 5.
@@ -169,16 +170,18 @@
 
 func newFinishedHash(version uint16, tls12Hash crypto.Hash) finishedHash {
 	if version >= VersionTLS12 {
-		return finishedHash{tls12Hash.New(), tls12Hash.New(), nil, nil, version, prfForVersion(version, tls12Hash)}
+		return finishedHash{tls12Hash.New(), tls12Hash.New(), tls12Hash, nil, nil, version, prfForVersion(version, tls12Hash)}
 	}
-	return finishedHash{sha1.New(), sha1.New(), md5.New(), md5.New(), version, prfForVersion(version, tls12Hash)}
+	return finishedHash{sha1.New(), sha1.New(), crypto.MD5SHA1, md5.New(), md5.New(), version, prfForVersion(version, tls12Hash)}
 }
 
 // A finishedHash calculates the hash of a set of handshake messages suitable
 // for including in a Finished message.
 type finishedHash struct {
 	client hash.Hash
-	server hash.Hash
+
+	server     hash.Hash
+	serverHash crypto.Hash
 
 	// Prior to TLS 1.2, an additional MD5 hash is required.
 	clientMD5 hash.Hash
@@ -279,7 +282,7 @@
 func (h finishedHash) hashForClientCertificate(sigType uint8) ([]byte, crypto.Hash, uint8) {
 	if h.version >= VersionTLS12 {
 		digest := h.server.Sum(nil)
-		return digest, crypto.SHA256, hashSHA256
+		return digest, h.serverHash, tls12HashID(h.serverHash)
 	}
 	if sigType == signatureECDSA {
 		digest := h.server.Sum(nil)
@@ -291,3 +294,15 @@
 	digest = h.server.Sum(digest)
 	return digest, crypto.MD5SHA1, 0 /* not specified in TLS 1.2. */
 }
+
+// tls12HashID returns the HashAlgorithm id corresponding to the hash h, as
+// specified in RFC 5246, section A.4.1.
+func tls12HashID(h crypto.Hash) uint8 {
+	switch h {
+	case crypto.SHA256:
+		return hashSHA256
+	case crypto.SHA384:
+		return hashSHA384
+	}
+	panic("tls12HashID called with unknown hash " + strconv.Itoa(int(h)))
+}
diff --git a/src/crypto/tls/testdata/Client-TLSv12-ClientCert-RSA-AES256-GCM-SHA384 b/src/crypto/tls/testdata/Client-TLSv12-ClientCert-RSA-AES256-GCM-SHA384
new file mode 100644
index 0000000..e7ca34c
--- /dev/null
+++ b/src/crypto/tls/testdata/Client-TLSv12-ClientCert-RSA-AES256-GCM-SHA384
@@ -0,0 +1,138 @@
+>>> Flow 1 (client to server)
+00000000  16 03 01 00 79 01 00 00  75 03 03 00 00 00 00 00  |....y...u.......|
+00000010  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
+00000020  00 00 00 00 00 00 00 00  00 00 00 00 00 1e c0 2f  |.............../|
+00000030  c0 2b c0 30 c0 2c c0 11  c0 07 c0 13 c0 09 c0 14  |.+.0.,..........|
+00000040  c0 0a 00 05 00 2f 00 35  c0 12 00 0a 01 00 00 2e  |...../.5........|
+00000050  00 05 00 05 01 00 00 00  00 00 0a 00 08 00 06 00  |................|
+00000060  17 00 18 00 19 00 0b 00  02 01 00 00 0d 00 0a 00  |................|
+00000070  08 04 01 04 03 02 01 02  03 ff 01 00 01 00        |..............|
+>>> Flow 2 (server to client)
+00000000  16 03 03 00 59 02 00 00  55 03 03 2d 12 aa 2a 67  |....Y...U..-..*g|
+00000010  e1 6c 55 dc 1c 0b 3f 94  39 7a 2f e3 4e d4 85 cb  |.lU...?.9z/.N...|
+00000020  31 ff da 09 dd e0 92 75  6c e8 0b 20 e1 e7 fc 09  |1......ul.. ....|
+00000030  bd 12 b8 5c b2 54 75 01  7a f5 65 95 d7 87 66 77  |...\.Tu.z.e...fw|
+00000040  03 1f 25 23 cb 39 9f 47  2b 5c fd bd c0 30 00 00  |..%#.9.G+\...0..|
+00000050  0d ff 01 00 01 00 00 0b  00 04 03 00 01 02 16 03  |................|
+00000060  03 02 be 0b 00 02 ba 00  02 b7 00 02 b4 30 82 02  |.............0..|
+00000070  b0 30 82 02 19 a0 03 02  01 02 02 09 00 85 b0 bb  |.0..............|
+00000080  a4 8a 7f b8 ca 30 0d 06  09 2a 86 48 86 f7 0d 01  |.....0...*.H....|
+00000090  01 05 05 00 30 45 31 0b  30 09 06 03 55 04 06 13  |....0E1.0...U...|
+000000a0  02 41 55 31 13 30 11 06  03 55 04 08 13 0a 53 6f  |.AU1.0...U....So|
+000000b0  6d 65 2d 53 74 61 74 65  31 21 30 1f 06 03 55 04  |me-State1!0...U.|
+000000c0  0a 13 18 49 6e 74 65 72  6e 65 74 20 57 69 64 67  |...Internet Widg|
+000000d0  69 74 73 20 50 74 79 20  4c 74 64 30 1e 17 0d 31  |its Pty Ltd0...1|
+000000e0  30 30 34 32 34 30 39 30  39 33 38 5a 17 0d 31 31  |00424090938Z..11|
+000000f0  30 34 32 34 30 39 30 39  33 38 5a 30 45 31 0b 30  |0424090938Z0E1.0|
+00000100  09 06 03 55 04 06 13 02  41 55 31 13 30 11 06 03  |...U....AU1.0...|
+00000110  55 04 08 13 0a 53 6f 6d  65 2d 53 74 61 74 65 31  |U....Some-State1|
+00000120  21 30 1f 06 03 55 04 0a  13 18 49 6e 74 65 72 6e  |!0...U....Intern|
+00000130  65 74 20 57 69 64 67 69  74 73 20 50 74 79 20 4c  |et Widgits Pty L|
+00000140  74 64 30 81 9f 30 0d 06  09 2a 86 48 86 f7 0d 01  |td0..0...*.H....|
+00000150  01 01 05 00 03 81 8d 00  30 81 89 02 81 81 00 bb  |........0.......|
+00000160  79 d6 f5 17 b5 e5 bf 46  10 d0 dc 69 be e6 2b 07  |y......F...i..+.|
+00000170  43 5a d0 03 2d 8a 7a 43  85 b7 14 52 e7 a5 65 4c  |CZ..-.zC...R..eL|
+00000180  2c 78 b8 23 8c b5 b4 82  e5 de 1f 95 3b 7e 62 a5  |,x.#........;~b.|
+00000190  2c a5 33 d6 fe 12 5c 7a  56 fc f5 06 bf fa 58 7b  |,.3...\zV.....X{|
+000001a0  26 3f b5 cd 04 d3 d0 c9  21 96 4a c7 f4 54 9f 5a  |&?......!.J..T.Z|
+000001b0  bf ef 42 71 00 fe 18 99  07 7f 7e 88 7d 7d f1 04  |..Bq......~.}}..|
+000001c0  39 c4 a2 2e db 51 c9 7c  e3 c0 4c 3b 32 66 01 cf  |9....Q.|..L;2f..|
+000001d0  af b1 1d b8 71 9a 1d db  db 89 6b ae da 2d 79 02  |....q.....k..-y.|
+000001e0  03 01 00 01 a3 81 a7 30  81 a4 30 1d 06 03 55 1d  |.......0..0...U.|
+000001f0  0e 04 16 04 14 b1 ad e2  85 5a cf cb 28 db 69 ce  |.........Z..(.i.|
+00000200  23 69 de d3 26 8e 18 88  39 30 75 06 03 55 1d 23  |#i..&...90u..U.#|
+00000210  04 6e 30 6c 80 14 b1 ad  e2 85 5a cf cb 28 db 69  |.n0l......Z..(.i|
+00000220  ce 23 69 de d3 26 8e 18  88 39 a1 49 a4 47 30 45  |.#i..&...9.I.G0E|
+00000230  31 0b 30 09 06 03 55 04  06 13 02 41 55 31 13 30  |1.0...U....AU1.0|
+00000240  11 06 03 55 04 08 13 0a  53 6f 6d 65 2d 53 74 61  |...U....Some-Sta|
+00000250  74 65 31 21 30 1f 06 03  55 04 0a 13 18 49 6e 74  |te1!0...U....Int|
+00000260  65 72 6e 65 74 20 57 69  64 67 69 74 73 20 50 74  |ernet Widgits Pt|
+00000270  79 20 4c 74 64 82 09 00  85 b0 bb a4 8a 7f b8 ca  |y Ltd...........|
+00000280  30 0c 06 03 55 1d 13 04  05 30 03 01 01 ff 30 0d  |0...U....0....0.|
+00000290  06 09 2a 86 48 86 f7 0d  01 01 05 05 00 03 81 81  |..*.H...........|
+000002a0  00 08 6c 45 24 c7 6b b1  59 ab 0c 52 cc f2 b0 14  |..lE$.k.Y..R....|
+000002b0  d7 87 9d 7a 64 75 b5 5a  95 66 e4 c5 2b 8e ae 12  |...zdu.Z.f..+...|
+000002c0  66 1f eb 4f 38 b3 6e 60  d3 92 fd f7 41 08 b5 25  |f..O8.n`....A..%|
+000002d0  13 b1 18 7a 24 fb 30 1d  ba ed 98 b9 17 ec e7 d7  |...z$.0.........|
+000002e0  31 59 db 95 d3 1d 78 ea  50 56 5c d5 82 5a 2d 5a  |1Y....x.PV\..Z-Z|
+000002f0  5f 33 c4 b6 d8 c9 75 90  96 8c 0f 52 98 b5 cd 98  |_3....u....R....|
+00000300  1f 89 20 5f f2 a0 1c a3  1b 96 94 dd a9 fd 57 e9  |.. _..........W.|
+00000310  70 e8 26 6d 71 99 9b 26  6e 38 50 29 6c 90 a7 bd  |p.&mq..&n8P)l...|
+00000320  d9 16 03 03 00 cd 0c 00  00 c9 03 00 17 41 04 99  |.............A..|
+00000330  91 58 07 9b 2b 79 26 ad  cb 37 07 5e f3 e3 75 81  |.X..+y&..7.^..u.|
+00000340  32 50 39 59 a4 7c c0 b8  c2 f4 16 de dc c3 9f ba  |2P9Y.|..........|
+00000350  04 42 a4 15 9c 8f 4e da  35 88 fc e5 b1 03 70 85  |.B....N.5.....p.|
+00000360  64 a3 6e 59 15 8c 92 11  4c 10 d9 90 f4 a9 9b 04  |d.nY....L.......|
+00000370  01 00 80 4e d1 02 4d d0  a7 7d 01 42 7a b6 75 ed  |...N..M..}.Bz.u.|
+00000380  ea 10 a3 66 a2 35 94 2d  2d 7a 32 55 63 23 df 8c  |...f.5.--z2Uc#..|
+00000390  9e ec d2 19 df bb e0 02  70 c0 50 4f 05 d8 ec 1c  |........p.PO....|
+000003a0  40 a1 a5 ae 2c 80 5b 6f  b1 f9 f9 74 20 dc 4f d7  |@...,.[o...t .O.|
+000003b0  23 b3 25 61 a7 5e 76 37  a7 17 f3 54 47 08 d9 2c  |#.%a.^v7...TG..,|
+000003c0  fb ea 4f 56 51 ee 5c cc  2f 4d 80 66 7b 21 78 1d  |..OVQ.\./M.f{!x.|
+000003d0  ef a0 71 96 cc 3d 09 8e  37 fd bc 9f 26 be 75 48  |..q..=..7...&.uH|
+000003e0  b2 a1 39 0e b3 d3 73 f5  f1 68 4f aa 03 92 c0 1f  |..9...s..hO.....|
+000003f0  90 74 a9 16 03 03 00 2e  0d 00 00 26 03 01 02 40  |.t.........&...@|
+00000400  00 1e 06 01 06 02 06 03  05 01 05 02 05 03 04 01  |................|
+00000410  04 02 04 03 03 01 03 02  03 03 02 01 02 02 02 03  |................|
+00000420  00 00 0e 00 00 00                                 |......|
+>>> Flow 3 (client to server)
+00000000  16 03 03 01 fb 0b 00 01  f7 00 01 f4 00 01 f1 30  |...............0|
+00000010  82 01 ed 30 82 01 58 a0  03 02 01 02 02 01 00 30  |...0..X........0|
+00000020  0b 06 09 2a 86 48 86 f7  0d 01 01 05 30 26 31 10  |...*.H......0&1.|
+00000030  30 0e 06 03 55 04 0a 13  07 41 63 6d 65 20 43 6f  |0...U....Acme Co|
+00000040  31 12 30 10 06 03 55 04  03 13 09 31 32 37 2e 30  |1.0...U....127.0|
+00000050  2e 30 2e 31 30 1e 17 0d  31 31 31 32 30 38 30 37  |.0.10...11120807|
+00000060  35 35 31 32 5a 17 0d 31  32 31 32 30 37 30 38 30  |5512Z..121207080|
+00000070  30 31 32 5a 30 26 31 10  30 0e 06 03 55 04 0a 13  |012Z0&1.0...U...|
+00000080  07 41 63 6d 65 20 43 6f  31 12 30 10 06 03 55 04  |.Acme Co1.0...U.|
+00000090  03 13 09 31 32 37 2e 30  2e 30 2e 31 30 81 9c 30  |...127.0.0.10..0|
+000000a0  0b 06 09 2a 86 48 86 f7  0d 01 01 01 03 81 8c 00  |...*.H..........|
+000000b0  30 81 88 02 81 80 4e d0  7b 31 e3 82 64 d9 59 c0  |0.....N.{1..d.Y.|
+000000c0  c2 87 a4 5e 1e 8b 73 33  c7 63 53 df 66 92 06 84  |...^..s3.cS.f...|
+000000d0  f6 64 d5 8f e4 36 a7 1d  2b e8 b3 20 36 45 23 b5  |.d...6..+.. 6E#.|
+000000e0  e3 95 ae ed e0 f5 20 9c  8d 95 df 7f 5a 12 ef 87  |...... .....Z...|
+000000f0  e4 5b 68 e4 e9 0e 74 ec  04 8a 7f de 93 27 c4 01  |.[h...t......'..|
+00000100  19 7a bd f2 dc 3d 14 ab  d0 54 ca 21 0c d0 4d 6e  |.z...=...T.!..Mn|
+00000110  87 2e 5c c5 d2 bb 4d 4b  4f ce b6 2c f7 7e 88 ec  |..\...MKO..,.~..|
+00000120  7c d7 02 91 74 a6 1e 0c  1a da e3 4a 5a 2e de 13  ||...t......JZ...|
+00000130  9c 4c 40 88 59 93 02 03  01 00 01 a3 32 30 30 30  |.L@.Y.......2000|
+00000140  0e 06 03 55 1d 0f 01 01  ff 04 04 03 02 00 a0 30  |...U...........0|
+00000150  0d 06 03 55 1d 0e 04 06  04 04 01 02 03 04 30 0f  |...U..........0.|
+00000160  06 03 55 1d 23 04 08 30  06 80 04 01 02 03 04 30  |..U.#..0.......0|
+00000170  0b 06 09 2a 86 48 86 f7  0d 01 01 05 03 81 81 00  |...*.H..........|
+00000180  36 1f b3 7a 0c 75 c9 6e  37 46 61 2b d5 bd c0 a7  |6..z.u.n7Fa+....|
+00000190  4b cc 46 9a 81 58 7c 85  79 29 c8 c8 c6 67 dd 32  |K.F..X|.y)...g.2|
+000001a0  56 45 2b 75 b6 e9 24 a9  50 9a be 1f 5a fa 1a 15  |VE+u..$.P...Z...|
+000001b0  d9 cc 55 95 72 16 83 b9  c2 b6 8f fd 88 8c 38 84  |..U.r.........8.|
+000001c0  1d ab 5d 92 31 13 4f fd  83 3b c6 9d f1 11 62 b6  |..].1.O..;....b.|
+000001d0  8b ec ab 67 be c8 64 b0  11 50 46 58 17 6b 99 1c  |...g..d..PFX.k..|
+000001e0  d3 1d fc 06 f1 0e e5 96  a8 0c f9 78 20 b7 44 18  |...........x .D.|
+000001f0  51 8d 10 7e 4f 94 67 df  a3 4e 70 73 8e 90 91 85  |Q..~O.g..Nps....|
+00000200  16 03 03 00 46 10 00 00  42 41 04 1e 18 37 ef 0d  |....F...BA...7..|
+00000210  19 51 88 35 75 71 b5 e5  54 5b 12 2e 8f 09 67 fd  |.Q.5uq..T[....g.|
+00000220  a7 24 20 3e b2 56 1c ce  97 28 5e f8 2b 2d 4f 9e  |.$ >.V...(^.+-O.|
+00000230  f1 07 9f 6c 4b 5b 83 56  e2 32 42 e9 58 b6 d7 49  |...lK[.V.2B.X..I|
+00000240  a6 b5 68 1a 41 03 56 6b  dc 5a 89 16 03 03 00 88  |..h.A.Vk.Z......|
+00000250  0f 00 00 84 05 01 00 80  2c 1c b4 c4 d6 73 62 3a  |........,....sb:|
+00000260  86 37 c5 cb 3d 28 5f 3b  7f e2 08 f8 38 ef dc c4  |.7..=(_;....8...|
+00000270  a9 13 b6 82 28 0a 3a 67  48 01 c7 54 1d 4f b4 b4  |....(.:gH..T.O..|
+00000280  4e a8 5b fc b6 9b 27 7c  e3 a6 d7 88 62 2d 2c ca  |N.[...'|....b-,.|
+00000290  35 55 b3 99 ac 4e 28 45  55 29 3e 30 fc 46 6b 86  |5U...N(EU)>0.Fk.|
+000002a0  20 0b b1 d0 7c c5 07 cd  d8 49 5a 88 dd c2 bc 5d  | ...|....IZ....]|
+000002b0  5f ad 52 d8 be 56 e4 fd  f8 ab ef 17 04 08 50 a5  |_.R..V........P.|
+000002c0  2f 52 58 e5 31 51 e4 83  44 41 c0 8e 16 cf 39 4f  |/RX.1Q..DA....9O|
+000002d0  3d de c8 19 1e 5c c3 a7  14 03 03 00 01 01 16 03  |=....\..........|
+000002e0  03 00 28 00 00 00 00 00  00 00 00 2c e0 65 72 59  |..(........,.erY|
+000002f0  1e 0a ff 8b 58 74 14 c8  c5 fa db 08 06 4f a1 d4  |....Xt.......O..|
+00000300  20 cc f4 3e 6a f5 5c 0f  8e 26 1d                 | ..>j.\..&.|
+>>> Flow 4 (server to client)
+00000000  14 03 03 00 01 01 16 03  03 00 28 59 f7 e1 f5 7c  |..........(Y...||
+00000010  ef 54 7c ee 08 29 50 82  d2 43 32 f5 c1 bc af 0c  |.T|..)P..C2.....|
+00000020  5f 4f 6e 9a fd 65 8c 4d  ef c4 0e ec 6a ea 46 73  |_On..e.M....j.Fs|
+00000030  e2 9f 4a                                          |..J|
+>>> Flow 5 (client to server)
+00000000  17 03 03 00 1e 00 00 00  00 00 00 00 01 4d b2 6d  |.............M.m|
+00000010  73 75 d3 68 3d a5 7c 98  32 3f b2 4a 47 3f b2 95  |su.h=.|.2?.JG?..|
+00000020  8f cd 99 15 03 03 00 1a  00 00 00 00 00 00 00 02  |................|
+00000030  91 31 70 57 68 0a e1 e1  1b ca f0 62 ab 22 da 3d  |.1pWh......b.".=|
+00000040  e1 64                                             |.d|
diff --git a/src/crypto/x509/cert_pool.go b/src/crypto/x509/cert_pool.go
index babe94d..2362e84 100644
--- a/src/crypto/x509/cert_pool.go
+++ b/src/crypto/x509/cert_pool.go
@@ -77,7 +77,7 @@
 }
 
 // AppendCertsFromPEM attempts to parse a series of PEM encoded certificates.
-// It appends any certificates found to s and returns true if any certificates
+// It appends any certificates found to s and reports whether any certificates
 // were successfully parsed.
 //
 // On many Linux systems, /etc/ssl/cert.pem will contain the system wide set
diff --git a/src/crypto/x509/pem_decrypt.go b/src/crypto/x509/pem_decrypt.go
index 194c81b..1d2c1c6 100644
--- a/src/crypto/x509/pem_decrypt.go
+++ b/src/crypto/x509/pem_decrypt.go
@@ -108,7 +108,10 @@
 // encrypt it and returns a slice of decrypted DER encoded bytes. It inspects
 // the DEK-Info header to determine the algorithm used for decryption. If no
 // DEK-Info header is present, an error is returned. If an incorrect password
-// is detected an IncorrectPasswordError is returned.
+// is detected an IncorrectPasswordError is returned. Because of deficiencies
+// in the encrypted-PEM format, it's not always possible to detect an incorrect
+// password. In these cases no error will be returned but the decrypted DER
+// bytes will be random noise.
 func DecryptPEMBlock(b *pem.Block, password []byte) ([]byte, error) {
 	dek, ok := b.Headers["DEK-Info"]
 	if !ok {
diff --git a/src/crypto/x509/sha2_windows_test.go b/src/crypto/x509/sha2_windows_test.go
new file mode 100644
index 0000000..79dc685
--- /dev/null
+++ b/src/crypto/x509/sha2_windows_test.go
@@ -0,0 +1,19 @@
+// Copyright 2015 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 x509
+
+import "syscall"
+
+func init() {
+	v, err := syscall.GetVersion()
+	if err != nil {
+		return
+	}
+	if major := byte(v); major < 6 {
+		// Windows XP SP2 and Windows 2003 do not support SHA2.
+		// http://blogs.technet.com/b/pki/archive/2010/09/30/sha2-and-windows.aspx
+		supportSHA2 = false
+	}
+}
diff --git a/src/crypto/x509/verify_test.go b/src/crypto/x509/verify_test.go
index 96b9d9b..20a3e31 100644
--- a/src/crypto/x509/verify_test.go
+++ b/src/crypto/x509/verify_test.go
@@ -14,6 +14,8 @@
 	"time"
 )
 
+var supportSHA2 = true
+
 type verifyTest struct {
 	leaf                 string
 	intermediates        []string
@@ -23,6 +25,7 @@
 	systemSkip           bool
 	keyUsages            []ExtKeyUsage
 	testSystemRootsError bool
+	sha2                 bool
 
 	errorCallback  func(*testing.T, int, error) bool
 	expectedChains [][]string
@@ -218,6 +221,7 @@
 		currentTime:   1397502195,
 		dnsName:       "api.moip.com.br",
 
+		sha2: true,
 		expectedChains: [][]string{
 			{
 				"api.moip.com.br",
@@ -297,6 +301,9 @@
 		if runtime.GOOS == "windows" && test.testSystemRootsError {
 			continue
 		}
+		if useSystemRoots && !supportSHA2 && test.sha2 {
+			continue
+		}
 
 		opts := VerifyOptions{
 			Intermediates: NewCertPool(),
diff --git a/src/database/sql/sql.go b/src/database/sql/sql.go
index 1ce679d..b0e8894 100644
--- a/src/database/sql/sql.go
+++ b/src/database/sql/sql.go
@@ -572,6 +572,22 @@
 	}
 }
 
+// DBStats contains database statistics.
+type DBStats struct {
+	// OpenConnections is the number of open connections to the database.
+	OpenConnections int
+}
+
+// Stats returns database statistics.
+func (db *DB) Stats() DBStats {
+	db.mu.Lock()
+	stats := DBStats{
+		OpenConnections: db.numOpen,
+	}
+	db.mu.Unlock()
+	return stats
+}
+
 // Assumes db.mu is locked.
 // If there are connRequests and the connection limit hasn't been reached,
 // then tell the connectionOpener to open new connections.
diff --git a/src/database/sql/sql_test.go b/src/database/sql/sql_test.go
index 60bdefa..e225ffe 100644
--- a/src/database/sql/sql_test.go
+++ b/src/database/sql/sql_test.go
@@ -1093,6 +1093,26 @@
 	}
 }
 
+func TestStats(t *testing.T) {
+	db := newTestDB(t, "people")
+	stats := db.Stats()
+	if got := stats.OpenConnections; got != 1 {
+		t.Errorf("stats.OpenConnections = %d; want 1", got)
+	}
+
+	tx, err := db.Begin()
+	if err != nil {
+		t.Fatal(err)
+	}
+	tx.Commit()
+
+	closeDB(t, db)
+	stats = db.Stats()
+	if got := stats.OpenConnections; got != 0 {
+		t.Errorf("stats.OpenConnections = %d; want 0", got)
+	}
+}
+
 // golang.org/issue/5323
 func TestStmtCloseDeps(t *testing.T) {
 	if testing.Short() {
diff --git a/src/debug/dwarf/buf.go b/src/debug/dwarf/buf.go
index 53c46eb..2ade0bd 100644
--- a/src/debug/dwarf/buf.go
+++ b/src/debug/dwarf/buf.go
@@ -163,6 +163,17 @@
 	return 0
 }
 
+func (b *buf) unitLength() (length Offset, dwarf64 bool) {
+	length = Offset(b.uint32())
+	if length == 0xffffffff {
+		dwarf64 = true
+		length = Offset(b.uint64())
+	} else if length >= 0xfffffff0 {
+		b.error("unit length has reserved value")
+	}
+	return
+}
+
 func (b *buf) error(s string) {
 	if b.err == nil {
 		b.data = nil
diff --git a/src/debug/dwarf/const.go b/src/debug/dwarf/const.go
index 93c6888..2170db1 100644
--- a/src/debug/dwarf/const.go
+++ b/src/debug/dwarf/const.go
@@ -452,3 +452,31 @@
 	encUnsignedChar   = 0x08
 	encImaginaryFloat = 0x09
 )
+
+// Statement program standard opcode encodings.
+const (
+	lnsCopy           = 1
+	lnsAdvancePC      = 2
+	lnsAdvanceLine    = 3
+	lnsSetFile        = 4
+	lnsSetColumn      = 5
+	lnsNegateStmt     = 6
+	lnsSetBasicBlock  = 7
+	lnsConstAddPC     = 8
+	lnsFixedAdvancePC = 9
+
+	// DWARF 3
+	lnsSetPrologueEnd   = 10
+	lnsSetEpilogueBegin = 11
+	lnsSetISA           = 12
+)
+
+// Statement program extended opcode encodings.
+const (
+	lneEndSequence = 1
+	lneSetAddress  = 2
+	lneDefineFile  = 3
+
+	// DWARF 4
+	lneSetDiscriminator = 4
+)
diff --git a/src/debug/dwarf/entry.go b/src/debug/dwarf/entry.go
index 665c684..2742ae0 100644
--- a/src/debug/dwarf/entry.go
+++ b/src/debug/dwarf/entry.go
@@ -112,7 +112,7 @@
 //
 // A common idiom is to merge the check for nil return with
 // the check that the value has the expected dynamic type, as in:
-//	v, ok := e.Val(AttrSibling).(int64);
+//	v, ok := e.Val(AttrSibling).(int64)
 //
 func (e *Entry) Val(a Attr) interface{} {
 	for _, f := range e.Field {
@@ -308,18 +308,13 @@
 		return
 	}
 
-	// TODO(rsc): binary search (maybe a new package)
-	var i int
-	var u *unit
-	for i = range d.unit {
-		u = &d.unit[i]
-		if u.off <= off && off < u.off+Offset(len(u.data)) {
-			r.unit = i
-			r.b = makeBuf(r.d, u, "info", off, u.data[off-u.off:])
-			return
-		}
+	i := d.offsetToUnit(off)
+	if i == -1 {
+		r.err = errors.New("offset out of range")
 	}
-	r.err = errors.New("offset out of range")
+	u := &d.unit[i]
+	r.unit = i
+	r.b = makeBuf(r.d, u, "info", off, u.data[off-u.off:])
 }
 
 // maybeNextUnit advances to the next unit if this one is finished.
diff --git a/src/debug/dwarf/line.go b/src/debug/dwarf/line.go
new file mode 100644
index 0000000..ca64bbd
--- /dev/null
+++ b/src/debug/dwarf/line.go
@@ -0,0 +1,590 @@
+// Copyright 2015 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 dwarf
+
+import (
+	"errors"
+	"fmt"
+	"io"
+	"path"
+)
+
+// A LineReader reads a sequence of LineEntry structures from a DWARF
+// "line" section for a single compilation unit. LineEntries occur in
+// order of increasing PC and each LineEntry gives metadata for the
+// instructions from that LineEntry's PC to just before the next
+// LineEntry's PC. The last entry will have its EndSequence field set.
+type LineReader struct {
+	buf buf
+
+	// Original .debug_line section data. Used by Seek.
+	section []byte
+
+	// Header information
+	version              uint16
+	minInstructionLength int
+	maxOpsPerInstruction int
+	defaultIsStmt        bool
+	lineBase             int
+	lineRange            int
+	opcodeBase           int
+	opcodeLengths        []int
+	directories          []string
+	fileEntries          []*LineFile
+
+	programOffset Offset // section offset of line number program
+	endOffset     Offset // section offset of byte following program
+
+	initialFileEntries int // initial length of fileEntries
+
+	// Current line number program state machine registers
+	state     LineEntry // public state
+	fileIndex int       // private state
+}
+
+// A LineEntry is a row in a DWARF line table.
+type LineEntry struct {
+	// Address is the program-counter value of a machine
+	// instruction generated by the compiler. This LineEntry
+	// applies to each instruction from Address to just before the
+	// Address of the next LineEntry.
+	Address uint64
+
+	// OpIndex is the index of an operation within a VLIW
+	// instruction. The index of the first operation is 0. For
+	// non-VLIW architectures, it will always be 0. Address and
+	// OpIndex together form an operation pointer that can
+	// reference any individual operation within the instruction
+	// stream.
+	OpIndex int
+
+	// File is the source file corresponding to these
+	// instructions.
+	File *LineFile
+
+	// Line is the source code line number corresponding to these
+	// instructions. Lines are numbered beginning at 1. It may be
+	// 0 if these instructions cannot be attributed to any source
+	// line.
+	Line int
+
+	// Column is the column number within the source line of these
+	// instructions. Columns are numbered beginning at 1. It may
+	// be 0 to indicate the "left edge" of the line.
+	Column int
+
+	// IsStmt indicates that Address is a recommended breakpoint
+	// location, such as the beginning of a line, statement, or a
+	// distinct subpart of a statement.
+	IsStmt bool
+
+	// BasicBlock indicates that Address is the beginning of a
+	// basic block.
+	BasicBlock bool
+
+	// PrologueEnd indicates that Address is one (of possibly
+	// many) PCs where execution should be suspended for a
+	// breakpoint on entry to the containing function.
+	//
+	// Added in DWARF 3.
+	PrologueEnd bool
+
+	// EpilogueBegin indicates that Address is one (of possibly
+	// many) PCs where execution should be suspended for a
+	// breakpoint on exit from this function.
+	//
+	// Added in DWARF 3.
+	EpilogueBegin bool
+
+	// ISA is the instruction set architecture for these
+	// instructions. Possible ISA values should be defined by the
+	// applicable ABI specification.
+	//
+	// Added in DWARF 3.
+	ISA int
+
+	// Discriminator is an arbitrary integer indicating the block
+	// to which these instructions belong. It serves to
+	// distinguish among multiple blocks that may all have with
+	// the same source file, line, and column. Where only one
+	// block exists for a given source position, it should be 0.
+	//
+	// Added in DWARF 3.
+	Discriminator int
+
+	// EndSequence indicates that Address is the first byte after
+	// the end of a sequence of target machine instructions. If it
+	// is set, only this and the Address field are meaningful. A
+	// line number table may contain information for multiple
+	// potentially disjoint instruction sequences. The last entry
+	// in a line table should always have EndSequence set.
+	EndSequence bool
+}
+
+// A LineFile is a source file referenced by a DWARF line table entry.
+type LineFile struct {
+	Name   string
+	Mtime  uint64 // Implementation defined modification time, or 0 if unknown
+	Length int    // File length, or 0 if unknown
+}
+
+// LineReader returns a new reader for the line table of compilation
+// unit cu, which must be an Entry with tag TagCompileUnit.
+//
+// If this compilation unit has no line table, it returns nil, nil.
+func (d *Data) LineReader(cu *Entry) (*LineReader, error) {
+	if d.line == nil {
+		// No line tables available.
+		return nil, nil
+	}
+
+	// Get line table information from cu.
+	off, ok := cu.Val(AttrStmtList).(int64)
+	if !ok {
+		// cu has no line table.
+		return nil, nil
+	}
+	if off > int64(len(d.line)) {
+		return nil, errors.New("AttrStmtList value out of range")
+	}
+	// AttrCompDir is optional if all file names are absolute. Use
+	// the empty string if it's not present.
+	compDir, _ := cu.Val(AttrCompDir).(string)
+
+	// Create the LineReader.
+	u := &d.unit[d.offsetToUnit(cu.Offset)]
+	buf := makeBuf(d, u, "line", Offset(off), d.line[off:])
+	// The compilation directory is implicitly directories[0].
+	r := LineReader{buf: buf, section: d.line, directories: []string{compDir}}
+
+	// Read the header.
+	if err := r.readHeader(); err != nil {
+		return nil, err
+	}
+
+	// Initialize line reader state.
+	r.Reset()
+
+	return &r, nil
+}
+
+// readHeader reads the line number program header from r.buf and sets
+// all of the header fields in r.
+func (r *LineReader) readHeader() error {
+	buf := &r.buf
+
+	// Read basic header fields [DWARF2 6.2.4].
+	hdrOffset := buf.off
+	unitLength, dwarf64 := buf.unitLength()
+	r.endOffset = buf.off + unitLength
+	if r.endOffset > buf.off+Offset(len(buf.data)) {
+		return DecodeError{"line", hdrOffset, fmt.Sprintf("line table end %d exceeds section size %d", r.endOffset, buf.off+Offset(len(buf.data)))}
+	}
+	r.version = buf.uint16()
+	if buf.err == nil && (r.version < 2 || r.version > 4) {
+		// DWARF goes to all this effort to make new opcodes
+		// backward-compatible, and then adds fields right in
+		// the middle of the header in new versions, so we're
+		// picky about only supporting known line table
+		// versions.
+		return DecodeError{"line", hdrOffset, fmt.Sprintf("unknown line table version %d", r.version)}
+	}
+	var headerLength Offset
+	if dwarf64 {
+		headerLength = Offset(buf.uint64())
+	} else {
+		headerLength = Offset(buf.uint32())
+	}
+	r.programOffset = buf.off + headerLength
+	r.minInstructionLength = int(buf.uint8())
+	if r.version >= 4 {
+		// [DWARF4 6.2.4]
+		r.maxOpsPerInstruction = int(buf.uint8())
+	} else {
+		r.maxOpsPerInstruction = 1
+	}
+	r.defaultIsStmt = buf.uint8() != 0
+	r.lineBase = int(int8(buf.uint8()))
+	r.lineRange = int(buf.uint8())
+
+	// Validate header.
+	if buf.err != nil {
+		return buf.err
+	}
+	if r.maxOpsPerInstruction == 0 {
+		return DecodeError{"line", hdrOffset, "invalid maximum operations per instruction: 0"}
+	}
+	if r.lineRange == 0 {
+		return DecodeError{"line", hdrOffset, "invalid line range: 0"}
+	}
+
+	// Read standard opcode length table. This table starts with opcode 1.
+	r.opcodeBase = int(buf.uint8())
+	r.opcodeLengths = make([]int, r.opcodeBase)
+	for i := 1; i < r.opcodeBase; i++ {
+		r.opcodeLengths[i] = int(buf.uint8())
+	}
+
+	// Validate opcode lengths.
+	if buf.err != nil {
+		return buf.err
+	}
+	for i, length := range r.opcodeLengths {
+		if known, ok := knownOpcodeLengths[i]; ok && known != length {
+			return DecodeError{"line", hdrOffset, fmt.Sprintf("opcode %d expected to have length %d, but has length %d", i, known, length)}
+		}
+	}
+
+	// Read include directories table. The caller already set
+	// directories[0] to the compilation directory.
+	for {
+		directory := buf.string()
+		if buf.err != nil {
+			return buf.err
+		}
+		if len(directory) == 0 {
+			break
+		}
+		if !path.IsAbs(directory) {
+			// Relative paths are implicitly relative to
+			// the compilation directory.
+			directory = path.Join(r.directories[0], directory)
+		}
+		r.directories = append(r.directories, directory)
+	}
+
+	// Read file name list. File numbering starts with 1, so leave
+	// the first entry nil.
+	r.fileEntries = make([]*LineFile, 1)
+	for {
+		if done, err := r.readFileEntry(); err != nil {
+			return err
+		} else if done {
+			break
+		}
+	}
+	r.initialFileEntries = len(r.fileEntries)
+
+	return buf.err
+}
+
+// readFileEntry reads a file entry from either the header or a
+// DW_LNE_define_file extended opcode and adds it to r.fileEntries. A
+// true return value indicates that there are no more entries to read.
+func (r *LineReader) readFileEntry() (bool, error) {
+	name := r.buf.string()
+	if r.buf.err != nil {
+		return false, r.buf.err
+	}
+	if len(name) == 0 {
+		return true, nil
+	}
+	off := r.buf.off
+	dirIndex := int(r.buf.uint())
+	if !path.IsAbs(name) {
+		if dirIndex >= len(r.directories) {
+			return false, DecodeError{"line", off, "directory index too large"}
+		}
+		name = path.Join(r.directories[dirIndex], name)
+	}
+	mtime := r.buf.uint()
+	length := int(r.buf.uint())
+
+	r.fileEntries = append(r.fileEntries, &LineFile{name, mtime, length})
+	return false, nil
+}
+
+// updateFile updates r.state.File after r.fileIndex has
+// changed or r.fileEntries has changed.
+func (r *LineReader) updateFile() {
+	if r.fileIndex < len(r.fileEntries) {
+		r.state.File = r.fileEntries[r.fileIndex]
+	} else {
+		r.state.File = nil
+	}
+}
+
+// Next sets *entry to the next row in this line table and moves to
+// the next row. If there are no more entries and the line table is
+// properly terminated, it returns io.EOF.
+//
+// Rows are always in order of increasing entry.Address, but
+// entry.Line may go forward or backward.
+func (r *LineReader) Next(entry *LineEntry) error {
+	if r.buf.err != nil {
+		return r.buf.err
+	}
+
+	// Execute opcodes until we reach an opcode that emits a line
+	// table entry.
+	for {
+		if len(r.buf.data) == 0 {
+			return io.EOF
+		}
+		emit := r.step(entry)
+		if r.buf.err != nil {
+			return r.buf.err
+		}
+		if emit {
+			return nil
+		}
+	}
+}
+
+// knownOpcodeLengths gives the opcode lengths (in varint arguments)
+// of known standard opcodes.
+var knownOpcodeLengths = map[int]int{
+	lnsCopy:             0,
+	lnsAdvancePC:        1,
+	lnsAdvanceLine:      1,
+	lnsSetFile:          1,
+	lnsNegateStmt:       0,
+	lnsSetBasicBlock:    0,
+	lnsConstAddPC:       0,
+	lnsSetPrologueEnd:   0,
+	lnsSetEpilogueBegin: 0,
+	lnsSetISA:           1,
+	// lnsFixedAdvancePC takes a uint8 rather than a varint; it's
+	// unclear what length the header is supposed to claim, so
+	// ignore it.
+}
+
+// step processes the next opcode and updates r.state. If the opcode
+// emits a row in the line table, this updates *entry and returns
+// true.
+func (r *LineReader) step(entry *LineEntry) bool {
+	opcode := int(r.buf.uint8())
+
+	if opcode >= r.opcodeBase {
+		// Special opcode [DWARF2 6.2.5.1, DWARF4 6.2.5.1]
+		adjustedOpcode := opcode - r.opcodeBase
+		r.advancePC(adjustedOpcode / r.lineRange)
+		lineDelta := r.lineBase + int(adjustedOpcode)%r.lineRange
+		r.state.Line += lineDelta
+		goto emit
+	}
+
+	switch opcode {
+	case 0:
+		// Extended opcode [DWARF2 6.2.5.3]
+		length := Offset(r.buf.uint())
+		startOff := r.buf.off
+		opcode := r.buf.uint8()
+
+		switch opcode {
+		case lneEndSequence:
+			r.state.EndSequence = true
+			*entry = r.state
+			r.resetState()
+
+		case lneSetAddress:
+			r.state.Address = r.buf.addr()
+
+		case lneDefineFile:
+			if done, err := r.readFileEntry(); err != nil {
+				r.buf.err = err
+				return false
+			} else if done {
+				r.buf.err = DecodeError{"line", startOff, "malformed DW_LNE_define_file operation"}
+				return false
+			}
+			r.updateFile()
+
+		case lneSetDiscriminator:
+			// [DWARF4 6.2.5.3]
+			r.state.Discriminator = int(r.buf.uint())
+		}
+
+		r.buf.skip(int(startOff + length - r.buf.off))
+
+		if opcode == lneEndSequence {
+			return true
+		}
+
+	// Standard opcodes [DWARF2 6.2.5.2]
+	case lnsCopy:
+		goto emit
+
+	case lnsAdvancePC:
+		r.advancePC(int(r.buf.uint()))
+
+	case lnsAdvanceLine:
+		r.state.Line += int(r.buf.int())
+
+	case lnsSetFile:
+		r.fileIndex = int(r.buf.uint())
+		r.updateFile()
+
+	case lnsSetColumn:
+		r.state.Column = int(r.buf.uint())
+
+	case lnsNegateStmt:
+		r.state.IsStmt = !r.state.IsStmt
+
+	case lnsSetBasicBlock:
+		r.state.BasicBlock = true
+
+	case lnsConstAddPC:
+		r.advancePC((255 - r.opcodeBase) / r.lineRange)
+
+	case lnsFixedAdvancePC:
+		r.state.Address += uint64(r.buf.uint16())
+
+	// DWARF3 standard opcodes [DWARF3 6.2.5.2]
+	case lnsSetPrologueEnd:
+		r.state.PrologueEnd = true
+
+	case lnsSetEpilogueBegin:
+		r.state.EpilogueBegin = true
+
+	case lnsSetISA:
+		r.state.ISA = int(r.buf.uint())
+
+	default:
+		// Unhandled standard opcode. Skip the number of
+		// arguments that the prologue says this opcode has.
+		for i := 0; i < r.opcodeLengths[opcode]; i++ {
+			r.buf.uint()
+		}
+	}
+	return false
+
+emit:
+	*entry = r.state
+	r.state.BasicBlock = false
+	r.state.PrologueEnd = false
+	r.state.EpilogueBegin = false
+	r.state.Discriminator = 0
+	return true
+}
+
+// advancePC advances "operation pointer" (the combination of Address
+// and OpIndex) in r.state by opAdvance steps.
+func (r *LineReader) advancePC(opAdvance int) {
+	opIndex := r.state.OpIndex + opAdvance
+	r.state.Address += uint64(r.minInstructionLength * (opIndex / r.maxOpsPerInstruction))
+	r.state.OpIndex = opIndex % r.maxOpsPerInstruction
+}
+
+// A LineReaderPos represents a position in a line table.
+type LineReaderPos struct {
+	// off is the current offset in the DWARF line section.
+	off Offset
+	// numFileEntries is the length of fileEntries.
+	numFileEntries int
+	// state and fileIndex are the statement machine state at
+	// offset off.
+	state     LineEntry
+	fileIndex int
+}
+
+// Tell returns the current position in the line table.
+func (r *LineReader) Tell() LineReaderPos {
+	return LineReaderPos{r.buf.off, len(r.fileEntries), r.state, r.fileIndex}
+}
+
+// Seek restores the line table reader to a position returned by Tell.
+//
+// The argument pos must have been returned by a call to Tell on this
+// line table.
+func (r *LineReader) Seek(pos LineReaderPos) {
+	r.buf.off = pos.off
+	r.buf.data = r.section[r.buf.off:r.endOffset]
+	r.fileEntries = r.fileEntries[:pos.numFileEntries]
+	r.state = pos.state
+	r.fileIndex = pos.fileIndex
+}
+
+// Reset repositions the line table reader at the beginning of the
+// line table.
+func (r *LineReader) Reset() {
+	// Reset buffer to the line number program offset.
+	r.buf.off = r.programOffset
+	r.buf.data = r.section[r.buf.off:r.endOffset]
+
+	// Reset file entries list.
+	r.fileEntries = r.fileEntries[:r.initialFileEntries]
+
+	// Reset line number program state.
+	r.resetState()
+}
+
+// resetState resets r.state to its default values
+func (r *LineReader) resetState() {
+	// Reset the state machine registers to the defaults given in
+	// [DWARF4 6.2.2].
+	r.state = LineEntry{
+		Address:       0,
+		OpIndex:       0,
+		File:          nil,
+		Line:          1,
+		Column:        0,
+		IsStmt:        r.defaultIsStmt,
+		BasicBlock:    false,
+		PrologueEnd:   false,
+		EpilogueBegin: false,
+		ISA:           0,
+		Discriminator: 0,
+	}
+	r.fileIndex = 1
+	r.updateFile()
+}
+
+// ErrUnknownPC is the error returned by LineReader.ScanPC when the
+// seek PC is not covered by any entry in the line table.
+var ErrUnknownPC = errors.New("ErrUnknownPC")
+
+// SeekPC sets *entry to the LineEntry that includes pc and positions
+// the reader on the next entry in the line table. If necessary, this
+// will seek backwards to find pc.
+//
+// If pc is not covered by any entry in this line table, SeekPC
+// returns ErrUnknownPC. In this case, *entry and the final seek
+// position are unspecified.
+//
+// Note that DWARF line tables only permit sequential, forward scans.
+// Hence, in the worst case, this takes time linear in the size of the
+// line table. If the caller wishes to do repeated fast PC lookups, it
+// should build an appropriate index of the line table.
+func (r *LineReader) SeekPC(pc uint64, entry *LineEntry) error {
+	if err := r.Next(entry); err != nil {
+		return err
+	}
+	if entry.Address > pc {
+		// We're too far. Start at the beginning of the table.
+		r.Reset()
+		if err := r.Next(entry); err != nil {
+			return err
+		}
+		if entry.Address > pc {
+			// The whole table starts after pc.
+			r.Reset()
+			return ErrUnknownPC
+		}
+	}
+
+	// Scan until we pass pc, then back up one.
+	for {
+		var next LineEntry
+		pos := r.Tell()
+		if err := r.Next(&next); err != nil {
+			if err == io.EOF {
+				return ErrUnknownPC
+			}
+			return err
+		}
+		if next.Address > pc {
+			if entry.EndSequence {
+				// pc is in a hole in the table.
+				return ErrUnknownPC
+			}
+			// entry is the desired entry. Back up the
+			// cursor to "next" and return success.
+			r.Seek(pos)
+			return nil
+		}
+		*entry = next
+	}
+}
diff --git a/src/debug/dwarf/line_test.go b/src/debug/dwarf/line_test.go
new file mode 100644
index 0000000..4104b5d
--- /dev/null
+++ b/src/debug/dwarf/line_test.go
@@ -0,0 +1,229 @@
+// Copyright 2015 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 dwarf_test
+
+import (
+	. "debug/dwarf"
+	"io"
+	"testing"
+)
+
+var (
+	file1C = &LineFile{Name: "/home/austin/go.dev/src/debug/dwarf/testdata/line1.c"}
+	file1H = &LineFile{Name: "/home/austin/go.dev/src/debug/dwarf/testdata/line1.h"}
+	file2C = &LineFile{Name: "/home/austin/go.dev/src/debug/dwarf/testdata/line2.c"}
+)
+
+func TestLineELFGCC(t *testing.T) {
+	// Generated by:
+	//   # gcc --version | head -n1
+	//   gcc (Ubuntu 4.8.2-19ubuntu1) 4.8.2
+	//   # gcc -g -o line-gcc.elf line*.c
+
+	// Line table based on readelf --debug-dump=rawline,decodedline
+	want := []LineEntry{
+		{Address: 0x40059d, File: file1H, Line: 2, IsStmt: true},
+		{Address: 0x4005a5, File: file1H, Line: 2, IsStmt: true},
+		{Address: 0x4005b4, File: file1H, Line: 5, IsStmt: true},
+		{Address: 0x4005bd, File: file1H, Line: 6, IsStmt: true, Discriminator: 2},
+		{Address: 0x4005c7, File: file1H, Line: 5, IsStmt: true, Discriminator: 2},
+		{Address: 0x4005cb, File: file1H, Line: 5, IsStmt: false, Discriminator: 1},
+		{Address: 0x4005d1, File: file1H, Line: 7, IsStmt: true},
+		{Address: 0x4005e7, File: file1C, Line: 6, IsStmt: true},
+		{Address: 0x4005eb, File: file1C, Line: 7, IsStmt: true},
+		{Address: 0x4005f5, File: file1C, Line: 8, IsStmt: true},
+		{Address: 0x4005ff, File: file1C, Line: 9, IsStmt: true},
+		{Address: 0x400601, EndSequence: true},
+
+		{Address: 0x400601, File: file2C, Line: 4, IsStmt: true},
+		{Address: 0x400605, File: file2C, Line: 5, IsStmt: true},
+		{Address: 0x40060f, File: file2C, Line: 6, IsStmt: true},
+		{Address: 0x400611, EndSequence: true},
+	}
+
+	testLineTable(t, want, elfData(t, "testdata/line-gcc.elf"))
+}
+
+func TestLineELFClang(t *testing.T) {
+	// Generated by:
+	//   # clang --version | head -n1
+	//   Ubuntu clang version 3.4-1ubuntu3 (tags/RELEASE_34/final) (based on LLVM 3.4)
+	//   # clang -g -o line-clang.elf line*.
+
+	want := []LineEntry{
+		{Address: 0x400530, File: file1C, Line: 6, IsStmt: true},
+		{Address: 0x400534, File: file1C, Line: 7, IsStmt: true, PrologueEnd: true},
+		{Address: 0x400539, File: file1C, Line: 8, IsStmt: true},
+		{Address: 0x400545, File: file1C, Line: 9, IsStmt: true},
+		{Address: 0x400550, File: file1H, Line: 2, IsStmt: true},
+		{Address: 0x400554, File: file1H, Line: 5, IsStmt: true, PrologueEnd: true},
+		{Address: 0x400568, File: file1H, Line: 6, IsStmt: true},
+		{Address: 0x400571, File: file1H, Line: 5, IsStmt: true},
+		{Address: 0x400581, File: file1H, Line: 7, IsStmt: true},
+		{Address: 0x400583, EndSequence: true},
+
+		{Address: 0x400590, File: file2C, Line: 4, IsStmt: true},
+		{Address: 0x4005a0, File: file2C, Line: 5, IsStmt: true, PrologueEnd: true},
+		{Address: 0x4005a7, File: file2C, Line: 6, IsStmt: true},
+		{Address: 0x4005b0, EndSequence: true},
+	}
+
+	testLineTable(t, want, elfData(t, "testdata/line-clang.elf"))
+}
+
+func TestLineSeek(t *testing.T) {
+	d := elfData(t, "testdata/line-gcc.elf")
+
+	// Get the line table for the first CU.
+	cu, err := d.Reader().Next()
+	if err != nil {
+		t.Fatal("d.Reader().Next:", err)
+	}
+	lr, err := d.LineReader(cu)
+	if err != nil {
+		t.Fatal("d.LineReader:", err)
+	}
+
+	// Read entries forward.
+	var line LineEntry
+	var posTable []LineReaderPos
+	var table []LineEntry
+	for {
+		posTable = append(posTable, lr.Tell())
+
+		err := lr.Next(&line)
+		if err != nil {
+			if err == io.EOF {
+				break
+			}
+			t.Fatal("lr.Next:", err)
+		}
+		table = append(table, line)
+	}
+
+	// Test that Reset returns to the first line.
+	lr.Reset()
+	if err := lr.Next(&line); err != nil {
+		t.Fatal("lr.Next after Reset failed:", err)
+	} else if line != table[0] {
+		t.Fatal("lr.Next after Reset returned", line, "instead of", table[0])
+	}
+
+	// Check that entries match when seeking backward.
+	for i := len(posTable) - 1; i >= 0; i-- {
+		lr.Seek(posTable[i])
+		err := lr.Next(&line)
+		if i == len(posTable)-1 {
+			if err != io.EOF {
+				t.Fatal("expected io.EOF after seek to end, got", err)
+			}
+		} else if err != nil {
+			t.Fatal("lr.Next after seek to", posTable[i], "failed:", err)
+		} else if line != table[i] {
+			t.Fatal("lr.Next after seek to", posTable[i], "returned", line, "instead of", table[i])
+		}
+	}
+
+	// Check that seeking to a PC returns the right line.
+	if err := lr.SeekPC(table[0].Address-1, &line); err != ErrUnknownPC {
+		t.Fatalf("lr.SeekPC to %#x returned %v instead of ErrUnknownPC", table[0].Address-1, err)
+	}
+	for i, testLine := range table {
+		if testLine.EndSequence {
+			if err := lr.SeekPC(testLine.Address, &line); err != ErrUnknownPC {
+				t.Fatalf("lr.SeekPC to %#x returned %v instead of ErrUnknownPC", testLine.Address, err)
+			}
+			continue
+		}
+
+		nextPC := table[i+1].Address
+		for pc := testLine.Address; pc < nextPC; pc++ {
+			if err := lr.SeekPC(pc, &line); err != nil {
+				t.Fatalf("lr.SeekPC to %#x failed: %v", pc, err)
+			} else if line != testLine {
+				t.Fatalf("lr.SeekPC to %#x returned %v instead of %v", pc, line, testLine)
+			}
+		}
+	}
+}
+
+func testLineTable(t *testing.T, want []LineEntry, d *Data) {
+	// Get line table from d.
+	var got []LineEntry
+	dr := d.Reader()
+	for {
+		ent, err := dr.Next()
+		if err != nil {
+			t.Fatal("dr.Next:", err)
+		} else if ent == nil {
+			break
+		}
+
+		if ent.Tag != TagCompileUnit {
+			dr.SkipChildren()
+			continue
+		}
+
+		// Decode CU's line table.
+		lr, err := d.LineReader(ent)
+		if err != nil {
+			t.Fatal("d.LineReader:", err)
+		} else if lr == nil {
+			continue
+		}
+
+		for {
+			var line LineEntry
+			err := lr.Next(&line)
+			if err != nil {
+				if err == io.EOF {
+					break
+				}
+				t.Fatal("lr.Next:", err)
+			}
+			got = append(got, line)
+		}
+	}
+
+	// Compare line tables.
+	if !compareLines(got, want) {
+		t.Log("Line tables do not match. Got:")
+		dumpLines(t, got)
+		t.Log("Want:")
+		dumpLines(t, want)
+		t.FailNow()
+	}
+}
+
+func compareLines(a, b []LineEntry) bool {
+	if len(a) != len(b) {
+		return false
+	}
+
+	for i := range a {
+		al, bl := a[i], b[i]
+		// If both are EndSequence, then the only other valid
+		// field is Address. Otherwise, test equality of all
+		// fields.
+		if al.EndSequence && bl.EndSequence && al.Address == bl.Address {
+			continue
+		}
+		if al.File.Name != bl.File.Name {
+			return false
+		}
+		al.File = nil
+		bl.File = nil
+		if al != bl {
+			return false
+		}
+	}
+	return true
+}
+
+func dumpLines(t *testing.T, lines []LineEntry) {
+	for _, l := range lines {
+		t.Logf("  %+v File:%+v", l, l.File)
+	}
+}
diff --git a/src/debug/dwarf/testdata/line-clang.elf b/src/debug/dwarf/testdata/line-clang.elf
new file mode 100755
index 0000000..b63cc78
--- /dev/null
+++ b/src/debug/dwarf/testdata/line-clang.elf
Binary files differ
diff --git a/src/debug/dwarf/testdata/line-gcc.elf b/src/debug/dwarf/testdata/line-gcc.elf
new file mode 100755
index 0000000..50500a8
--- /dev/null
+++ b/src/debug/dwarf/testdata/line-gcc.elf
Binary files differ
diff --git a/src/debug/dwarf/testdata/line1.c b/src/debug/dwarf/testdata/line1.c
new file mode 100644
index 0000000..f358647
--- /dev/null
+++ b/src/debug/dwarf/testdata/line1.c
@@ -0,0 +1,9 @@
+#include "line1.h"
+
+void f2();
+
+int main()
+{
+	f1();
+	f2();
+}
diff --git a/src/debug/dwarf/testdata/line1.h b/src/debug/dwarf/testdata/line1.h
new file mode 100644
index 0000000..974d4c8
--- /dev/null
+++ b/src/debug/dwarf/testdata/line1.h
@@ -0,0 +1,7 @@
+static void f1()
+{
+	char buf[10];
+	int i;
+	for(i = 0; i < 10; i++)
+		buf[i] = 1;
+}
diff --git a/src/debug/dwarf/testdata/line2.c b/src/debug/dwarf/testdata/line2.c
new file mode 100644
index 0000000..38d89983
--- /dev/null
+++ b/src/debug/dwarf/testdata/line2.c
@@ -0,0 +1,6 @@
+#include <stdio.h>
+
+void f2()
+{
+	printf("hello\n");
+}
diff --git a/src/debug/dwarf/typeunit.go b/src/debug/dwarf/typeunit.go
index 3fd1c99..80971bb 100644
--- a/src/debug/dwarf/typeunit.go
+++ b/src/debug/dwarf/typeunit.go
@@ -27,16 +27,10 @@
 	b := makeBuf(d, unknownFormat{}, name, 0, types)
 	for len(b.data) > 0 {
 		base := b.off
-		dwarf64 := false
-		n := b.uint32()
-		if n == 0xffffffff {
-			n64 := b.uint64()
-			if n64 != uint64(uint32(n64)) {
-				b.error("type unit length overflow")
-				return b.err
-			}
-			n = uint32(n64)
-			dwarf64 = true
+		n, dwarf64 := b.unitLength()
+		if n != Offset(uint32(n)) {
+			b.error("type unit length overflow")
+			return b.err
 		}
 		hdroff := b.off
 		vers := b.uint16()
@@ -79,7 +73,7 @@
 			unit: unit{
 				base:   base,
 				off:    boff,
-				data:   b.bytes(int(Offset(n) - (b.off - hdroff))),
+				data:   b.bytes(int(n - (b.off - hdroff))),
 				atable: atable,
 				asize:  int(asize),
 				vers:   int(vers),
diff --git a/src/debug/dwarf/unit.go b/src/debug/dwarf/unit.go
index 0fbc8e0..901ba0d 100644
--- a/src/debug/dwarf/unit.go
+++ b/src/debug/dwarf/unit.go
@@ -4,7 +4,10 @@
 
 package dwarf
 
-import "strconv"
+import (
+	"sort"
+	"strconv"
+)
 
 // DWARF debug info is split into a sequence of compilation units.
 // Each unit has its own abbreviation table and address size.
@@ -38,14 +41,10 @@
 	nunit := 0
 	b := makeBuf(d, unknownFormat{}, "info", 0, d.info)
 	for len(b.data) > 0 {
-		len := b.uint32()
-		if len == 0xffffffff {
-			len64 := b.uint64()
-			if len64 != uint64(uint32(len64)) {
-				b.error("unit length overflow")
-				break
-			}
-			len = uint32(len64)
+		len, _ := b.unitLength()
+		if len != Offset(uint32(len)) {
+			b.error("unit length overflow")
+			break
 		}
 		b.skip(int(len))
 		nunit++
@@ -60,11 +59,8 @@
 	for i := range units {
 		u := &units[i]
 		u.base = b.off
-		n := b.uint32()
-		if n == 0xffffffff {
-			u.is64 = true
-			n = uint32(b.uint64())
-		}
+		var n Offset
+		n, u.is64 = b.unitLength()
 		vers := b.uint16()
 		if vers != 2 && vers != 3 && vers != 4 {
 			b.error("unsupported DWARF version " + strconv.Itoa(int(vers)))
@@ -88,3 +84,20 @@
 	}
 	return units, nil
 }
+
+// offsetToUnit returns the index of the unit containing offset off.
+// It returns -1 if no unit contains this offset.
+func (d *Data) offsetToUnit(off Offset) int {
+	// Find the unit after off
+	next := sort.Search(len(d.unit), func(i int) bool {
+		return d.unit[i].off > off
+	})
+	if next == 0 {
+		return -1
+	}
+	u := &d.unit[next-1]
+	if u.off <= off && off < u.off+Offset(len(u.data)) {
+		return next - 1
+	}
+	return -1
+}
diff --git a/src/debug/elf/file.go b/src/debug/elf/file.go
index 74d1db3..8e02c8b 100644
--- a/src/debug/elf/file.go
+++ b/src/debug/elf/file.go
@@ -13,6 +13,7 @@
 	"fmt"
 	"io"
 	"os"
+	"strings"
 )
 
 // TODO: error reporting detail
@@ -523,20 +524,22 @@
 // applyRelocations applies relocations to dst. rels is a relocations section
 // in RELA format.
 func (f *File) applyRelocations(dst []byte, rels []byte) error {
-	if f.Class == ELFCLASS64 && f.Machine == EM_X86_64 {
+	switch {
+	case f.Class == ELFCLASS64 && f.Machine == EM_X86_64:
 		return f.applyRelocationsAMD64(dst, rels)
-	}
-	if f.Class == ELFCLASS32 && f.Machine == EM_386 {
+	case f.Class == ELFCLASS32 && f.Machine == EM_386:
 		return f.applyRelocations386(dst, rels)
-	}
-	if f.Class == ELFCLASS64 && f.Machine == EM_AARCH64 {
+	case f.Class == ELFCLASS32 && f.Machine == EM_ARM:
+		return f.applyRelocationsARM(dst, rels)
+	case f.Class == ELFCLASS64 && f.Machine == EM_AARCH64:
 		return f.applyRelocationsARM64(dst, rels)
-	}
-	if f.Class == ELFCLASS64 && f.Machine == EM_PPC64 {
+	case f.Class == ELFCLASS32 && f.Machine == EM_PPC:
+		return f.applyRelocationsPPC(dst, rels)
+	case f.Class == ELFCLASS64 && f.Machine == EM_PPC64:
 		return f.applyRelocationsPPC64(dst, rels)
+	default:
+		return errors.New("applyRelocations: not implemented")
 	}
-
-	return errors.New("not implemented")
 }
 
 func (f *File) applyRelocationsAMD64(dst []byte, rels []byte) error {
@@ -625,6 +628,44 @@
 	return nil
 }
 
+func (f *File) applyRelocationsARM(dst []byte, rels []byte) error {
+	// 8 is the size of Rel32.
+	if len(rels)%8 != 0 {
+		return errors.New("length of relocation section is not a multiple of 8")
+	}
+
+	symbols, _, err := f.getSymbols(SHT_SYMTAB)
+	if err != nil {
+		return err
+	}
+
+	b := bytes.NewReader(rels)
+	var rel Rel32
+
+	for b.Len() > 0 {
+		binary.Read(b, f.ByteOrder, &rel)
+		symNo := rel.Info >> 8
+		t := R_ARM(rel.Info & 0xff)
+
+		if symNo == 0 || symNo > uint32(len(symbols)) {
+			continue
+		}
+		sym := &symbols[symNo-1]
+
+		switch t {
+		case R_ARM_REL32:
+			if rel.Off+4 >= uint32(len(dst)) {
+				continue
+			}
+			val := f.ByteOrder.Uint32(dst[rel.Off : rel.Off+4])
+			val += uint32(sym.Value)
+			f.ByteOrder.PutUint32(dst[rel.Off:rel.Off+4], val)
+		}
+	}
+
+	return nil
+}
+
 func (f *File) applyRelocationsARM64(dst []byte, rels []byte) error {
 	// 24 is the size of Rela64.
 	if len(rels)%24 != 0 {
@@ -674,6 +715,46 @@
 	return nil
 }
 
+func (f *File) applyRelocationsPPC(dst []byte, rels []byte) error {
+	// 12 is the size of Rela32.
+	if len(rels)%12 != 0 {
+		return errors.New("length of relocation section is not a multiple of 12")
+	}
+
+	symbols, _, err := f.getSymbols(SHT_SYMTAB)
+	if err != nil {
+		return err
+	}
+
+	b := bytes.NewReader(rels)
+	var rela Rela32
+
+	for b.Len() > 0 {
+		binary.Read(b, f.ByteOrder, &rela)
+		symNo := rela.Info >> 8
+		t := R_PPC(rela.Info & 0xff)
+
+		if symNo == 0 || symNo > uint32(len(symbols)) {
+			continue
+		}
+		sym := &symbols[symNo-1]
+		if SymType(sym.Info&0xf) != STT_SECTION {
+			// We don't handle non-section relocations for now.
+			continue
+		}
+
+		switch t {
+		case R_PPC_ADDR32:
+			if rela.Off+4 >= uint32(len(dst)) || rela.Addend < 0 {
+				continue
+			}
+			f.ByteOrder.PutUint32(dst[rela.Off:rela.Off+4], uint32(rela.Addend))
+		}
+	}
+
+	return nil
+}
+
 func (f *File) applyRelocationsPPC64(dst []byte, rels []byte) error {
 	// 24 is the size of Rela64.
 	if len(rels)%24 != 0 {
@@ -720,53 +801,52 @@
 }
 
 func (f *File) DWARF() (*dwarf.Data, error) {
-	// There are many other DWARF sections, but these
-	// are the required ones, and the debug/dwarf package
-	// does not use the others, so don't bother loading them.
-	var names = [...]string{"abbrev", "info", "str"}
-	var dat [len(names)][]byte
-	for i, name := range names {
-		name = ".debug_" + name
-		s := f.Section(name)
-		if s == nil {
-			continue
-		}
+	// sectionData gets the data for s, checks its size, and
+	// applies any applicable relations.
+	sectionData := func(i int, s *Section) ([]byte, error) {
 		b, err := s.Data()
 		if err != nil && uint64(len(b)) < s.Size {
 			return nil, err
 		}
-		dat[i] = b
+
+		for _, r := range f.Sections {
+			if r.Type != SHT_RELA && r.Type != SHT_REL {
+				continue
+			}
+			if int(r.Info) != i {
+				continue
+			}
+			rd, err := r.Data()
+			if err != nil {
+				return nil, err
+			}
+			err = f.applyRelocations(b, rd)
+			if err != nil {
+				return nil, err
+			}
+		}
+		return b, nil
 	}
 
-	// If there's a relocation table for .debug_info, we have to process it
-	// now otherwise the data in .debug_info is invalid for x86-64 objects.
-	rela := f.Section(".rela.debug_info")
-	if rela != nil && rela.Type == SHT_RELA && (f.Machine == EM_X86_64 || f.Machine == EM_AARCH64 || f.Machine == EM_PPC64) {
-		data, err := rela.Data()
+	// There are many other DWARF sections, but these
+	// are the ones the debug/dwarf package uses.
+	// Don't bother loading others.
+	var dat = map[string][]byte{"abbrev": nil, "info": nil, "str": nil, "line": nil}
+	for i, s := range f.Sections {
+		if !strings.HasPrefix(s.Name, ".debug_") {
+			continue
+		}
+		if _, ok := dat[s.Name[7:]]; !ok {
+			continue
+		}
+		b, err := sectionData(i, s)
 		if err != nil {
 			return nil, err
 		}
-		err = f.applyRelocations(dat[1], data)
-		if err != nil {
-			return nil, err
-		}
+		dat[s.Name[7:]] = b
 	}
 
-	// When using clang we need to process relocations even for 386.
-	rel := f.Section(".rel.debug_info")
-	if rel != nil && rel.Type == SHT_REL && f.Machine == EM_386 {
-		data, err := rel.Data()
-		if err != nil {
-			return nil, err
-		}
-		err = f.applyRelocations(dat[1], data)
-		if err != nil {
-			return nil, err
-		}
-	}
-
-	abbrev, info, str := dat[0], dat[1], dat[2]
-	d, err := dwarf.New(abbrev, nil, nil, info, nil, nil, nil, str)
+	d, err := dwarf.New(dat["abbrev"], nil, nil, dat["info"], dat["line"], nil, nil, dat["str"])
 	if err != nil {
 		return nil, err
 	}
@@ -774,28 +854,11 @@
 	// Look for DWARF4 .debug_types sections.
 	for i, s := range f.Sections {
 		if s.Name == ".debug_types" {
-			b, err := s.Data()
-			if err != nil && uint64(len(b)) < s.Size {
+			b, err := sectionData(i, s)
+			if err != nil {
 				return nil, err
 			}
 
-			for _, r := range f.Sections {
-				if r.Type != SHT_RELA && r.Type != SHT_REL {
-					continue
-				}
-				if int(r.Info) != i {
-					continue
-				}
-				rd, err := r.Data()
-				if err != nil {
-					return nil, err
-				}
-				err = f.applyRelocations(b, rd)
-				if err != nil {
-					return nil, err
-				}
-			}
-
 			err = d.AddTypes(fmt.Sprintf("types-%d", i), b)
 			if err != nil {
 				return nil, err
diff --git a/src/debug/elf/file_test.go b/src/debug/elf/file_test.go
index d57aaab..0d10ec5 100644
--- a/src/debug/elf/file_test.go
+++ b/src/debug/elf/file_test.go
@@ -267,6 +267,18 @@
 		},
 	},
 	{
+		"testdata/go-relocation-test-gcc492-arm.obj",
+		[]relocationTestEntry{
+			{0, &dwarf.Entry{Offset: 0xb, Tag: dwarf.TagCompileUnit, Children: true, Field: []dwarf.Field{{Attr: dwarf.AttrProducer, Val: "GNU C 4.9.2 20141224 (prerelease) -march=armv7-a -mfloat-abi=hard -mfpu=vfpv3-d16 -mtls-dialect=gnu -g"}, {Attr: dwarf.AttrLanguage, Val: int64(1)}, {Attr: dwarf.AttrName, Val: "go-relocation-test-gcc492.c"}, {Attr: dwarf.AttrCompDir, Val: "/root/go/src/debug/elf/testdata"}, {Attr: dwarf.AttrLowpc, Val: uint64(0x0)}, {Attr: dwarf.AttrHighpc, Val: int64(0x28)}, {Attr: dwarf.AttrStmtList, Val: int64(0)}}}},
+		},
+	},
+	{
+		"testdata/go-relocation-test-gcc5-ppc.obj",
+		[]relocationTestEntry{
+			{0, &dwarf.Entry{Offset: 0xb, Tag: dwarf.TagCompileUnit, Children: true, Field: []dwarf.Field{dwarf.Field{Attr: dwarf.AttrProducer, Val: "GNU C11 5.0.0 20150116 (experimental) -Asystem=linux -Asystem=unix -Asystem=posix -g"}, dwarf.Field{Attr: dwarf.AttrLanguage, Val: int64(12)}, dwarf.Field{Attr: dwarf.AttrName, Val: "go-relocation-test-gcc5-ppc.c"}, dwarf.Field{Attr: dwarf.AttrCompDir, Val: "/tmp"}, dwarf.Field{Attr: dwarf.AttrLowpc, Val: uint64(0x0)}, dwarf.Field{Attr: dwarf.AttrHighpc, Val: int64(0x44)}, dwarf.Field{Attr: dwarf.AttrStmtList, Val: int64(0)}}}},
+		},
+	},
+	{
 		"testdata/go-relocation-test-gcc482-ppc64le.obj",
 		[]relocationTestEntry{
 			{0, &dwarf.Entry{Offset: 0xb, Tag: dwarf.TagCompileUnit, Children: true, Field: []dwarf.Field{dwarf.Field{Attr: dwarf.AttrProducer, Val: "GNU C 4.8.2 -Asystem=linux -Asystem=unix -Asystem=posix -msecure-plt -mtune=power8 -mcpu=power7 -gdwarf-2 -fstack-protector"}, dwarf.Field{Attr: dwarf.AttrLanguage, Val: int64(1)}, dwarf.Field{Attr: dwarf.AttrName, Val: "go-relocation-test-gcc482-ppc64le.c"}, dwarf.Field{Attr: dwarf.AttrCompDir, Val: "/tmp"}, dwarf.Field{Attr: dwarf.AttrLowpc, Val: uint64(0x0)}, dwarf.Field{Attr: dwarf.AttrHighpc, Val: uint64(0x24)}, dwarf.Field{Attr: dwarf.AttrStmtList, Val: int64(0)}}}},
diff --git a/src/debug/elf/testdata/go-relocation-test-gcc492-arm.obj b/src/debug/elf/testdata/go-relocation-test-gcc492-arm.obj
new file mode 100644
index 0000000..ed45be2
--- /dev/null
+++ b/src/debug/elf/testdata/go-relocation-test-gcc492-arm.obj
Binary files differ
diff --git a/src/debug/elf/testdata/go-relocation-test-gcc5-ppc.obj b/src/debug/elf/testdata/go-relocation-test-gcc5-ppc.obj
new file mode 100644
index 0000000..f4165af
--- /dev/null
+++ b/src/debug/elf/testdata/go-relocation-test-gcc5-ppc.obj
Binary files differ
diff --git a/src/debug/gosym/symtab.go b/src/debug/gosym/symtab.go
index ee18499..46f0783 100644
--- a/src/debug/gosym/symtab.go
+++ b/src/debug/gosym/symtab.go
@@ -30,7 +30,7 @@
 	Type   byte
 	Name   string
 	GoType uint64
-	// If this symbol if a function symbol, the corresponding Func
+	// If this symbol is a function symbol, the corresponding Func
 	Func *Func
 }
 
diff --git a/src/debug/macho/file.go b/src/debug/macho/file.go
index eefb744..a7599aa 100644
--- a/src/debug/macho/file.go
+++ b/src/debug/macho/file.go
@@ -472,9 +472,9 @@
 // DWARF returns the DWARF debug information for the Mach-O file.
 func (f *File) DWARF() (*dwarf.Data, error) {
 	// There are many other DWARF sections, but these
-	// are the required ones, and the debug/dwarf package
-	// does not use the others, so don't bother loading them.
-	var names = [...]string{"abbrev", "info", "str"}
+	// are the ones the debug/dwarf package uses.
+	// Don't bother loading others.
+	var names = [...]string{"abbrev", "info", "line", "str"}
 	var dat [len(names)][]byte
 	for i, name := range names {
 		name = "__debug_" + name
@@ -489,8 +489,8 @@
 		dat[i] = b
 	}
 
-	abbrev, info, str := dat[0], dat[1], dat[2]
-	return dwarf.New(abbrev, nil, nil, info, nil, nil, nil, str)
+	abbrev, info, line, str := dat[0], dat[1], dat[2], dat[3]
+	return dwarf.New(abbrev, nil, nil, info, line, nil, nil, str)
 }
 
 // ImportedSymbols returns the names of all symbols
diff --git a/src/debug/pe/file.go b/src/debug/pe/file.go
index 759e567..844dffc 100644
--- a/src/debug/pe/file.go
+++ b/src/debug/pe/file.go
@@ -296,9 +296,9 @@
 
 func (f *File) DWARF() (*dwarf.Data, error) {
 	// There are many other DWARF sections, but these
-	// are the required ones, and the debug/dwarf package
-	// does not use the others, so don't bother loading them.
-	var names = [...]string{"abbrev", "info", "str"}
+	// are the ones the debug/dwarf package uses.
+	// Don't bother loading others.
+	var names = [...]string{"abbrev", "info", "line", "str"}
 	var dat [len(names)][]byte
 	for i, name := range names {
 		name = ".debug_" + name
@@ -313,8 +313,8 @@
 		dat[i] = b
 	}
 
-	abbrev, info, str := dat[0], dat[1], dat[2]
-	return dwarf.New(abbrev, nil, nil, info, nil, nil, nil, str)
+	abbrev, info, line, str := dat[0], dat[1], dat[2], dat[3]
+	return dwarf.New(abbrev, nil, nil, info, line, nil, nil, str)
 }
 
 // ImportedSymbols returns the names of all symbols
diff --git a/src/encoding/asn1/asn1.go b/src/encoding/asn1/asn1.go
index 8b3d1b3..aa99ca5 100644
--- a/src/encoding/asn1/asn1.go
+++ b/src/encoding/asn1/asn1.go
@@ -320,7 +320,7 @@
 	return
 }
 
-// isPrintable returns true iff the given b is in the ASN.1 PrintableString set.
+// isPrintable reports whether the given b is in the ASN.1 PrintableString set.
 func isPrintable(b byte) bool {
 	return 'a' <= b && b <= 'z' ||
 		'A' <= b && b <= 'Z' ||
diff --git a/src/encoding/asn1/marshal.go b/src/encoding/asn1/marshal.go
index b2f104b..bf92c04 100644
--- a/src/encoding/asn1/marshal.go
+++ b/src/encoding/asn1/marshal.go
@@ -18,7 +18,7 @@
 // A forkableWriter is an in-memory buffer that can be
 // 'forked' to create new forkableWriters that bracket the
 // original.  After
-//    pre, post := w.fork();
+//    pre, post := w.fork()
 // the overall sequence of bytes represented is logically w+pre+post.
 type forkableWriter struct {
 	*bytes.Buffer
diff --git a/src/encoding/binary/binary.go b/src/encoding/binary/binary.go
index 3c37949..ac15fb7 100644
--- a/src/encoding/binary/binary.go
+++ b/src/encoding/binary/binary.go
@@ -239,78 +239,62 @@
 		}
 		switch v := data.(type) {
 		case *int8:
-			bs = b[:1]
 			b[0] = byte(*v)
 		case int8:
-			bs = b[:1]
 			b[0] = byte(v)
 		case []int8:
 			for i, x := range v {
 				bs[i] = byte(x)
 			}
 		case *uint8:
-			bs = b[:1]
 			b[0] = *v
 		case uint8:
-			bs = b[:1]
 			b[0] = byte(v)
 		case []uint8:
 			bs = v
 		case *int16:
-			bs = b[:2]
 			order.PutUint16(bs, uint16(*v))
 		case int16:
-			bs = b[:2]
 			order.PutUint16(bs, uint16(v))
 		case []int16:
 			for i, x := range v {
 				order.PutUint16(bs[2*i:], uint16(x))
 			}
 		case *uint16:
-			bs = b[:2]
 			order.PutUint16(bs, *v)
 		case uint16:
-			bs = b[:2]
 			order.PutUint16(bs, v)
 		case []uint16:
 			for i, x := range v {
 				order.PutUint16(bs[2*i:], x)
 			}
 		case *int32:
-			bs = b[:4]
 			order.PutUint32(bs, uint32(*v))
 		case int32:
-			bs = b[:4]
 			order.PutUint32(bs, uint32(v))
 		case []int32:
 			for i, x := range v {
 				order.PutUint32(bs[4*i:], uint32(x))
 			}
 		case *uint32:
-			bs = b[:4]
 			order.PutUint32(bs, *v)
 		case uint32:
-			bs = b[:4]
 			order.PutUint32(bs, v)
 		case []uint32:
 			for i, x := range v {
 				order.PutUint32(bs[4*i:], x)
 			}
 		case *int64:
-			bs = b[:8]
 			order.PutUint64(bs, uint64(*v))
 		case int64:
-			bs = b[:8]
 			order.PutUint64(bs, uint64(v))
 		case []int64:
 			for i, x := range v {
 				order.PutUint64(bs[8*i:], uint64(x))
 			}
 		case *uint64:
-			bs = b[:8]
 			order.PutUint64(bs, *v)
 		case uint64:
-			bs = b[:8]
 			order.PutUint64(bs, v)
 		case []uint64:
 			for i, x := range v {
diff --git a/src/encoding/csv/writer.go b/src/encoding/csv/writer.go
index 17e7bb7..db2dc79 100644
--- a/src/encoding/csv/writer.go
+++ b/src/encoding/csv/writer.go
@@ -114,7 +114,7 @@
 	return w.w.Flush()
 }
 
-// fieldNeedsQuotes returns true if our field must be enclosed in quotes.
+// fieldNeedsQuotes reports whether our field must be enclosed in quotes.
 // Fields with a Comma, fields with a quote or newline, and
 // fields which start with a space must be enclosed in quotes.
 // We used to quote empty strings, but we do not anymore (as of Go 1.4).
diff --git a/src/encoding/xml/marshal.go b/src/encoding/xml/marshal.go
index 9d6045c..a0e2058 100644
--- a/src/encoding/xml/marshal.go
+++ b/src/encoding/xml/marshal.go
@@ -1018,25 +1018,22 @@
 			}
 
 		case fElement, fElement | fAny:
-			if err := s.trim(finfo.parents); err != nil {
+			if err := s.setParents(finfo, vf); err != nil {
 				return err
 			}
-			if len(finfo.parents) > len(s.stack) {
-				if vf.Kind() != reflect.Ptr && vf.Kind() != reflect.Interface || !vf.IsNil() {
-					if err := s.push(finfo.parents[len(s.stack):]); err != nil {
-						return err
-					}
-				}
-			}
 		}
 		if err := p.marshalValue(vf, finfo, nil); err != nil {
 			return err
 		}
 	}
-	s.trim(nil)
+	if err := s.setParents(&noField, reflect.Value{}); err != nil {
+		return err
+	}
 	return p.cachedWriteError()
 }
 
+var noField fieldInfo
+
 // return the bufio Writer's cached write error
 func (p *printer) cachedWriteError() error {
 	_, err := p.Write(nil)
@@ -1075,37 +1072,64 @@
 }
 
 type parentStack struct {
-	p     *printer
-	stack []string
+	p       *printer
+	xmlns   string
+	parents []string
 }
 
-// trim updates the XML context to match the longest common prefix of the stack
-// and the given parents.  A closing tag will be written for every parent
-// popped.  Passing a zero slice or nil will close all the elements.
-func (s *parentStack) trim(parents []string) error {
-	split := 0
-	for ; split < len(parents) && split < len(s.stack); split++ {
-		if parents[split] != s.stack[split] {
-			break
+// setParents sets the stack of current parents to those found in finfo.
+// It only writes the start elements if vf holds a non-nil value.
+// If finfo is &noField, it pops all elements.
+func (s *parentStack) setParents(finfo *fieldInfo, vf reflect.Value) error {
+	xmlns := s.p.defaultNS
+	if finfo.xmlns != "" {
+		xmlns = finfo.xmlns
+	}
+	commonParents := 0
+	if xmlns == s.xmlns {
+		for ; commonParents < len(finfo.parents) && commonParents < len(s.parents); commonParents++ {
+			if finfo.parents[commonParents] != s.parents[commonParents] {
+				break
+			}
 		}
 	}
-	for i := len(s.stack) - 1; i >= split; i-- {
-		if err := s.p.writeEnd(Name{Local: s.stack[i]}); err != nil {
+	// Pop off any parents that aren't in common with the previous field.
+	for i := len(s.parents) - 1; i >= commonParents; i-- {
+		if err := s.p.writeEnd(Name{
+			Space: s.xmlns,
+			Local: s.parents[i],
+		}); err != nil {
 			return err
 		}
 	}
-	s.stack = parents[:split]
-	return nil
-}
-
-// push adds parent elements to the stack and writes open tags.
-func (s *parentStack) push(parents []string) error {
-	for i := 0; i < len(parents); i++ {
-		if err := s.p.writeStart(&StartElement{Name: Name{Local: parents[i]}}); err != nil {
+	s.parents = finfo.parents
+	s.xmlns = xmlns
+	if commonParents >= len(s.parents) {
+		// No new elements to push.
+		return nil
+	}
+	if (vf.Kind() == reflect.Ptr || vf.Kind() == reflect.Interface) && vf.IsNil() {
+		// The element is nil, so no need for the start elements.
+		s.parents = s.parents[:commonParents]
+		return nil
+	}
+	// Push any new parents required.
+	for _, name := range s.parents[commonParents:] {
+		start := &StartElement{
+			Name: Name{
+				Space: s.xmlns,
+				Local: name,
+			},
+		}
+		// Set the default name space for parent elements
+		// to match what we do with other elements.
+		if s.xmlns != s.p.defaultNS {
+			start.setDefaultNamespace()
+		}
+		if err := s.p.writeStart(start); err != nil {
 			return err
 		}
 	}
-	s.stack = append(s.stack, parents...)
 	return nil
 }
 
diff --git a/src/encoding/xml/marshal_test.go b/src/encoding/xml/marshal_test.go
index 7410a81..8362421 100644
--- a/src/encoding/xml/marshal_test.go
+++ b/src/encoding/xml/marshal_test.go
@@ -12,6 +12,7 @@
 	"reflect"
 	"strconv"
 	"strings"
+	"sync"
 	"testing"
 	"time"
 )
@@ -625,17 +626,23 @@
 			C       string   `xml:"space x>c"`
 			C1      string   `xml:"space1 x>c"`
 			D1      string   `xml:"space1 x>d"`
+			E1      string   `xml:"x>e"`
 		}{
 			A:  "a",
 			B:  "b",
 			C:  "c",
 			C1: "c1",
 			D1: "d1",
+			E1: "e1",
 		},
 		ExpectXML: `<top xmlns="space">` +
-			`<x xmlns=""><a>a</a><b>b</b><c xmlns="space">c</c>` +
-			`<c xmlns="space1">c1</c>` +
-			`<d xmlns="space1">d1</d>` +
+			`<x><a>a</a><b>b</b><c>c</c></x>` +
+			`<x xmlns="space1">` +
+			`<c>c1</c>` +
+			`<d>d1</d>` +
+			`</x>` +
+			`<x>` +
+			`<e>e1</e>` +
 			`</x>` +
 			`</top>`,
 	},
@@ -659,10 +666,11 @@
 			D1: "d1",
 		},
 		ExpectXML: `<top xmlns="space0">` +
-			`<x xmlns=""><a>a</a><b>b</b>` +
-			`<c xmlns="space">c</c>` +
-			`<c xmlns="space1">c1</c>` +
-			`<d xmlns="space1">d1</d>` +
+			`<x><a>a</a><b>b</b></x>` +
+			`<x xmlns="space"><c>c</c></x>` +
+			`<x xmlns="space1">` +
+			`<c>c1</c>` +
+			`<d>d1</d>` +
 			`</x>` +
 			`</top>`,
 	},
@@ -676,8 +684,8 @@
 			B1: "b1",
 		},
 		ExpectXML: `<top>` +
-			`<x><b xmlns="space">b</b>` +
-			`<b xmlns="space1">b1</b></x>` +
+			`<x xmlns="space"><b>b</b></x>` +
+			`<x xmlns="space1"><b>b1</b></x>` +
 			`</top>`,
 	},
 
@@ -1100,15 +1108,6 @@
 		if _, ok := test.Value.(*Plain); ok {
 			continue
 		}
-		if test.ExpectXML == `<top>`+
-			`<x><b xmlns="space">b</b>`+
-			`<b xmlns="space1">b1</b></x>`+
-			`</top>` {
-			// TODO(rogpeppe): re-enable this test in
-			// https://go-review.googlesource.com/#/c/5910/
-			continue
-		}
-
 		vt := reflect.TypeOf(test.Value)
 		dest := reflect.New(vt.Elem()).Interface()
 		err := Unmarshal([]byte(test.ExpectXML), dest)
@@ -1659,3 +1658,20 @@
 		}
 	}
 }
+
+// Issue 9796. Used to fail with GORACE="halt_on_error=1" -race.
+func TestRace9796(t *testing.T) {
+	type A struct{}
+	type B struct {
+		C []A `xml:"X>Y"`
+	}
+	var wg sync.WaitGroup
+	for i := 0; i < 2; i++ {
+		wg.Add(1)
+		go func() {
+			Marshal(B{[]A{A{}}})
+			wg.Done()
+		}()
+	}
+	wg.Wait()
+}
diff --git a/src/encoding/xml/typeinfo.go b/src/encoding/xml/typeinfo.go
index 22248d2..c9a6421 100644
--- a/src/encoding/xml/typeinfo.go
+++ b/src/encoding/xml/typeinfo.go
@@ -194,6 +194,14 @@
 		return finfo, nil
 	}
 
+	if finfo.xmlns == "" && finfo.flags&fAttr == 0 {
+		// If it's an element no namespace specified, get the default
+		// from the XMLName of enclosing struct if possible.
+		if xmlname := lookupXMLName(typ); xmlname != nil {
+			finfo.xmlns = xmlname.xmlns
+		}
+	}
+
 	// Prepare field name and parents.
 	parents := strings.Split(tag, ">")
 	if parents[0] == "" {
diff --git a/src/flag/flag.go b/src/flag/flag.go
index 8c0e402..4e42790 100644
--- a/src/flag/flag.go
+++ b/src/flag/flag.go
@@ -373,20 +373,110 @@
 	return CommandLine.Set(name, value)
 }
 
-// PrintDefaults prints, to standard error unless configured
-// otherwise, the default values of all defined flags in the set.
+// isZeroValue guesses whether the string represents the zero
+// value for a flag. It is not accurate but in practice works OK.
+func isZeroValue(value string) bool {
+	switch value {
+	case "false":
+		return true
+	case "":
+		return true
+	case "0":
+		return true
+	}
+	return false
+}
+
+// UnquoteUsage extracts a back-quoted name from the usage
+// string for a flag and returns it and the un-quoted usage.
+// Given "a `name` to show" it returns ("name", "a name to show").
+// If there are no back quotes, the name is an educated guess of the
+// type of the flag's value, or the empty string if the flag is boolean.
+func UnquoteUsage(flag *Flag) (name string, usage string) {
+	// Look for a back-quoted name, but avoid the strings package.
+	usage = flag.Usage
+	for i := 0; i < len(usage); i++ {
+		if usage[i] == '`' {
+			for j := i + 1; j < len(usage); j++ {
+				if usage[j] == '`' {
+					name = usage[i+1 : j]
+					usage = usage[:i] + name + usage[j+1:]
+					return name, usage
+				}
+			}
+			break // Only one back quote; use type name.
+		}
+	}
+	// No explicit name, so use type if we can find one.
+	name = "value"
+	switch flag.Value.(type) {
+	case boolFlag:
+		name = ""
+	case *durationValue:
+		name = "duration"
+	case *float64Value:
+		name = "float"
+	case *intValue, *int64Value:
+		name = "int"
+	case *stringValue:
+		name = "string"
+	case *uintValue, *uint64Value:
+		name = "uint"
+	}
+	return
+}
+
+// PrintDefaults prints to standard error the default values of all
+// defined command-line flags in the set. See the documentation for
+// the global function PrintDefaults for more information.
 func (f *FlagSet) PrintDefaults() {
 	f.VisitAll(func(flag *Flag) {
-		format := "  -%s=%s: %s\n"
-		if _, ok := flag.Value.(*stringValue); ok {
-			// put quotes on the value
-			format = "  -%s=%q: %s\n"
+		s := fmt.Sprintf("  -%s", flag.Name) // Two spaces before -; see next two comments.
+		name, usage := UnquoteUsage(flag)
+		if len(name) > 0 {
+			s += " " + name
 		}
-		fmt.Fprintf(f.out(), format, flag.Name, flag.DefValue, flag.Usage)
+		// Boolean flags of one ASCII letter are so common we
+		// treat them specially, putting their usage on the same line.
+		if len(s) <= 4 { // space, space, '-', 'x'.
+			s += "\t"
+		} else {
+			// Four spaces before the tab triggers good alignment
+			// for both 4- and 8-space tab stops.
+			s += "\n    \t"
+		}
+		s += usage
+		if !isZeroValue(flag.DefValue) {
+			if _, ok := flag.Value.(*stringValue); ok {
+				// put quotes on the value
+				s += fmt.Sprintf(" (default %q)", flag.DefValue)
+			} else {
+				s += fmt.Sprintf(" (default %v)", flag.DefValue)
+			}
+		}
+		fmt.Fprint(f.out(), s, "\n")
 	})
 }
 
-// PrintDefaults prints to standard error the default values of all defined command-line flags.
+// PrintDefaults prints, to standard error unless configured otherwise,
+// a usage message showing the default settings of all defined
+// command-line flags.
+// For an integer valued flag x, the default output has the form
+//	-x int
+//		usage-message-for-x (default 7)
+// The usage message will appear on a separate line for anything but
+// a bool flag with a one-byte name. For bool flags, the type is
+// omitted and if the flag name is one byte the usage message appears
+// on the same line. The parenthetical default is omitted if the
+// default is the zero value for the type. The listed type, here int,
+// can be changed by placing a back-quoted name in the flag's usage
+// string; the first such item in the message is taken to be a parameter
+// name to show in the message and the back quotes are stripped from
+// the message when displayed. For instance, given
+//	flag.String("I", "", "search `directory` for include files")
+// the output will be
+//	-I directory
+//		search directory for include files.
 func PrintDefaults() {
 	CommandLine.PrintDefaults()
 }
@@ -408,6 +498,8 @@
 // Usage prints to standard error a usage message documenting all defined command-line flags.
 // It is called when an error occurs while parsing flags.
 // The function is a variable that may be changed to point to a custom function.
+// By default it prints a simple header and calls PrintDefaults; for details about the
+// format of the output and how to control it, see the documentation for PrintDefaults.
 var Usage = func() {
 	fmt.Fprintf(os.Stderr, "Usage of %s:\n", os.Args[0])
 	PrintDefaults()
@@ -831,7 +923,7 @@
 	CommandLine.Parse(os.Args[1:])
 }
 
-// Parsed returns true if the command-line flags have been parsed.
+// Parsed reports whether the command-line flags have been parsed.
 func Parsed() bool {
 	return CommandLine.Parsed()
 }
diff --git a/src/flag/flag_test.go b/src/flag/flag_test.go
index 8c88c8c..e2319ec 100644
--- a/src/flag/flag_test.go
+++ b/src/flag/flag_test.go
@@ -377,3 +377,41 @@
 		t.Fatal("help was called; should not have been for defined help flag")
 	}
 }
+
+const defaultOutput = `  -A	for bootstrapping, allow 'any' type
+  -Alongflagname
+    	disable bounds checking
+  -C	a boolean defaulting to true (default true)
+  -D path
+    	set relative path for local imports
+  -F number
+    	a non-zero number (default 2.7)
+  -G float
+    	a float that defaults to zero
+  -N int
+    	a non-zero int (default 27)
+  -Z int
+    	an int that defaults to zero
+  -maxT timeout
+    	set timeout for dial
+`
+
+func TestPrintDefaults(t *testing.T) {
+	fs := NewFlagSet("print defaults test", ContinueOnError)
+	var buf bytes.Buffer
+	fs.SetOutput(&buf)
+	fs.Bool("A", false, "for bootstrapping, allow 'any' type")
+	fs.Bool("Alongflagname", false, "disable bounds checking")
+	fs.Bool("C", true, "a boolean defaulting to true")
+	fs.String("D", "", "set relative `path` for local imports")
+	fs.Float64("F", 2.7, "a non-zero `number`")
+	fs.Float64("G", 0, "a float that defaults to zero")
+	fs.Int("N", 27, "a non-zero int")
+	fs.Int("Z", 0, "an int that defaults to zero")
+	fs.Duration("maxT", 0, "set `timeout` for dial")
+	fs.PrintDefaults()
+	got := buf.String()
+	if got != defaultOutput {
+		t.Errorf("got %q want %q\n", got, defaultOutput)
+	}
+}
diff --git a/src/fmt/fmt_test.go b/src/fmt/fmt_test.go
index d7161c2..c14bd2f 100644
--- a/src/fmt/fmt_test.go
+++ b/src/fmt/fmt_test.go
@@ -135,27 +135,33 @@
 
 	// basic string
 	{"%s", "abc", "abc"},
+	{"%q", "abc", `"abc"`},
 	{"%x", "abc", "616263"},
+	{"%x", "\xff\xf0\x0f\xff", "fff00fff"},
+	{"%X", "\xff\xf0\x0f\xff", "FFF00FFF"},
 	{"%x", "xyz", "78797a"},
 	{"%X", "xyz", "78797A"},
-	{"%q", "abc", `"abc"`},
-	{"%#x", []byte("abc\xff"), "0x616263ff"},
-	{"%#X", []byte("abc\xff"), "0X616263FF"},
-	{"%# x", []byte("abc\xff"), "0x61 0x62 0x63 0xff"},
-	{"%# X", []byte("abc\xff"), "0X61 0X62 0X63 0XFF"},
+	{"% x", "xyz", "78 79 7a"},
+	{"% X", "xyz", "78 79 7A"},
+	{"%#x", "xyz", "0x78797a"},
+	{"%#X", "xyz", "0X78797A"},
+	{"%# x", "xyz", "0x78 0x79 0x7a"},
+	{"%# X", "xyz", "0X78 0X79 0X7A"},
 
 	// basic bytes
 	{"%s", []byte("abc"), "abc"},
+	{"%q", []byte("abc"), `"abc"`},
 	{"%x", []byte("abc"), "616263"},
-	{"% x", []byte("abc\xff"), "61 62 63 ff"},
-	{"%#x", []byte("abc\xff"), "0x616263ff"},
-	{"%#X", []byte("abc\xff"), "0X616263FF"},
-	{"%# x", []byte("abc\xff"), "0x61 0x62 0x63 0xff"},
-	{"%# X", []byte("abc\xff"), "0X61 0X62 0X63 0XFF"},
-	{"% X", []byte("abc\xff"), "61 62 63 FF"},
+	{"%x", []byte("\xff\xf0\x0f\xff"), "fff00fff"},
+	{"%X", []byte("\xff\xf0\x0f\xff"), "FFF00FFF"},
 	{"%x", []byte("xyz"), "78797a"},
 	{"%X", []byte("xyz"), "78797A"},
-	{"%q", []byte("abc"), `"abc"`},
+	{"% x", []byte("xyz"), "78 79 7a"},
+	{"% X", []byte("xyz"), "78 79 7A"},
+	{"%#x", []byte("xyz"), "0x78797a"},
+	{"%#X", []byte("xyz"), "0X78797A"},
+	{"%# x", []byte("xyz"), "0x78 0x79 0x7a"},
+	{"%# X", []byte("xyz"), "0X78 0X79 0X7A"},
 
 	// escaped strings
 	{"%#q", `abc`, "`abc`"},
diff --git a/src/go/ast/ast.go b/src/go/ast/ast.go
index d21390e..5ab4283 100644
--- a/src/go/ast/ast.go
+++ b/src/go/ast/ast.go
@@ -486,7 +486,7 @@
 func (x *ChanType) End() token.Pos      { return x.Value.End() }
 
 // exprNode() ensures that only expression/type nodes can be
-// assigned to an ExprNode.
+// assigned to an Expr.
 //
 func (*BadExpr) exprNode()        {}
 func (*Ident) exprNode()          {}
@@ -787,7 +787,7 @@
 func (s *RangeStmt) End() token.Pos  { return s.Body.End() }
 
 // stmtNode() ensures that only statement nodes can be
-// assigned to a StmtNode.
+// assigned to a Stmt.
 //
 func (*BadStmt) stmtNode()        {}
 func (*DeclStmt) stmtNode()       {}
@@ -951,7 +951,7 @@
 }
 
 // declNode() ensures that only declaration nodes can be
-// assigned to a DeclNode.
+// assigned to a Decl.
 //
 func (*BadDecl) declNode()  {}
 func (*GenDecl) declNode()  {}
diff --git a/src/go/ast/filter.go b/src/go/ast/filter.go
index 50e576e..bb57116 100644
--- a/src/go/ast/filter.go
+++ b/src/go/ast/filter.go
@@ -23,8 +23,7 @@
 // body) are removed. Non-exported fields and methods of exported types are
 // stripped. The File.Comments list is not changed.
 //
-// FileExports returns true if there are exported declarations;
-// it returns false otherwise.
+// FileExports reports whether there are exported declarations.
 //
 func FileExports(src *File) bool {
 	return filterFile(src, exportFilter, true)
@@ -34,7 +33,7 @@
 // only exported nodes remain. The pkg.Files list is not changed, so that
 // file names and top-level package comments don't get lost.
 //
-// PackageExports returns true if there are exported declarations;
+// PackageExports reports whether there are exported declarations;
 // it returns false otherwise.
 //
 func PackageExports(pkg *Package) bool {
@@ -199,8 +198,8 @@
 // all names (including struct field and interface method names, but
 // not from parameter lists) that don't pass through the filter f.
 //
-// FilterDecl returns true if there are any declared names left after
-// filtering; it returns false otherwise.
+// FilterDecl reports whether there are any declared names left after
+// filtering.
 //
 func FilterDecl(decl Decl, f Filter) bool {
 	return filterDecl(decl, f, false)
@@ -224,8 +223,8 @@
 // the declaration is removed from the AST. Import declarations are
 // always removed. The File.Comments list is not changed.
 //
-// FilterFile returns true if there are any top-level declarations
-// left after filtering; it returns false otherwise.
+// FilterFile reports whether there are any top-level declarations
+// left after filtering.
 //
 func FilterFile(src *File, f Filter) bool {
 	return filterFile(src, f, false)
@@ -251,8 +250,8 @@
 // changed, so that file names and top-level package comments don't get
 // lost.
 //
-// FilterPackage returns true if there are any top-level declarations
-// left after filtering; it returns false otherwise.
+// FilterPackage reports whether there are any top-level declarations
+// left after filtering.
 //
 func FilterPackage(pkg *Package, f Filter) bool {
 	return filterPackage(pkg, f, false)
diff --git a/src/go/ast/scope.go b/src/go/ast/scope.go
index df1529d..1ce5e2e 100644
--- a/src/go/ast/scope.go
+++ b/src/go/ast/scope.go
@@ -38,7 +38,7 @@
 // Insert attempts to insert a named object obj into the scope s.
 // If the scope already contains an object alt with the same name,
 // Insert leaves the scope unchanged and returns alt. Otherwise
-// it inserts obj and returns nil."
+// it inserts obj and returns nil.
 //
 func (s *Scope) Insert(obj *Object) (alt *Object) {
 	if alt = s.Objects[obj.Name]; alt == nil {
diff --git a/src/go/build/build.go b/src/go/build/build.go
index 6e95e48..b590105 100644
--- a/src/go/build/build.go
+++ b/src/go/build/build.go
@@ -259,11 +259,9 @@
 var cgoEnabled = map[string]bool{
 	"darwin/386":      true,
 	"darwin/amd64":    true,
-	"dragonfly/386":   true,
 	"dragonfly/amd64": true,
 	"freebsd/386":     true,
 	"freebsd/amd64":   true,
-	"freebsd/arm":     true,
 	"linux/386":       true,
 	"linux/amd64":     true,
 	"linux/arm":       true,
@@ -1230,7 +1228,7 @@
 	return args, err
 }
 
-// match returns true if the name is one of:
+// match reports whether the name is one of:
 //
 //	$GOOS
 //	$GOARCH
@@ -1398,6 +1396,8 @@
 		return "6", nil
 	case "arm":
 		return "5", nil
+	case "arm64":
+		return "7", nil
 	case "ppc64", "ppc64le":
 		return "9", nil
 	}
diff --git a/src/go/build/build_test.go b/src/go/build/build_test.go
index 3985638..cc51174 100644
--- a/src/go/build/build_test.go
+++ b/src/go/build/build_test.go
@@ -109,6 +109,10 @@
 }
 
 func TestLocalDirectory(t *testing.T) {
+	if runtime.GOOS == "darwin" && runtime.GOARCH == "arm" {
+		t.Skipf("skipping on %s/%s, no valid GOROOT", runtime.GOOS, runtime.GOARCH)
+	}
+
 	cwd, err := os.Getwd()
 	if err != nil {
 		t.Fatal(err)
@@ -223,6 +227,10 @@
 }
 
 func TestImportCmd(t *testing.T) {
+	if runtime.GOOS == "darwin" && runtime.GOARCH == "arm" {
+		t.Skipf("skipping on %s/%s, no valid GOROOT", runtime.GOOS, runtime.GOARCH)
+	}
+
 	p, err := Import("cmd/internal/objfile", "", 0)
 	if err != nil {
 		t.Fatal(err)
diff --git a/src/go/build/deps_test.go b/src/go/build/deps_test.go
index 17f5282..5719ffc 100644
--- a/src/go/build/deps_test.go
+++ b/src/go/build/deps_test.go
@@ -207,9 +207,9 @@
 	"flag":                {"L4", "OS"},
 	"go/build":            {"L4", "OS", "GOPARSER"},
 	"html":                {"L4"},
-	"image/draw":          {"L4"},
+	"image/draw":          {"L4", "image/internal/imageutil"},
 	"image/gif":           {"L4", "compress/lzw", "image/color/palette", "image/draw"},
-	"image/jpeg":          {"L4"},
+	"image/jpeg":          {"L4", "image/internal/imageutil"},
 	"image/png":           {"L4", "compress/zlib"},
 	"index/suffixarray":   {"L4", "regexp"},
 	"math/big":            {"L4"},
diff --git a/src/go/build/doc.go b/src/go/build/doc.go
index 75a827b..78e17b2 100644
--- a/src/go/build/doc.go
+++ b/src/go/build/doc.go
@@ -111,7 +111,7 @@
 // (example: source_windows_amd64.go) where GOOS and GOARCH represent
 // any known operating system and architecture values respectively, then
 // the file is considered to have an implicit build constraint requiring
-// those terms.
+// those terms (in addition to any explicit constraints in the file).
 //
 // To keep a file from being considered for the build:
 //
diff --git a/src/go/build/syslist.go b/src/go/build/syslist.go
index 9246cbf..e84a066 100644
--- a/src/go/build/syslist.go
+++ b/src/go/build/syslist.go
@@ -5,4 +5,4 @@
 package build
 
 const goosList = "android darwin dragonfly freebsd linux nacl netbsd openbsd plan9 solaris windows "
-const goarchList = "386 amd64 amd64p32 arm ppc64 ppc64le "
+const goarchList = "386 amd64 amd64p32 arm arm64 ppc64 ppc64le "
diff --git a/src/go/doc/exports.go b/src/go/doc/exports.go
index 6aa38f1..4a12b1e 100644
--- a/src/go/doc/exports.go
+++ b/src/go/doc/exports.go
@@ -63,7 +63,7 @@
 }
 
 // filterFieldList removes unexported fields (field names) from the field list
-// in place and returns true if fields were removed. Anonymous fields are
+// in place and reports whether fields were removed. Anonymous fields are
 // recorded with the parent type. filterType is called with the types of
 // all remaining fields.
 //
diff --git a/src/go/format/format.go b/src/go/format/format.go
index 668a42d..1adfd7d 100644
--- a/src/go/format/format.go
+++ b/src/go/format/format.go
@@ -12,8 +12,8 @@
 	"go/parser"
 	"go/printer"
 	"go/token"
+	"internal/format"
 	"io"
-	"strings"
 )
 
 var config = printer.Config{Mode: printer.UseSpaces | printer.TabIndent, Tabwidth: 8}
@@ -82,7 +82,7 @@
 //
 func Source(src []byte) ([]byte, error) {
 	fset := token.NewFileSet()
-	file, sourceAdj, indentAdj, err := parse(fset, "", src, true)
+	file, sourceAdj, indentAdj, err := format.Parse(fset, "", src, true)
 	if err != nil {
 		return nil, err
 	}
@@ -93,7 +93,7 @@
 		ast.SortImports(fset, file)
 	}
 
-	return format(fset, file, sourceAdj, indentAdj, src, config)
+	return format.Format(fset, file, sourceAdj, indentAdj, src, config)
 }
 
 func hasUnsortedImports(file *ast.File) bool {
@@ -113,154 +113,3 @@
 	}
 	return false
 }
-
-// ----------------------------------------------------------------------------
-// Support functions
-//
-// The functions parse, format, and isSpace below are identical to the
-// respective functions in cmd/gofmt/gofmt.go - keep them in sync!
-//
-// TODO(gri) Factor out this functionality, eventually.
-
-// parse parses src, which was read from the named file,
-// as a Go source file, declaration, or statement list.
-func parse(fset *token.FileSet, filename string, src []byte, fragmentOk bool) (
-	file *ast.File,
-	sourceAdj func(src []byte, indent int) []byte,
-	indentAdj int,
-	err error,
-) {
-	// Try as whole source file.
-	file, err = parser.ParseFile(fset, filename, src, parserMode)
-	// If there's no error, return.  If the error is that the source file didn't begin with a
-	// package line and source fragments are ok, fall through to
-	// try as a source fragment.  Stop and return on any other error.
-	if err == nil || !fragmentOk || !strings.Contains(err.Error(), "expected 'package'") {
-		return
-	}
-
-	// If this is a declaration list, make it a source file
-	// by inserting a package clause.
-	// Insert using a ;, not a newline, so that the line numbers
-	// in psrc match the ones in src.
-	psrc := append([]byte("package p;"), src...)
-	file, err = parser.ParseFile(fset, filename, psrc, parserMode)
-	if err == nil {
-		sourceAdj = func(src []byte, indent int) []byte {
-			// Remove the package clause.
-			// Gofmt has turned the ; into a \n.
-			src = src[indent+len("package p\n"):]
-			return bytes.TrimSpace(src)
-		}
-		return
-	}
-	// If the error is that the source file didn't begin with a
-	// declaration, fall through to try as a statement list.
-	// Stop and return on any other error.
-	if !strings.Contains(err.Error(), "expected declaration") {
-		return
-	}
-
-	// If this is a statement list, make it a source file
-	// by inserting a package clause and turning the list
-	// into a function body.  This handles expressions too.
-	// Insert using a ;, not a newline, so that the line numbers
-	// in fsrc match the ones in src.
-	fsrc := append(append([]byte("package p; func _() {"), src...), '\n', '}')
-	file, err = parser.ParseFile(fset, filename, fsrc, parserMode)
-	if err == nil {
-		sourceAdj = func(src []byte, indent int) []byte {
-			// Cap adjusted indent to zero.
-			if indent < 0 {
-				indent = 0
-			}
-			// Remove the wrapping.
-			// Gofmt has turned the ; into a \n\n.
-			// There will be two non-blank lines with indent, hence 2*indent.
-			src = src[2*indent+len("package p\n\nfunc _() {"):]
-			src = src[:len(src)-(indent+len("\n}\n"))]
-			return bytes.TrimSpace(src)
-		}
-		// Gofmt has also indented the function body one level.
-		// Adjust that with indentAdj.
-		indentAdj = -1
-	}
-
-	// Succeeded, or out of options.
-	return
-}
-
-// format formats the given package file originally obtained from src
-// and adjusts the result based on the original source via sourceAdj
-// and indentAdj.
-func format(
-	fset *token.FileSet,
-	file *ast.File,
-	sourceAdj func(src []byte, indent int) []byte,
-	indentAdj int,
-	src []byte,
-	cfg printer.Config,
-) ([]byte, error) {
-	if sourceAdj == nil {
-		// Complete source file.
-		var buf bytes.Buffer
-		err := cfg.Fprint(&buf, fset, file)
-		if err != nil {
-			return nil, err
-		}
-		return buf.Bytes(), nil
-	}
-
-	// Partial source file.
-	// Determine and prepend leading space.
-	i, j := 0, 0
-	for j < len(src) && isSpace(src[j]) {
-		if src[j] == '\n' {
-			i = j + 1 // byte offset of last line in leading space
-		}
-		j++
-	}
-	var res []byte
-	res = append(res, src[:i]...)
-
-	// Determine and prepend indentation of first code line.
-	// Spaces are ignored unless there are no tabs,
-	// in which case spaces count as one tab.
-	indent := 0
-	hasSpace := false
-	for _, b := range src[i:j] {
-		switch b {
-		case ' ':
-			hasSpace = true
-		case '\t':
-			indent++
-		}
-	}
-	if indent == 0 && hasSpace {
-		indent = 1
-	}
-	for i := 0; i < indent; i++ {
-		res = append(res, '\t')
-	}
-
-	// Format the source.
-	// Write it without any leading and trailing space.
-	cfg.Indent = indent + indentAdj
-	var buf bytes.Buffer
-	err := cfg.Fprint(&buf, fset, file)
-	if err != nil {
-		return nil, err
-	}
-	res = append(res, sourceAdj(buf.Bytes(), cfg.Indent)...)
-
-	// Determine and append trailing space.
-	i = len(src)
-	for i > 0 && isSpace(src[i-1]) {
-		i--
-	}
-	return append(res, src[i:]...), nil
-}
-
-func isSpace(b byte) bool {
-	return b == ' ' || b == '\t' || b == '\n' || b == '\r'
-}
diff --git a/src/go/parser/parser.go b/src/go/parser/parser.go
index d1b766c..0095d7f 100644
--- a/src/go/parser/parser.go
+++ b/src/go/parser/parser.go
@@ -1259,7 +1259,7 @@
 	return &ast.CallExpr{Fun: fun, Lparen: lparen, Args: list, Ellipsis: ellipsis, Rparen: rparen}
 }
 
-func (p *parser) parseElement(keyOk bool) ast.Expr {
+func (p *parser) parseValue(keyOk bool) ast.Expr {
 	if p.trace {
 		defer un(trace(p, "Element"))
 	}
@@ -1287,16 +1287,30 @@
 	x := p.checkExpr(p.parseExpr(keyOk))
 	if keyOk {
 		if p.tok == token.COLON {
-			colon := p.pos
-			p.next()
 			// Try to resolve the key but don't collect it
 			// as unresolved identifier if it fails so that
 			// we don't get (possibly false) errors about
 			// undeclared names.
 			p.tryResolve(x, false)
-			return &ast.KeyValueExpr{Key: x, Colon: colon, Value: p.parseElement(false)}
+		} else {
+			// not a key
+			p.resolve(x)
 		}
-		p.resolve(x) // not a key
+	}
+
+	return x
+}
+
+func (p *parser) parseElement() ast.Expr {
+	if p.trace {
+		defer un(trace(p, "Element"))
+	}
+
+	x := p.parseValue(true)
+	if p.tok == token.COLON {
+		colon := p.pos
+		p.next()
+		x = &ast.KeyValueExpr{Key: x, Colon: colon, Value: p.parseValue(false)}
 	}
 
 	return x
@@ -1308,7 +1322,7 @@
 	}
 
 	for p.tok != token.RBRACE && p.tok != token.EOF {
-		list = append(list, p.parseElement(true))
+		list = append(list, p.parseElement())
 		if !p.atComma("composite literal") {
 			break
 		}
@@ -1365,7 +1379,7 @@
 	return x
 }
 
-// isTypeName returns true iff x is a (qualified) TypeName.
+// isTypeName reports whether x is a (qualified) TypeName.
 func isTypeName(x ast.Expr) bool {
 	switch t := x.(type) {
 	case *ast.BadExpr:
@@ -1379,7 +1393,7 @@
 	return true
 }
 
-// isLiteralType returns true iff x is a legal composite literal type.
+// isLiteralType reports whether x is a legal composite literal type.
 func isLiteralType(x ast.Expr) bool {
 	switch t := x.(type) {
 	case *ast.BadExpr:
diff --git a/src/go/parser/short_test.go b/src/go/parser/short_test.go
index 14a14d5..970ef2d 100644
--- a/src/go/parser/short_test.go
+++ b/src/go/parser/short_test.go
@@ -44,6 +44,8 @@
 	`package p; func _(x interface{f()}) { interface{f()}(x).f() }`,
 	`package p; func _(x chan int) { chan int(x) <- 0 }`,
 	`package p; const (x = 0; y; z)`, // issue 9639
+	`package p; var _ = map[P]int{P{}:0, {}:1}`,
+	`package p; var _ = map[*P]int{&P{}:0, {}:1}`,
 }
 
 func TestValid(t *testing.T) {
diff --git a/src/go/parser/testdata/issue3106.src b/src/go/parser/testdata/issue3106.src
index 82796c8..2db10be 100644
--- a/src/go/parser/testdata/issue3106.src
+++ b/src/go/parser/testdata/issue3106.src
@@ -19,7 +19,7 @@
 				time.Sleep(1e8)
 				m.Lock()
 				defer
-				if /* ERROR "expected operand, found 'if'" */ percent == 100 {
+				if /* ERROR "expected ';', found 'if'" */ percent == 100 {
 					m.Unlock()
 					break
 				}
diff --git a/src/go/printer/printer.go b/src/go/printer/printer.go
index 36f9439..f9343d3 100644
--- a/src/go/printer/printer.go
+++ b/src/go/printer/printer.go
@@ -144,7 +144,7 @@
 	p.commentOffset = infinity
 }
 
-// commentBefore returns true iff the current comment group occurs
+// commentBefore reports whether the current comment group occurs
 // before the next position in the source code and printing it does
 // not introduce implicit semicolons.
 //
diff --git a/src/go/printer/testdata/parser.go b/src/go/printer/testdata/parser.go
index dba8bbd..44dfa19 100644
--- a/src/go/printer/testdata/parser.go
+++ b/src/go/printer/testdata/parser.go
@@ -1165,7 +1165,7 @@
 	return x
 }
 
-// isTypeName returns true iff x is a (qualified) TypeName.
+// isTypeName reports whether x is a (qualified) TypeName.
 func isTypeName(x ast.Expr) bool {
 	switch t := x.(type) {
 	case *ast.BadExpr:
@@ -1179,7 +1179,7 @@
 	return true
 }
 
-// isLiteralType returns true iff x is a legal composite literal type.
+// isLiteralType reports whether x is a legal composite literal type.
 func isLiteralType(x ast.Expr) bool {
 	switch t := x.(type) {
 	case *ast.BadExpr:
diff --git a/src/go/scanner/errors.go b/src/go/scanner/errors.go
index 22de69c..7c9ab25 100644
--- a/src/go/scanner/errors.go
+++ b/src/go/scanner/errors.go
@@ -62,7 +62,14 @@
 			return true
 		}
 		if e.Line == f.Line {
-			return e.Column < f.Column
+			if e.Column < f.Column {
+				return true
+			}
+			if e.Column == f.Column {
+				if p[i].Msg < p[j].Msg {
+					return true
+				}
+			}
 		}
 	}
 	return false
diff --git a/src/go/token/position.go b/src/go/token/position.go
index 17452bb..3375177 100644
--- a/src/go/token/position.go
+++ b/src/go/token/position.go
@@ -24,7 +24,7 @@
 	Column   int    // column number, starting at 1 (byte count)
 }
 
-// IsValid returns true if the position is valid.
+// IsValid reports whether the position is valid.
 func (pos *Position) IsValid() bool { return pos.Line > 0 }
 
 // String returns a string in one of several forms:
@@ -77,7 +77,7 @@
 //
 const NoPos Pos = 0
 
-// IsValid returns true if the position is valid.
+// IsValid reports whether the position is valid.
 func (p Pos) IsValid() bool {
 	return p != NoPos
 }
@@ -157,7 +157,7 @@
 	f.lines = f.lines[:len(f.lines)-1]
 }
 
-// SetLines sets the line offsets for a file and returns true if successful.
+// SetLines sets the line offsets for a file and reports whether it succeeded.
 // The line offsets are the offsets of the first character of each line;
 // for instance for the content "ab\nc\n" the line offsets are {0, 3}.
 // An empty file has an empty line offset table.
diff --git a/src/hash/crc32/crc32_generic.go b/src/hash/crc32/crc32_generic.go
index 6f597f5..416c1b7 100644
--- a/src/hash/crc32/crc32_generic.go
+++ b/src/hash/crc32/crc32_generic.go
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// +build 386 arm ppc64 ppc64le
+// +build 386 arm arm64 ppc64 ppc64le
 
 package crc32
 
diff --git a/src/html/template/escape_test.go b/src/html/template/escape_test.go
index ef7b877..9c9502a 100644
--- a/src/html/template/escape_test.go
+++ b/src/html/template/escape_test.go
@@ -1686,6 +1686,21 @@
 	}
 }
 
+// Unlike text/template, html/template crashed if given an incomplete
+// template, that is, a template that had been named but not given any content.
+// This is issue #10204.
+func TestErrorOnUndefined(t *testing.T) {
+	tmpl := New("undefined")
+
+	err := tmpl.Execute(nil, nil)
+	if err == nil {
+		t.Error("expected error")
+	}
+	if !strings.Contains(err.Error(), "incomplete") {
+		t.Errorf("expected error about incomplete template; got %s", err)
+	}
+}
+
 func BenchmarkEscapedExecute(b *testing.B) {
 	tmpl := Must(New("t").Parse(`<a onclick="alert('{{.}}')">{{.}}</a>`))
 	var buf bytes.Buffer
diff --git a/src/html/template/template.go b/src/html/template/template.go
index ce61701..64c0041 100644
--- a/src/html/template/template.go
+++ b/src/html/template/template.go
@@ -56,6 +56,9 @@
 	t.nameSpace.mu.Lock()
 	defer t.nameSpace.mu.Unlock()
 	if t.escapeErr == nil {
+		if t.Tree == nil {
+			return fmt.Errorf("template: %q is an incomplete or empty template%s", t.Name(), t.text.DefinedTemplates())
+		}
 		if err := escapeTemplate(t, t.text.Root, t.Name()); err != nil {
 			return err
 		}
diff --git a/src/image/color/color.go b/src/image/color/color.go
index ff596a7..00bd8fd 100644
--- a/src/image/color/color.go
+++ b/src/image/color/color.go
@@ -9,14 +9,20 @@
 // The conversion may be lossy.
 type Color interface {
 	// RGBA returns the alpha-premultiplied red, green, blue and alpha values
-	// for the color. Each value ranges within [0, 0xFFFF], but is represented
-	// by a uint32 so that multiplying by a blend factor up to 0xFFFF will not
+	// for the color. Each value ranges within [0, 0xffff], but is represented
+	// by a uint32 so that multiplying by a blend factor up to 0xffff will not
 	// overflow.
+	//
+	// An alpha-premultiplied color component c has been scaled by alpha (a),
+	// so has valid values 0 <= c <= a.
 	RGBA() (r, g, b, a uint32)
 }
 
-// RGBA represents a traditional 32-bit alpha-premultiplied color,
-// having 8 bits for each of red, green, blue and alpha.
+// RGBA represents a traditional 32-bit alpha-premultiplied color, having 8
+// bits for each of red, green, blue and alpha.
+//
+// An alpha-premultiplied color component C has been scaled by alpha (A), so
+// has valid values 0 <= C <= A.
 type RGBA struct {
 	R, G, B, A uint8
 }
@@ -33,8 +39,11 @@
 	return
 }
 
-// RGBA64 represents a 64-bit alpha-premultiplied color,
-// having 16 bits for each of red, green, blue and alpha.
+// RGBA64 represents a 64-bit alpha-premultiplied color, having 16 bits for
+// each of red, green, blue and alpha.
+//
+// An alpha-premultiplied color component C has been scaled by alpha (A), so
+// has valid values 0 <= C <= A.
 type RGBA64 struct {
 	R, G, B, A uint16
 }
diff --git a/src/image/color/ycbcr.go b/src/image/color/ycbcr.go
index b7df672..bbaaf7e 100644
--- a/src/image/color/ycbcr.go
+++ b/src/image/color/ycbcr.go
@@ -19,18 +19,18 @@
 	cr := (32768*r1 - 27440*g1 - 5328*b1 + 257<<15) >> 16
 	if yy < 0 {
 		yy = 0
-	} else if yy > 255 {
-		yy = 255
+	} else if yy > 0xff {
+		yy = 0xff
 	}
 	if cb < 0 {
 		cb = 0
-	} else if cb > 255 {
-		cb = 255
+	} else if cb > 0xff {
+		cb = 0xff
 	}
 	if cr < 0 {
 		cr = 0
-	} else if cr > 255 {
-		cr = 255
+	} else if cr > 0xff {
+		cr = 0xff
 	}
 	return uint8(yy), uint8(cb), uint8(cr)
 }
@@ -50,18 +50,18 @@
 	b := (yy1 + 116130*cb1) >> 16
 	if r < 0 {
 		r = 0
-	} else if r > 255 {
-		r = 255
+	} else if r > 0xff {
+		r = 0xff
 	}
 	if g < 0 {
 		g = 0
-	} else if g > 255 {
-		g = 255
+	} else if g > 0xff {
+		g = 0xff
 	}
 	if b < 0 {
 		b = 0
-	} else if b > 255 {
-		b = 255
+	} else if b > 0xff {
+		b = 0xff
 	}
 	return uint8(r), uint8(g), uint8(b)
 }
@@ -82,8 +82,45 @@
 }
 
 func (c YCbCr) RGBA() (uint32, uint32, uint32, uint32) {
-	r, g, b := YCbCrToRGB(c.Y, c.Cb, c.Cr)
-	return uint32(r) * 0x101, uint32(g) * 0x101, uint32(b) * 0x101, 0xffff
+	// This code is a copy of the YCbCrToRGB function above, except that it
+	// returns values in the range [0, 0xffff] instead of [0, 0xff]. There is a
+	// subtle difference between doing this and having YCbCr satisfy the Color
+	// interface by first converting to an RGBA. The latter loses some
+	// information by going to and from 8 bits per channel.
+	//
+	// For example, this code:
+	//	const y, cb, cr = 0x7f, 0x7f, 0x7f
+	//	r, g, b := color.YCbCrToRGB(y, cb, cr)
+	//	r0, g0, b0, _ := color.YCbCr{y, cb, cr}.RGBA()
+	//	r1, g1, b1, _ := color.RGBA{r, g, b, 0xff}.RGBA()
+	//	fmt.Printf("0x%04x 0x%04x 0x%04x\n", r0, g0, b0)
+	//	fmt.Printf("0x%04x 0x%04x 0x%04x\n", r1, g1, b1)
+	// prints:
+	//	0x7e19 0x808e 0x7dba
+	//	0x7e7e 0x8080 0x7d7d
+
+	yy1 := int(c.Y)<<16 + 1<<15
+	cb1 := int(c.Cb) - 128
+	cr1 := int(c.Cr) - 128
+	r := (yy1 + 91881*cr1) >> 8
+	g := (yy1 - 22554*cb1 - 46802*cr1) >> 8
+	b := (yy1 + 116130*cb1) >> 8
+	if r < 0 {
+		r = 0
+	} else if r > 0xffff {
+		r = 0xffff
+	}
+	if g < 0 {
+		g = 0
+	} else if g > 0xffff {
+		g = 0xffff
+	}
+	if b < 0 {
+		b = 0
+	} else if b > 0xffff {
+		b = 0xffff
+	}
+	return uint32(r), uint32(g), uint32(b), 0xffff
 }
 
 // YCbCrModel is the Model for Y'CbCr colors.
@@ -111,20 +148,20 @@
 		w = bb
 	}
 	if w == 0 {
-		return 0, 0, 0, 255
+		return 0, 0, 0, 0xff
 	}
-	c := (w - rr) * 255 / w
-	m := (w - gg) * 255 / w
-	y := (w - bb) * 255 / w
-	return uint8(c), uint8(m), uint8(y), uint8(255 - w)
+	c := (w - rr) * 0xff / w
+	m := (w - gg) * 0xff / w
+	y := (w - bb) * 0xff / w
+	return uint8(c), uint8(m), uint8(y), uint8(0xff - w)
 }
 
 // CMYKToRGB converts a CMYK quadruple to an RGB triple.
 func CMYKToRGB(c, m, y, k uint8) (uint8, uint8, uint8) {
-	w := uint32(255 - k)
-	r := uint32(255-c) * w / 255
-	g := uint32(255-m) * w / 255
-	b := uint32(255-y) * w / 255
+	w := uint32(0xff - k)
+	r := uint32(0xff-c) * w / 0xff
+	g := uint32(0xff-m) * w / 0xff
+	b := uint32(0xff-y) * w / 0xff
 	return uint8(r), uint8(g), uint8(b)
 }
 
diff --git a/src/image/decode_test.go b/src/image/decode_test.go
index e88bfda..d16ef8a 100644
--- a/src/image/decode_test.go
+++ b/src/image/decode_test.go
@@ -6,6 +6,7 @@
 
 import (
 	"bufio"
+	"fmt"
 	"image"
 	"image/color"
 	"os"
@@ -32,7 +33,9 @@
 	// JPEG is a lossy format and hence needs a non-zero tolerance.
 	{"testdata/video-001.png", "testdata/video-001.jpeg", 8 << 8},
 	{"testdata/video-001.png", "testdata/video-001.progressive.jpeg", 8 << 8},
+	{"testdata/video-001.221212.png", "testdata/video-001.221212.jpeg", 8 << 8},
 	{"testdata/video-001.cmyk.png", "testdata/video-001.cmyk.jpeg", 8 << 8},
+	{"testdata/video-001.rgb.png", "testdata/video-001.rgb.jpeg", 8 << 8},
 	// Grayscale images.
 	{"testdata/video-005.gray.png", "testdata/video-005.gray.jpeg", 8 << 8},
 	{"testdata/video-005.gray.png", "testdata/video-005.gray.png", 0},
@@ -75,6 +78,11 @@
 }
 
 func TestDecode(t *testing.T) {
+	rgba := func(c color.Color) string {
+		r, g, b, a := c.RGBA()
+		return fmt.Sprintf("rgba = 0x%04x, 0x%04x, 0x%04x, 0x%04x for %T%v", r, g, b, a, c, c)
+	}
+
 	golden := make(map[string]image.Image)
 loop:
 	for _, it := range imageTests {
@@ -95,13 +103,14 @@
 		}
 		b := g.Bounds()
 		if !b.Eq(m.Bounds()) {
-			t.Errorf("%s: want bounds %v got %v", it.filename, b, m.Bounds())
+			t.Errorf("%s: got bounds %v want %v", it.filename, m.Bounds(), b)
 			continue loop
 		}
 		for y := b.Min.Y; y < b.Max.Y; y++ {
 			for x := b.Min.X; x < b.Max.X; x++ {
 				if !withinTolerance(g.At(x, y), m.At(x, y), it.tolerance) {
-					t.Errorf("%s: at (%d, %d), want %v got %v", it.filename, x, y, g.At(x, y), m.At(x, y))
+					t.Errorf("%s: at (%d, %d):\ngot  %v\nwant %v",
+						it.filename, x, y, rgba(m.At(x, y)), rgba(g.At(x, y)))
 					continue loop
 				}
 			}
diff --git a/src/image/draw/draw.go b/src/image/draw/draw.go
index f704ff0..420fd05 100644
--- a/src/image/draw/draw.go
+++ b/src/image/draw/draw.go
@@ -11,6 +11,7 @@
 import (
 	"image"
 	"image/color"
+	"image/internal/imageutil"
 )
 
 // m is the maximum color value returned by image.Color.RGBA.
@@ -124,7 +125,11 @@
 					drawNRGBAOver(dst0, r, src0, sp)
 					return
 				case *image.YCbCr:
-					if drawYCbCr(dst0, r, src0, sp) {
+					// An image.YCbCr is always fully opaque, and so if the
+					// mask is nil (i.e. fully opaque) then the op is
+					// effectively always Src. Similarly for image.Gray and
+					// image.CMYK.
+					if imageutil.DrawYCbCr(dst0, r, src0, sp) {
 						return
 					}
 				case *image.Gray:
@@ -154,7 +159,7 @@
 					drawNRGBASrc(dst0, r, src0, sp)
 					return
 				case *image.YCbCr:
-					if drawYCbCr(dst0, r, src0, sp) {
+					if imageutil.DrawYCbCr(dst0, r, src0, sp) {
 						return
 					}
 				case *image.Gray:
@@ -408,79 +413,7 @@
 	}
 }
 
-// TODO(nigeltao): this function is copy/pasted to image/jpeg/reader.go. We
-// should un-copy/paste it.
-func drawYCbCr(dst *image.RGBA, r image.Rectangle, src *image.YCbCr, sp image.Point) (ok bool) {
-	// An image.YCbCr is always fully opaque, and so if the mask is implicitly nil
-	// (i.e. fully opaque) then the op is effectively always Src.
-	x0 := (r.Min.X - dst.Rect.Min.X) * 4
-	x1 := (r.Max.X - dst.Rect.Min.X) * 4
-	y0 := r.Min.Y - dst.Rect.Min.Y
-	y1 := r.Max.Y - dst.Rect.Min.Y
-	switch src.SubsampleRatio {
-	case image.YCbCrSubsampleRatio444:
-		for y, sy := y0, sp.Y; y != y1; y, sy = y+1, sy+1 {
-			dpix := dst.Pix[y*dst.Stride:]
-			yi := (sy-src.Rect.Min.Y)*src.YStride + (sp.X - src.Rect.Min.X)
-			ci := (sy-src.Rect.Min.Y)*src.CStride + (sp.X - src.Rect.Min.X)
-			for x := x0; x != x1; x, yi, ci = x+4, yi+1, ci+1 {
-				rr, gg, bb := color.YCbCrToRGB(src.Y[yi], src.Cb[ci], src.Cr[ci])
-				dpix[x+0] = rr
-				dpix[x+1] = gg
-				dpix[x+2] = bb
-				dpix[x+3] = 255
-			}
-		}
-	case image.YCbCrSubsampleRatio422:
-		for y, sy := y0, sp.Y; y != y1; y, sy = y+1, sy+1 {
-			dpix := dst.Pix[y*dst.Stride:]
-			yi := (sy-src.Rect.Min.Y)*src.YStride + (sp.X - src.Rect.Min.X)
-			ciBase := (sy-src.Rect.Min.Y)*src.CStride - src.Rect.Min.X/2
-			for x, sx := x0, sp.X; x != x1; x, sx, yi = x+4, sx+1, yi+1 {
-				ci := ciBase + sx/2
-				rr, gg, bb := color.YCbCrToRGB(src.Y[yi], src.Cb[ci], src.Cr[ci])
-				dpix[x+0] = rr
-				dpix[x+1] = gg
-				dpix[x+2] = bb
-				dpix[x+3] = 255
-			}
-		}
-	case image.YCbCrSubsampleRatio420:
-		for y, sy := y0, sp.Y; y != y1; y, sy = y+1, sy+1 {
-			dpix := dst.Pix[y*dst.Stride:]
-			yi := (sy-src.Rect.Min.Y)*src.YStride + (sp.X - src.Rect.Min.X)
-			ciBase := (sy/2-src.Rect.Min.Y/2)*src.CStride - src.Rect.Min.X/2
-			for x, sx := x0, sp.X; x != x1; x, sx, yi = x+4, sx+1, yi+1 {
-				ci := ciBase + sx/2
-				rr, gg, bb := color.YCbCrToRGB(src.Y[yi], src.Cb[ci], src.Cr[ci])
-				dpix[x+0] = rr
-				dpix[x+1] = gg
-				dpix[x+2] = bb
-				dpix[x+3] = 255
-			}
-		}
-	case image.YCbCrSubsampleRatio440:
-		for y, sy := y0, sp.Y; y != y1; y, sy = y+1, sy+1 {
-			dpix := dst.Pix[y*dst.Stride:]
-			yi := (sy-src.Rect.Min.Y)*src.YStride + (sp.X - src.Rect.Min.X)
-			ci := (sy/2-src.Rect.Min.Y/2)*src.CStride + (sp.X - src.Rect.Min.X)
-			for x := x0; x != x1; x, yi, ci = x+4, yi+1, ci+1 {
-				rr, gg, bb := color.YCbCrToRGB(src.Y[yi], src.Cb[ci], src.Cr[ci])
-				dpix[x+0] = rr
-				dpix[x+1] = gg
-				dpix[x+2] = bb
-				dpix[x+3] = 255
-			}
-		}
-	default:
-		return false
-	}
-	return true
-}
-
 func drawGray(dst *image.RGBA, r image.Rectangle, src *image.Gray, sp image.Point) {
-	// An image.Gray is always fully opaque, and so if the mask is implicitly nil
-	// (i.e. fully opaque) then the op is effectively always Src.
 	i0 := (r.Min.X - dst.Rect.Min.X) * 4
 	i1 := (r.Max.X - dst.Rect.Min.X) * 4
 	si0 := (sp.X - src.Rect.Min.X) * 1
@@ -503,8 +436,6 @@
 }
 
 func drawCMYK(dst *image.RGBA, r image.Rectangle, src *image.CMYK, sp image.Point) {
-	// An image.CMYK is always fully opaque, and so if the mask is implicitly nil
-	// (i.e. fully opaque) then the op is effectively always Src.
 	i0 := (r.Min.X - dst.Rect.Min.X) * 4
 	i1 := (r.Max.X - dst.Rect.Min.X) * 4
 	si0 := (sp.X - src.Rect.Min.X) * 4
diff --git a/src/image/draw/draw_test.go b/src/image/draw/draw_test.go
index a58f0f4..29951bf 100644
--- a/src/image/draw/draw_test.go
+++ b/src/image/draw/draw_test.go
@@ -163,8 +163,8 @@
 	// The source pixel is {0, 0, 136} in YCbCr-space, which is {11, 38, 0, 255} in RGB-space.
 	{"ycbcr", vgradCr(), fillAlpha(255), Over, color.RGBA{11, 38, 0, 255}},
 	{"ycbcrSrc", vgradCr(), fillAlpha(255), Src, color.RGBA{11, 38, 0, 255}},
-	{"ycbcrAlpha", vgradCr(), fillAlpha(192), Over, color.RGBA{42, 28, 0, 255}},
-	{"ycbcrAlphaSrc", vgradCr(), fillAlpha(192), Src, color.RGBA{8, 28, 0, 192}},
+	{"ycbcrAlpha", vgradCr(), fillAlpha(192), Over, color.RGBA{42, 29, 0, 255}},
+	{"ycbcrAlphaSrc", vgradCr(), fillAlpha(192), Src, color.RGBA{8, 29, 0, 192}},
 	{"ycbcrNil", vgradCr(), nil, Over, color.RGBA{11, 38, 0, 255}},
 	{"ycbcrNilSrc", vgradCr(), nil, Src, color.RGBA{11, 38, 0, 255}},
 	// Uniform mask (100%, 75%, nil) and variable Gray source.
diff --git a/src/image/geom.go b/src/image/geom.go
index 70e3ff0..e1cd4dc 100644
--- a/src/image/geom.go
+++ b/src/image/geom.go
@@ -5,6 +5,7 @@
 package image
 
 import (
+	"image/color"
 	"strconv"
 )
 
@@ -77,6 +78,10 @@
 // It is well-formed if Min.X <= Max.X and likewise for Y. Points are always
 // well-formed. A rectangle's methods always return well-formed outputs for
 // well-formed inputs.
+//
+// A Rectangle is also an Image whose bounds are the rectangle itself. At
+// returns color.Opaque for points in the rectangle and color.Transparent
+// otherwise.
 type Rectangle struct {
 	Min, Max Point
 }
@@ -226,6 +231,24 @@
 	return r
 }
 
+// At implements the Image interface.
+func (r Rectangle) At(x, y int) color.Color {
+	if (Point{x, y}).In(r) {
+		return color.Opaque
+	}
+	return color.Transparent
+}
+
+// Bounds implements the Image interface.
+func (r Rectangle) Bounds() Rectangle {
+	return r
+}
+
+// ColorModel implements the Image interface.
+func (r Rectangle) ColorModel() color.Model {
+	return color.Alpha16Model
+}
+
 // ZR is the zero Rectangle.
 var ZR Rectangle
 
diff --git a/src/image/internal/imageutil/gen.go b/src/image/internal/imageutil/gen.go
new file mode 100644
index 0000000..cde05ad
--- /dev/null
+++ b/src/image/internal/imageutil/gen.go
@@ -0,0 +1,154 @@
+// Copyright 2015 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.
+
+// +build ignore
+
+package main
+
+import (
+	"bytes"
+	"flag"
+	"fmt"
+	"go/format"
+	"io/ioutil"
+	"log"
+	"os"
+)
+
+var debug = flag.Bool("debug", false, "")
+
+func main() {
+	flag.Parse()
+
+	w := new(bytes.Buffer)
+	w.WriteString(pre)
+	for _, sratio := range subsampleRatios {
+		fmt.Fprintf(w, sratioCase, sratio, sratioLines[sratio])
+	}
+	w.WriteString(post)
+
+	if *debug {
+		os.Stdout.Write(w.Bytes())
+		return
+	}
+	out, err := format.Source(w.Bytes())
+	if err != nil {
+		log.Fatal(err)
+	}
+	if err := ioutil.WriteFile("impl.go", out, 0660); err != nil {
+		log.Fatal(err)
+	}
+}
+
+const pre = `// generated by "go run gen.go". DO NOT EDIT.
+
+package imageutil
+
+import (
+	"image"
+)
+
+// DrawYCbCr draws the YCbCr source image on the RGBA destination image with
+// r.Min in dst aligned with sp in src. It reports whether the draw was
+// successful. If it returns false, no dst pixels were changed.
+//
+// This function assumes that r is entirely within dst's bounds and the
+// translation of r from dst co-ordinate space to src co-ordinate space is
+// entirely within src's bounds.
+func DrawYCbCr(dst *image.RGBA, r image.Rectangle, src *image.YCbCr, sp image.Point) (ok bool) {
+	// This function exists in the image/internal/imageutil package because it
+	// is needed by both the image/draw and image/jpeg packages, but it doesn't
+	// seem right for one of those two to depend on the other.
+	//
+	// Another option is to have this code be exported in the image package,
+	// but we'd need to make sure we're totally happy with the API (for the
+	// rest of Go 1 compatibility), and decide if we want to have a more
+	// general purpose DrawToRGBA method for other image types. One possibility
+	// is:
+	//
+	// func (src *YCbCr) CopyToRGBA(dst *RGBA, dr, sr Rectangle) (effectiveDr, effectiveSr Rectangle)
+	//
+	// in the spirit of the built-in copy function for 1-dimensional slices,
+	// that also allowed a CopyFromRGBA method if needed.
+
+	x0 := (r.Min.X - dst.Rect.Min.X) * 4
+	x1 := (r.Max.X - dst.Rect.Min.X) * 4
+	y0 := r.Min.Y - dst.Rect.Min.Y
+	y1 := r.Max.Y - dst.Rect.Min.Y
+	switch src.SubsampleRatio {
+`
+
+const post = `
+	default:
+		return false
+	}
+	return true
+}
+`
+
+const sratioCase = `
+	case image.YCbCrSubsampleRatio%s:
+		for y, sy := y0, sp.Y; y != y1; y, sy = y+1, sy+1 {
+			dpix := dst.Pix[y*dst.Stride:]
+			yi := (sy-src.Rect.Min.Y)*src.YStride + (sp.X - src.Rect.Min.X)
+			%s
+
+				// This is an inline version of image/color/ycbcr.go's func YCbCrToRGB.
+				yy1 := int(src.Y[yi])<<16 + 1<<15
+				cb1 := int(src.Cb[ci]) - 128
+				cr1 := int(src.Cr[ci]) - 128
+				r := (yy1 + 91881*cr1) >> 16
+				g := (yy1 - 22554*cb1 - 46802*cr1) >> 16
+				b := (yy1 + 116130*cb1) >> 16
+				if r < 0 {
+					r = 0
+				} else if r > 255 {
+					r = 255
+				}
+				if g < 0 {
+					g = 0
+				} else if g > 255 {
+					g = 255
+				}
+				if b < 0 {
+					b = 0
+				} else if b > 255 {
+					b = 255
+				}
+
+				dpix[x+0] = uint8(r)
+				dpix[x+1] = uint8(g)
+				dpix[x+2] = uint8(b)
+				dpix[x+3] = 255
+			}
+		}
+`
+
+var subsampleRatios = []string{
+	"444",
+	"422",
+	"420",
+	"440",
+}
+
+var sratioLines = map[string]string{
+	"444": `
+		ci := (sy-src.Rect.Min.Y)*src.CStride + (sp.X - src.Rect.Min.X)
+		for x := x0; x != x1; x, yi, ci = x+4, yi+1, ci+1 {
+	`,
+	"422": `
+		ciBase := (sy-src.Rect.Min.Y)*src.CStride - src.Rect.Min.X/2
+		for x, sx := x0, sp.X; x != x1; x, sx, yi = x+4, sx+1, yi+1 {
+			ci := ciBase + sx/2
+	`,
+	"420": `
+		ciBase := (sy/2-src.Rect.Min.Y/2)*src.CStride - src.Rect.Min.X/2
+		for x, sx := x0, sp.X; x != x1; x, sx, yi = x+4, sx+1, yi+1 {
+			ci := ciBase + sx/2
+	`,
+	"440": `
+		ci := (sy/2-src.Rect.Min.Y/2)*src.CStride + (sp.X - src.Rect.Min.X)
+		for x := x0; x != x1; x, yi, ci = x+4, yi+1, ci+1 {
+	`,
+}
diff --git a/src/image/internal/imageutil/imageutil.go b/src/image/internal/imageutil/imageutil.go
new file mode 100644
index 0000000..10cef0c
--- /dev/null
+++ b/src/image/internal/imageutil/imageutil.go
@@ -0,0 +1,8 @@
+// Copyright 2015 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.
+
+//go:generate go run gen.go
+
+// Package imageutil contains code shared by image-related packages.
+package imageutil
diff --git a/src/image/internal/imageutil/impl.go b/src/image/internal/imageutil/impl.go
new file mode 100644
index 0000000..d4bd325
--- /dev/null
+++ b/src/image/internal/imageutil/impl.go
@@ -0,0 +1,196 @@
+// generated by "go run gen.go". DO NOT EDIT.
+
+package imageutil
+
+import (
+	"image"
+)
+
+// DrawYCbCr draws the YCbCr source image on the RGBA destination image with
+// r.Min in dst aligned with sp in src. It reports whether the draw was
+// successful. If it returns false, no dst pixels were changed.
+//
+// This function assumes that r is entirely within dst's bounds and the
+// translation of r from dst co-ordinate space to src co-ordinate space is
+// entirely within src's bounds.
+func DrawYCbCr(dst *image.RGBA, r image.Rectangle, src *image.YCbCr, sp image.Point) (ok bool) {
+	// This function exists in the image/internal/imageutil package because it
+	// is needed by both the image/draw and image/jpeg packages, but it doesn't
+	// seem right for one of those two to depend on the other.
+	//
+	// Another option is to have this code be exported in the image package,
+	// but we'd need to make sure we're totally happy with the API (for the
+	// rest of Go 1 compatibility), and decide if we want to have a more
+	// general purpose DrawToRGBA method for other image types. One possibility
+	// is:
+	//
+	// func (src *YCbCr) CopyToRGBA(dst *RGBA, dr, sr Rectangle) (effectiveDr, effectiveSr Rectangle)
+	//
+	// in the spirit of the built-in copy function for 1-dimensional slices,
+	// that also allowed a CopyFromRGBA method if needed.
+
+	x0 := (r.Min.X - dst.Rect.Min.X) * 4
+	x1 := (r.Max.X - dst.Rect.Min.X) * 4
+	y0 := r.Min.Y - dst.Rect.Min.Y
+	y1 := r.Max.Y - dst.Rect.Min.Y
+	switch src.SubsampleRatio {
+
+	case image.YCbCrSubsampleRatio444:
+		for y, sy := y0, sp.Y; y != y1; y, sy = y+1, sy+1 {
+			dpix := dst.Pix[y*dst.Stride:]
+			yi := (sy-src.Rect.Min.Y)*src.YStride + (sp.X - src.Rect.Min.X)
+
+			ci := (sy-src.Rect.Min.Y)*src.CStride + (sp.X - src.Rect.Min.X)
+			for x := x0; x != x1; x, yi, ci = x+4, yi+1, ci+1 {
+
+				// This is an inline version of image/color/ycbcr.go's func YCbCrToRGB.
+				yy1 := int(src.Y[yi])<<16 + 1<<15
+				cb1 := int(src.Cb[ci]) - 128
+				cr1 := int(src.Cr[ci]) - 128
+				r := (yy1 + 91881*cr1) >> 16
+				g := (yy1 - 22554*cb1 - 46802*cr1) >> 16
+				b := (yy1 + 116130*cb1) >> 16
+				if r < 0 {
+					r = 0
+				} else if r > 255 {
+					r = 255
+				}
+				if g < 0 {
+					g = 0
+				} else if g > 255 {
+					g = 255
+				}
+				if b < 0 {
+					b = 0
+				} else if b > 255 {
+					b = 255
+				}
+
+				dpix[x+0] = uint8(r)
+				dpix[x+1] = uint8(g)
+				dpix[x+2] = uint8(b)
+				dpix[x+3] = 255
+			}
+		}
+
+	case image.YCbCrSubsampleRatio422:
+		for y, sy := y0, sp.Y; y != y1; y, sy = y+1, sy+1 {
+			dpix := dst.Pix[y*dst.Stride:]
+			yi := (sy-src.Rect.Min.Y)*src.YStride + (sp.X - src.Rect.Min.X)
+
+			ciBase := (sy-src.Rect.Min.Y)*src.CStride - src.Rect.Min.X/2
+			for x, sx := x0, sp.X; x != x1; x, sx, yi = x+4, sx+1, yi+1 {
+				ci := ciBase + sx/2
+
+				// This is an inline version of image/color/ycbcr.go's func YCbCrToRGB.
+				yy1 := int(src.Y[yi])<<16 + 1<<15
+				cb1 := int(src.Cb[ci]) - 128
+				cr1 := int(src.Cr[ci]) - 128
+				r := (yy1 + 91881*cr1) >> 16
+				g := (yy1 - 22554*cb1 - 46802*cr1) >> 16
+				b := (yy1 + 116130*cb1) >> 16
+				if r < 0 {
+					r = 0
+				} else if r > 255 {
+					r = 255
+				}
+				if g < 0 {
+					g = 0
+				} else if g > 255 {
+					g = 255
+				}
+				if b < 0 {
+					b = 0
+				} else if b > 255 {
+					b = 255
+				}
+
+				dpix[x+0] = uint8(r)
+				dpix[x+1] = uint8(g)
+				dpix[x+2] = uint8(b)
+				dpix[x+3] = 255
+			}
+		}
+
+	case image.YCbCrSubsampleRatio420:
+		for y, sy := y0, sp.Y; y != y1; y, sy = y+1, sy+1 {
+			dpix := dst.Pix[y*dst.Stride:]
+			yi := (sy-src.Rect.Min.Y)*src.YStride + (sp.X - src.Rect.Min.X)
+
+			ciBase := (sy/2-src.Rect.Min.Y/2)*src.CStride - src.Rect.Min.X/2
+			for x, sx := x0, sp.X; x != x1; x, sx, yi = x+4, sx+1, yi+1 {
+				ci := ciBase + sx/2
+
+				// This is an inline version of image/color/ycbcr.go's func YCbCrToRGB.
+				yy1 := int(src.Y[yi])<<16 + 1<<15
+				cb1 := int(src.Cb[ci]) - 128
+				cr1 := int(src.Cr[ci]) - 128
+				r := (yy1 + 91881*cr1) >> 16
+				g := (yy1 - 22554*cb1 - 46802*cr1) >> 16
+				b := (yy1 + 116130*cb1) >> 16
+				if r < 0 {
+					r = 0
+				} else if r > 255 {
+					r = 255
+				}
+				if g < 0 {
+					g = 0
+				} else if g > 255 {
+					g = 255
+				}
+				if b < 0 {
+					b = 0
+				} else if b > 255 {
+					b = 255
+				}
+
+				dpix[x+0] = uint8(r)
+				dpix[x+1] = uint8(g)
+				dpix[x+2] = uint8(b)
+				dpix[x+3] = 255
+			}
+		}
+
+	case image.YCbCrSubsampleRatio440:
+		for y, sy := y0, sp.Y; y != y1; y, sy = y+1, sy+1 {
+			dpix := dst.Pix[y*dst.Stride:]
+			yi := (sy-src.Rect.Min.Y)*src.YStride + (sp.X - src.Rect.Min.X)
+
+			ci := (sy/2-src.Rect.Min.Y/2)*src.CStride + (sp.X - src.Rect.Min.X)
+			for x := x0; x != x1; x, yi, ci = x+4, yi+1, ci+1 {
+
+				// This is an inline version of image/color/ycbcr.go's func YCbCrToRGB.
+				yy1 := int(src.Y[yi])<<16 + 1<<15
+				cb1 := int(src.Cb[ci]) - 128
+				cr1 := int(src.Cr[ci]) - 128
+				r := (yy1 + 91881*cr1) >> 16
+				g := (yy1 - 22554*cb1 - 46802*cr1) >> 16
+				b := (yy1 + 116130*cb1) >> 16
+				if r < 0 {
+					r = 0
+				} else if r > 255 {
+					r = 255
+				}
+				if g < 0 {
+					g = 0
+				} else if g > 255 {
+					g = 255
+				}
+				if b < 0 {
+					b = 0
+				} else if b > 255 {
+					b = 255
+				}
+
+				dpix[x+0] = uint8(r)
+				dpix[x+1] = uint8(g)
+				dpix[x+2] = uint8(b)
+				dpix[x+3] = 255
+			}
+		}
+
+	default:
+		return false
+	}
+	return true
+}
diff --git a/src/image/jpeg/reader.go b/src/image/jpeg/reader.go
index 3e002e5..6a86472 100644
--- a/src/image/jpeg/reader.go
+++ b/src/image/jpeg/reader.go
@@ -10,6 +10,7 @@
 import (
 	"image"
 	"image/color"
+	"image/internal/imageutil"
 	"io"
 )
 
@@ -26,6 +27,8 @@
 
 func (e UnsupportedError) Error() string { return "unsupported JPEG feature: " + string(e) }
 
+var errUnsupportedSubsamplingRatio = UnsupportedError("luma/chroma subsampling ratio")
+
 // Component specification, specified in section B.2.2.
 type component struct {
 	h  int   // Horizontal sampling factor.
@@ -126,6 +129,7 @@
 	ri                  int // Restart Interval.
 	nComp               int
 	progressive         bool
+	jfif                bool
 	adobeTransformValid bool
 	adobeTransform      uint8
 	eobRun              uint16 // End-of-Band run, specified in section G.1.2.2.
@@ -297,12 +301,12 @@
 	switch n {
 	case 6 + 3*1: // Grayscale image.
 		d.nComp = 1
-	case 6 + 3*3: // YCbCr image. (TODO(nigeltao): or RGB image.)
+	case 6 + 3*3: // YCbCr or RGB image.
 		d.nComp = 3
 	case 6 + 3*4: // YCbCrK or CMYK image.
 		d.nComp = 4
 	default:
-		return UnsupportedError("SOF has wrong length")
+		return UnsupportedError("number of components")
 	}
 	if err := d.readFull(d.tmp[:n]); err != nil {
 		return err
@@ -314,12 +318,34 @@
 	d.height = int(d.tmp[1])<<8 + int(d.tmp[2])
 	d.width = int(d.tmp[3])<<8 + int(d.tmp[4])
 	if int(d.tmp[5]) != d.nComp {
-		return UnsupportedError("SOF has wrong number of image components")
+		return FormatError("SOF has wrong length")
 	}
+
 	for i := 0; i < d.nComp; i++ {
 		d.comp[i].c = d.tmp[6+3*i]
+		// Section B.2.2 states that "the value of C_i shall be different from
+		// the values of C_1 through C_(i-1)".
+		for j := 0; j < i; j++ {
+			if d.comp[i].c == d.comp[j].c {
+				return FormatError("repeated component identifier")
+			}
+		}
+
 		d.comp[i].tq = d.tmp[8+3*i]
-		if d.nComp == 1 {
+		if d.comp[i].tq > maxTq {
+			return FormatError("bad Tq value")
+		}
+
+		hv := d.tmp[7+3*i]
+		h, v := int(hv>>4), int(hv&0x0f)
+		if h < 1 || 4 < h || v < 1 || 4 < v {
+			return FormatError("luma/chroma subsampling ratio")
+		}
+		if h == 3 || v == 3 {
+			return errUnsupportedSubsamplingRatio
+		}
+		switch d.nComp {
+		case 1:
 			// If a JPEG image has only one component, section A.2 says "this data
 			// is non-interleaved by definition" and section A.2.2 says "[in this
 			// case...] the order of data units within a scan shall be left-to-right
@@ -331,27 +357,34 @@
 			// always 1. The component's (h, v) is effectively always (1, 1): even if
 			// the nominal (h, v) is (2, 1), a 20x5 image is encoded in three 8x8
 			// MCUs, not two 16x8 MCUs.
-			d.comp[i].h = 1
-			d.comp[i].v = 1
-			continue
-		}
-		hv := d.tmp[7+3*i]
-		d.comp[i].h = int(hv >> 4)
-		d.comp[i].v = int(hv & 0x0f)
-		switch d.nComp {
+			h, v = 1, 1
+
 		case 3:
 			// For YCbCr images, we only support 4:4:4, 4:4:0, 4:2:2, 4:2:0,
-			// 4:1:1 or 4:1:0 chroma downsampling ratios. This implies that the
+			// 4:1:1 or 4:1:0 chroma subsampling ratios. This implies that the
 			// (h, v) values for the Y component are either (1, 1), (1, 2),
-			// (2, 1), (2, 2), (4, 1) or (4, 2), and the (h, v) values for the Cr
-			// and Cb components must be (1, 1).
-			if i == 0 {
-				if hv != 0x11 && hv != 0x21 && hv != 0x22 && hv != 0x12 && hv != 0x41 && hv != 0x42 {
-					return UnsupportedError("luma/chroma downsample ratio")
+			// (2, 1), (2, 2), (4, 1) or (4, 2), and the Y component's values
+			// must be a multiple of the Cb and Cr component's values. We also
+			// assume that the two chroma components have the same subsampling
+			// ratio.
+			switch i {
+			case 0: // Y.
+				// We have already verified, above, that h and v are both
+				// either 1, 2 or 4, so invalid (h, v) combinations are those
+				// with v == 4.
+				if v == 4 {
+					return errUnsupportedSubsamplingRatio
 				}
-			} else if hv != 0x11 {
-				return UnsupportedError("luma/chroma downsample ratio")
+			case 1: // Cb.
+				if d.comp[0].h%h != 0 || d.comp[0].v%v != 0 {
+					return errUnsupportedSubsamplingRatio
+				}
+			case 2: // Cr.
+				if d.comp[1].h != h || d.comp[1].v != v {
+					return errUnsupportedSubsamplingRatio
+				}
 			}
+
 		case 4:
 			// For 4-component images (either CMYK or YCbCrK), we only support two
 			// hv vectors: [0x11 0x11 0x11 0x11] and [0x22 0x11 0x11 0x22].
@@ -365,18 +398,21 @@
 			switch i {
 			case 0:
 				if hv != 0x11 && hv != 0x22 {
-					return UnsupportedError("luma/chroma downsample ratio")
+					return errUnsupportedSubsamplingRatio
 				}
 			case 1, 2:
 				if hv != 0x11 {
-					return UnsupportedError("luma/chroma downsample ratio")
+					return errUnsupportedSubsamplingRatio
 				}
 			case 3:
-				if d.comp[0].h != d.comp[3].h || d.comp[0].v != d.comp[3].v {
-					return UnsupportedError("luma/chroma downsample ratio")
+				if d.comp[0].h != h || d.comp[0].v != v {
+					return errUnsupportedSubsamplingRatio
 				}
 			}
 		}
+
+		d.comp[i].h = h
+		d.comp[i].v = v
 	}
 	return nil
 }
@@ -439,6 +475,23 @@
 	return nil
 }
 
+func (d *decoder) processApp0Marker(n int) error {
+	if n < 5 {
+		return d.ignore(n)
+	}
+	if err := d.readFull(d.tmp[:5]); err != nil {
+		return err
+	}
+	n -= 5
+
+	d.jfif = d.tmp[0] == 'J' && d.tmp[1] == 'F' && d.tmp[2] == 'I' && d.tmp[3] == 'F' && d.tmp[4] == '\x00'
+
+	if n > 0 {
+		return d.ignore(n)
+	}
+	return nil
+}
+
 func (d *decoder) processApp14Marker(n int) error {
 	if n < 12 {
 		return d.ignore(n)
@@ -544,17 +597,34 @@
 		case sof0Marker, sof1Marker, sof2Marker:
 			d.progressive = marker == sof2Marker
 			err = d.processSOF(n)
-			if configOnly {
+			if configOnly && d.jfif {
 				return nil, err
 			}
 		case dhtMarker:
-			err = d.processDHT(n)
+			if configOnly {
+				err = d.ignore(n)
+			} else {
+				err = d.processDHT(n)
+			}
 		case dqtMarker:
-			err = d.processDQT(n)
+			if configOnly {
+				err = d.ignore(n)
+			} else {
+				err = d.processDQT(n)
+			}
 		case sosMarker:
+			if configOnly {
+				return nil, nil
+			}
 			err = d.processSOS(n)
 		case driMarker:
-			err = d.processDRI(n)
+			if configOnly {
+				err = d.ignore(n)
+			} else {
+				err = d.processDRI(n)
+			}
+		case app0Marker:
+			err = d.processApp0Marker(n)
 		case app14Marker:
 			err = d.processApp14Marker(n)
 		default:
@@ -576,6 +646,8 @@
 	if d.img3 != nil {
 		if d.blackPix != nil {
 			return d.applyBlack()
+		} else if d.isRGB() {
+			return d.convertToRGB()
 		}
 		return d.img3, nil
 	}
@@ -605,7 +677,7 @@
 		// above, so in practice, only the fourth channel (black) is inverted.
 		bounds := d.img3.Bounds()
 		img := image.NewRGBA(bounds)
-		drawYCbCr(img, bounds, d.img3, bounds.Min)
+		imageutil.DrawYCbCr(img, bounds, d.img3, bounds.Min)
 		for iBase, y := 0, bounds.Min.Y; y < bounds.Max.Y; iBase, y = iBase+img.Stride, y+1 {
 			for i, x := iBase+3, bounds.Min.X; x < bounds.Max.X; i, x = i+4, x+1 {
 				img.Pix[i] = 255 - d.blackPix[(y-bounds.Min.Y)*d.blackStride+(x-bounds.Min.X)]
@@ -654,80 +726,34 @@
 	return img, nil
 }
 
-// drawYCbCr is the non-exported drawYCbCr function copy/pasted from the
-// image/draw package. It is copy/pasted because it doesn't seem right for the
-// image/jpeg package to depend on image/draw.
-//
-// TODO(nigeltao): remove the copy/paste, possibly by moving this to be an
-// exported method on *image.YCbCr. We'd need to make sure we're totally happy
-// with the API (for the rest of Go 1 compatibility) though, and if we want to
-// have a more general purpose DrawToRGBA method for other image types.
-func drawYCbCr(dst *image.RGBA, r image.Rectangle, src *image.YCbCr, sp image.Point) (ok bool) {
-	// An image.YCbCr is always fully opaque, and so if the mask is implicitly nil
-	// (i.e. fully opaque) then the op is effectively always Src.
-	x0 := (r.Min.X - dst.Rect.Min.X) * 4
-	x1 := (r.Max.X - dst.Rect.Min.X) * 4
-	y0 := r.Min.Y - dst.Rect.Min.Y
-	y1 := r.Max.Y - dst.Rect.Min.Y
-	switch src.SubsampleRatio {
-	case image.YCbCrSubsampleRatio444:
-		for y, sy := y0, sp.Y; y != y1; y, sy = y+1, sy+1 {
-			dpix := dst.Pix[y*dst.Stride:]
-			yi := (sy-src.Rect.Min.Y)*src.YStride + (sp.X - src.Rect.Min.X)
-			ci := (sy-src.Rect.Min.Y)*src.CStride + (sp.X - src.Rect.Min.X)
-			for x := x0; x != x1; x, yi, ci = x+4, yi+1, ci+1 {
-				rr, gg, bb := color.YCbCrToRGB(src.Y[yi], src.Cb[ci], src.Cr[ci])
-				dpix[x+0] = rr
-				dpix[x+1] = gg
-				dpix[x+2] = bb
-				dpix[x+3] = 255
-			}
-		}
-	case image.YCbCrSubsampleRatio422:
-		for y, sy := y0, sp.Y; y != y1; y, sy = y+1, sy+1 {
-			dpix := dst.Pix[y*dst.Stride:]
-			yi := (sy-src.Rect.Min.Y)*src.YStride + (sp.X - src.Rect.Min.X)
-			ciBase := (sy-src.Rect.Min.Y)*src.CStride - src.Rect.Min.X/2
-			for x, sx := x0, sp.X; x != x1; x, sx, yi = x+4, sx+1, yi+1 {
-				ci := ciBase + sx/2
-				rr, gg, bb := color.YCbCrToRGB(src.Y[yi], src.Cb[ci], src.Cr[ci])
-				dpix[x+0] = rr
-				dpix[x+1] = gg
-				dpix[x+2] = bb
-				dpix[x+3] = 255
-			}
-		}
-	case image.YCbCrSubsampleRatio420:
-		for y, sy := y0, sp.Y; y != y1; y, sy = y+1, sy+1 {
-			dpix := dst.Pix[y*dst.Stride:]
-			yi := (sy-src.Rect.Min.Y)*src.YStride + (sp.X - src.Rect.Min.X)
-			ciBase := (sy/2-src.Rect.Min.Y/2)*src.CStride - src.Rect.Min.X/2
-			for x, sx := x0, sp.X; x != x1; x, sx, yi = x+4, sx+1, yi+1 {
-				ci := ciBase + sx/2
-				rr, gg, bb := color.YCbCrToRGB(src.Y[yi], src.Cb[ci], src.Cr[ci])
-				dpix[x+0] = rr
-				dpix[x+1] = gg
-				dpix[x+2] = bb
-				dpix[x+3] = 255
-			}
-		}
-	case image.YCbCrSubsampleRatio440:
-		for y, sy := y0, sp.Y; y != y1; y, sy = y+1, sy+1 {
-			dpix := dst.Pix[y*dst.Stride:]
-			yi := (sy-src.Rect.Min.Y)*src.YStride + (sp.X - src.Rect.Min.X)
-			ci := (sy/2-src.Rect.Min.Y/2)*src.CStride + (sp.X - src.Rect.Min.X)
-			for x := x0; x != x1; x, yi, ci = x+4, yi+1, ci+1 {
-				rr, gg, bb := color.YCbCrToRGB(src.Y[yi], src.Cb[ci], src.Cr[ci])
-				dpix[x+0] = rr
-				dpix[x+1] = gg
-				dpix[x+2] = bb
-				dpix[x+3] = 255
-			}
-		}
-	default:
+func (d *decoder) isRGB() bool {
+	if d.jfif {
 		return false
 	}
-	return true
+	if d.adobeTransformValid && d.adobeTransform == adobeTransformUnknown {
+		// http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/JPEG.html#Adobe
+		// says that 0 means Unknown (and in practice RGB) and 1 means YCbCr.
+		return true
+	}
+	return d.comp[0].c == 'R' && d.comp[1].c == 'G' && d.comp[2].c == 'B'
+}
+
+func (d *decoder) convertToRGB() (image.Image, error) {
+	cScale := d.comp[0].h / d.comp[1].h
+	bounds := d.img3.Bounds()
+	img := image.NewRGBA(bounds)
+	for y := bounds.Min.Y; y < bounds.Max.Y; y++ {
+		po := img.PixOffset(bounds.Min.X, y)
+		yo := d.img3.YOffset(bounds.Min.X, y)
+		co := d.img3.COffset(bounds.Min.X, y)
+		for i, iMax := 0, bounds.Max.X-bounds.Min.X; i < iMax; i++ {
+			img.Pix[po+4*i+0] = d.img3.Y[yo+i]
+			img.Pix[po+4*i+1] = d.img3.Cb[co+i/cScale]
+			img.Pix[po+4*i+2] = d.img3.Cr[co+i/cScale]
+			img.Pix[po+4*i+3] = 255
+		}
+	}
+	return img, nil
 }
 
 // Decode reads a JPEG image from r and returns it as an image.Image.
@@ -751,8 +777,12 @@
 			Height:     d.height,
 		}, nil
 	case 3:
+		cm := color.YCbCrModel
+		if d.isRGB() {
+			cm = color.RGBAModel
+		}
 		return image.Config{
-			ColorModel: color.YCbCrModel, // TODO(nigeltao): support RGB JPEGs.
+			ColorModel: cm,
 			Width:      d.width,
 			Height:     d.height,
 		}, nil
diff --git a/src/image/jpeg/scan.go b/src/image/jpeg/scan.go
index 8fcf401..99734c0 100644
--- a/src/image/jpeg/scan.go
+++ b/src/image/jpeg/scan.go
@@ -9,26 +9,30 @@
 )
 
 // makeImg allocates and initializes the destination image.
-func (d *decoder) makeImg(h0, v0, mxx, myy int) {
+func (d *decoder) makeImg(mxx, myy int) {
 	if d.nComp == 1 {
 		m := image.NewGray(image.Rect(0, 0, 8*mxx, 8*myy))
 		d.img1 = m.SubImage(image.Rect(0, 0, d.width, d.height)).(*image.Gray)
 		return
 	}
 
+	h0 := d.comp[0].h
+	v0 := d.comp[0].v
+	hRatio := h0 / d.comp[1].h
+	vRatio := v0 / d.comp[1].v
 	var subsampleRatio image.YCbCrSubsampleRatio
-	switch {
-	case h0 == 1 && v0 == 1:
+	switch hRatio<<4 | vRatio {
+	case 0x11:
 		subsampleRatio = image.YCbCrSubsampleRatio444
-	case h0 == 1 && v0 == 2:
+	case 0x12:
 		subsampleRatio = image.YCbCrSubsampleRatio440
-	case h0 == 2 && v0 == 1:
+	case 0x21:
 		subsampleRatio = image.YCbCrSubsampleRatio422
-	case h0 == 2 && v0 == 2:
+	case 0x22:
 		subsampleRatio = image.YCbCrSubsampleRatio420
-	case h0 == 4 && v0 == 1:
+	case 0x41:
 		subsampleRatio = image.YCbCrSubsampleRatio411
-	case h0 == 4 && v0 == 2:
+	case 0x42:
 		subsampleRatio = image.YCbCrSubsampleRatio410
 	default:
 		panic("unreachable")
@@ -63,10 +67,11 @@
 		td        uint8 // DC table selector.
 		ta        uint8 // AC table selector.
 	}
+	totalHV := 0
 	for i := 0; i < nComp; i++ {
 		cs := d.tmp[1+2*i] // Component selector.
 		compIndex := -1
-		for j, comp := range d.comp {
+		for j, comp := range d.comp[:d.nComp] {
 			if cs == comp.c {
 				compIndex = j
 			}
@@ -75,6 +80,18 @@
 			return FormatError("unknown component selector")
 		}
 		scan[i].compIndex = uint8(compIndex)
+		// Section B.2.3 states that "the value of Cs_j shall be different from
+		// the values of Cs_1 through Cs_(j-1)". Since we have previously
+		// verified that a frame's component identifiers (C_i values in section
+		// B.2.2) are unique, it suffices to check that the implicit indexes
+		// into d.comp are unique.
+		for j := 0; j < i; j++ {
+			if scan[i].compIndex == scan[j].compIndex {
+				return FormatError("repeated component selector")
+			}
+		}
+		totalHV += d.comp[compIndex].h * d.comp[compIndex].v
+
 		scan[i].td = d.tmp[2+2*i] >> 4
 		if scan[i].td > maxTh {
 			return FormatError("bad Td value")
@@ -84,6 +101,11 @@
 			return FormatError("bad Ta value")
 		}
 	}
+	// Section B.2.3 states that if there is more than one component then the
+	// total H*V values in a scan must be <= 10.
+	if d.nComp > 1 && totalHV > 10 {
+		return FormatError("total sampling factors too large")
+	}
 
 	// zigStart and zigEnd are the spectral selection bounds.
 	// ah and al are the successive approximation high and low values.
@@ -123,7 +145,7 @@
 	mxx := (d.width + 8*h0 - 1) / (8 * h0)
 	myy := (d.height + 8*v0 - 1) / (8 * v0)
 	if d.img1 == nil && d.img3 == nil {
-		d.makeImg(h0, v0, mxx, myy)
+		d.makeImg(mxx, myy)
 	}
 	if d.progressive {
 		for i := 0; i < nComp; i++ {
@@ -140,10 +162,8 @@
 		// b is the decoded coefficients, in natural (not zig-zag) order.
 		b  block
 		dc [maxComponents]int32
-		// bx and by are the location of the current (in terms of 8x8 blocks).
-		// For example, with 4:2:0 chroma subsampling, the block whose top left
-		// pixel co-ordinates are (16, 8) is the third block in the first row:
-		// bx is 2 and by is 0, even though the pixel is in the second MCU.
+		// bx and by are the location of the current block, in units of 8x8
+		// blocks: the third block in the first row has (bx, by) = (2, 0).
 		bx, by     int
 		blockCount int
 	)
@@ -151,8 +171,10 @@
 		for mx := 0; mx < mxx; mx++ {
 			for i := 0; i < nComp; i++ {
 				compIndex := scan[i].compIndex
+				hi := d.comp[compIndex].h
+				vi := d.comp[compIndex].v
 				qt := &d.quant[d.comp[compIndex].tq]
-				for j := 0; j < d.comp[compIndex].h*d.comp[compIndex].v; j++ {
+				for j := 0; j < hi*vi; j++ {
 					// The blocks are traversed one MCU at a time. For 4:2:0 chroma
 					// subsampling, there are four Y 8x8 blocks in every 16x16 MCU.
 					//
@@ -179,10 +201,10 @@
 					//	0 1 2
 					//	3 4 5
 					if nComp != 1 {
-						bx = d.comp[compIndex].h*mx + j%h0
-						by = d.comp[compIndex].v*my + j/h0
+						bx = hi*mx + j%hi
+						by = vi*my + j/hi
 					} else {
-						q := mxx * d.comp[compIndex].h
+						q := mxx * hi
 						bx = blockCount % q
 						by = blockCount / q
 						blockCount++
@@ -193,7 +215,7 @@
 
 					// Load the previous partially decoded coefficients, if applicable.
 					if d.progressive {
-						b = d.progCoeffs[compIndex][by*mxx*d.comp[compIndex].h+bx]
+						b = d.progCoeffs[compIndex][by*mxx*hi+bx]
 					} else {
 						b = block{}
 					}
@@ -266,7 +288,7 @@
 					if d.progressive {
 						if zigEnd != blockSize-1 || al != 0 {
 							// We haven't completely decoded this 8x8 block. Save the coefficients.
-							d.progCoeffs[compIndex][by*mxx*d.comp[compIndex].h+bx] = b
+							d.progCoeffs[compIndex][by*mxx*hi+bx] = b
 							// At this point, we could execute the rest of the loop body to dequantize and
 							// perform the inverse DCT, to save early stages of a progressive image to the
 							// *image.YCbCr buffers (the whole point of progressive encoding), but in Go,
diff --git a/src/image/testdata/video-001.221212.jpeg b/src/image/testdata/video-001.221212.jpeg
new file mode 100644
index 0000000..f069c76
--- /dev/null
+++ b/src/image/testdata/video-001.221212.jpeg
Binary files differ
diff --git a/src/image/testdata/video-001.221212.png b/src/image/testdata/video-001.221212.png
new file mode 100644
index 0000000..d619a62
--- /dev/null
+++ b/src/image/testdata/video-001.221212.png
Binary files differ
diff --git a/src/image/testdata/video-001.rgb.jpeg b/src/image/testdata/video-001.rgb.jpeg
new file mode 100644
index 0000000..fc2ce3ca
--- /dev/null
+++ b/src/image/testdata/video-001.rgb.jpeg
Binary files differ
diff --git a/src/image/testdata/video-001.rgb.png b/src/image/testdata/video-001.rgb.png
new file mode 100644
index 0000000..edb716d
--- /dev/null
+++ b/src/image/testdata/video-001.rgb.png
Binary files differ
diff --git a/src/internal/format/format.go b/src/internal/format/format.go
new file mode 100644
index 0000000..f8812ff
--- /dev/null
+++ b/src/internal/format/format.go
@@ -0,0 +1,161 @@
+// Copyright 2015 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 format
+
+import (
+	"bytes"
+	"go/ast"
+	"go/parser"
+	"go/printer"
+	"go/token"
+	"strings"
+)
+
+const parserMode = parser.ParseComments
+
+// Parse parses src, which was read from the named file,
+// as a Go source file, declaration, or statement list.
+func Parse(fset *token.FileSet, filename string, src []byte, fragmentOk bool) (
+	file *ast.File,
+	sourceAdj func(src []byte, indent int) []byte,
+	indentAdj int,
+	err error,
+) {
+	// Try as whole source file.
+	file, err = parser.ParseFile(fset, filename, src, parserMode)
+	// If there's no error, return.  If the error is that the source file didn't begin with a
+	// package line and source fragments are ok, fall through to
+	// try as a source fragment.  Stop and return on any other error.
+	if err == nil || !fragmentOk || !strings.Contains(err.Error(), "expected 'package'") {
+		return
+	}
+
+	// If this is a declaration list, make it a source file
+	// by inserting a package clause.
+	// Insert using a ;, not a newline, so that the line numbers
+	// in psrc match the ones in src.
+	psrc := append([]byte("package p;"), src...)
+	file, err = parser.ParseFile(fset, filename, psrc, parserMode)
+	if err == nil {
+		sourceAdj = func(src []byte, indent int) []byte {
+			// Remove the package clause.
+			// Gofmt has turned the ; into a \n.
+			src = src[indent+len("package p\n"):]
+			return bytes.TrimSpace(src)
+		}
+		return
+	}
+	// If the error is that the source file didn't begin with a
+	// declaration, fall through to try as a statement list.
+	// Stop and return on any other error.
+	if !strings.Contains(err.Error(), "expected declaration") {
+		return
+	}
+
+	// If this is a statement list, make it a source file
+	// by inserting a package clause and turning the list
+	// into a function body.  This handles expressions too.
+	// Insert using a ;, not a newline, so that the line numbers
+	// in fsrc match the ones in src.
+	fsrc := append(append([]byte("package p; func _() {"), src...), '\n', '}')
+	file, err = parser.ParseFile(fset, filename, fsrc, parserMode)
+	if err == nil {
+		sourceAdj = func(src []byte, indent int) []byte {
+			// Cap adjusted indent to zero.
+			if indent < 0 {
+				indent = 0
+			}
+			// Remove the wrapping.
+			// Gofmt has turned the ; into a \n\n.
+			// There will be two non-blank lines with indent, hence 2*indent.
+			src = src[2*indent+len("package p\n\nfunc _() {"):]
+			src = src[:len(src)-(indent+len("\n}\n"))]
+			return bytes.TrimSpace(src)
+		}
+		// Gofmt has also indented the function body one level.
+		// Adjust that with indentAdj.
+		indentAdj = -1
+	}
+
+	// Succeeded, or out of options.
+	return
+}
+
+// Format formats the given package file originally obtained from src
+// and adjusts the result based on the original source via sourceAdj
+// and indentAdj.
+func Format(
+	fset *token.FileSet,
+	file *ast.File,
+	sourceAdj func(src []byte, indent int) []byte,
+	indentAdj int,
+	src []byte,
+	cfg printer.Config,
+) ([]byte, error) {
+	if sourceAdj == nil {
+		// Complete source file.
+		var buf bytes.Buffer
+		err := cfg.Fprint(&buf, fset, file)
+		if err != nil {
+			return nil, err
+		}
+		return buf.Bytes(), nil
+	}
+
+	// Partial source file.
+	// Determine and prepend leading space.
+	i, j := 0, 0
+	for j < len(src) && IsSpace(src[j]) {
+		if src[j] == '\n' {
+			i = j + 1 // byte offset of last line in leading space
+		}
+		j++
+	}
+	var res []byte
+	res = append(res, src[:i]...)
+
+	// Determine and prepend indentation of first code line.
+	// Spaces are ignored unless there are no tabs,
+	// in which case spaces count as one tab.
+	indent := 0
+	hasSpace := false
+	for _, b := range src[i:j] {
+		switch b {
+		case ' ':
+			hasSpace = true
+		case '\t':
+			indent++
+		}
+	}
+	if indent == 0 && hasSpace {
+		indent = 1
+	}
+	for i := 0; i < indent; i++ {
+		res = append(res, '\t')
+	}
+
+	// Format the source.
+	// Write it without any leading and trailing space.
+	cfg.Indent = indent + indentAdj
+	var buf bytes.Buffer
+	err := cfg.Fprint(&buf, fset, file)
+	if err != nil {
+		return nil, err
+	}
+	res = append(res, sourceAdj(buf.Bytes(), cfg.Indent)...)
+
+	// Determine and append trailing space.
+	i = len(src)
+	for i > 0 && IsSpace(src[i-1]) {
+		i--
+	}
+	return append(res, src[i:]...), nil
+}
+
+// IsSpace reports whether the byte is a space character.
+// IsSpace defines a space as being among the following bytes: ' ', '\t', '\n' and '\r'.
+func IsSpace(b byte) bool {
+	return b == ' ' || b == '\t' || b == '\n' || b == '\r'
+}
diff --git a/src/internal/trace/goroutines.go b/src/internal/trace/goroutines.go
new file mode 100644
index 0000000..f8673e2
--- /dev/null
+++ b/src/internal/trace/goroutines.go
@@ -0,0 +1,180 @@
+// 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.
+
+package trace
+
+// GDesc contains statistics about execution of a single goroutine.
+type GDesc struct {
+	ID           uint64
+	Name         string
+	PC           uint64
+	CreationTime int64
+	StartTime    int64
+	EndTime      int64
+
+	ExecTime      int64
+	SchedWaitTime int64
+	IOTime        int64
+	BlockTime     int64
+	SyscallTime   int64
+	GCTime        int64
+	SweepTime     int64
+	TotalTime     int64
+
+	*gdesc // private part
+}
+
+// gdesc is a private part of GDesc that is required only during analysis.
+type gdesc struct {
+	lastStartTime    int64
+	blockNetTime     int64
+	blockSyncTime    int64
+	blockSyscallTime int64
+	blockSweepTime   int64
+	blockGCTime      int64
+	blockSchedTime   int64
+}
+
+// GoroutineStats generates statistics for all goroutines in the trace.
+func GoroutineStats(events []*Event) map[uint64]*GDesc {
+	gs := make(map[uint64]*GDesc)
+	var lastTs int64
+	var gcStartTime int64
+	for _, ev := range events {
+		lastTs = ev.Ts
+		switch ev.Type {
+		case EvGoCreate:
+			g := &GDesc{ID: ev.Args[0], CreationTime: ev.Ts, gdesc: new(gdesc)}
+			g.blockSchedTime = ev.Ts
+			gs[g.ID] = g
+		case EvGoStart:
+			g := gs[ev.G]
+			if g.PC == 0 {
+				g.PC = ev.Stk[0].PC
+				g.Name = ev.Stk[0].Fn
+			}
+			g.lastStartTime = ev.Ts
+			if g.StartTime == 0 {
+				g.StartTime = ev.Ts
+			}
+			if g.blockSchedTime != 0 {
+				g.SchedWaitTime += ev.Ts - g.blockSchedTime
+				g.blockSchedTime = 0
+			}
+		case EvGoEnd, EvGoStop:
+			g := gs[ev.G]
+			g.ExecTime += ev.Ts - g.lastStartTime
+			g.TotalTime = ev.Ts - g.CreationTime
+			g.EndTime = ev.Ts
+		case EvGoBlockSend, EvGoBlockRecv, EvGoBlockSelect,
+			EvGoBlockSync, EvGoBlockCond:
+			g := gs[ev.G]
+			g.ExecTime += ev.Ts - g.lastStartTime
+			g.blockSyncTime = ev.Ts
+		case EvGoSched, EvGoPreempt:
+			g := gs[ev.G]
+			g.ExecTime += ev.Ts - g.lastStartTime
+			g.blockSchedTime = ev.Ts
+		case EvGoSleep, EvGoBlock:
+			g := gs[ev.G]
+			g.ExecTime += ev.Ts - g.lastStartTime
+		case EvGoBlockNet:
+			g := gs[ev.G]
+			g.ExecTime += ev.Ts - g.lastStartTime
+			g.blockNetTime = ev.Ts
+		case EvGoUnblock:
+			g := gs[ev.Args[0]]
+			if g.blockNetTime != 0 {
+				g.IOTime += ev.Ts - g.blockNetTime
+				g.blockNetTime = 0
+			}
+			if g.blockSyncTime != 0 {
+				g.BlockTime += ev.Ts - g.blockSyncTime
+				g.blockSyncTime = 0
+			}
+			g.blockSchedTime = ev.Ts
+		case EvGoSysBlock:
+			g := gs[ev.G]
+			g.ExecTime += ev.Ts - g.lastStartTime
+			g.blockSyscallTime = ev.Ts
+		case EvGoSysExit:
+			g := gs[ev.G]
+			if g.blockSyscallTime != 0 {
+				g.SyscallTime += ev.Ts - g.blockSyscallTime
+				g.blockSyscallTime = 0
+			}
+			g.blockSchedTime = ev.Ts
+		case EvGCSweepStart:
+			g := gs[ev.G]
+			if g != nil {
+				// Sweep can happen during GC on system goroutine.
+				g.blockSweepTime = ev.Ts
+			}
+		case EvGCSweepDone:
+			g := gs[ev.G]
+			if g != nil && g.blockSweepTime != 0 {
+				g.SweepTime += ev.Ts - g.blockSweepTime
+				g.blockSweepTime = 0
+			}
+		case EvGCStart:
+			gcStartTime = ev.Ts
+		case EvGCDone:
+			for _, g := range gs {
+				if g.EndTime == 0 {
+					g.GCTime += ev.Ts - gcStartTime
+				}
+			}
+		}
+	}
+
+	for _, g := range gs {
+		if g.TotalTime == 0 {
+			g.TotalTime = lastTs - g.CreationTime
+		}
+		if g.EndTime == 0 {
+			g.EndTime = lastTs
+		}
+		if g.blockNetTime != 0 {
+			g.IOTime += lastTs - g.blockNetTime
+			g.blockNetTime = 0
+		}
+		if g.blockSyncTime != 0 {
+			g.BlockTime += lastTs - g.blockSyncTime
+			g.blockSyncTime = 0
+		}
+		if g.blockSyscallTime != 0 {
+			g.SyscallTime += lastTs - g.blockSyscallTime
+			g.blockSyscallTime = 0
+		}
+		if g.blockSchedTime != 0 {
+			g.SchedWaitTime += lastTs - g.blockSchedTime
+			g.blockSchedTime = 0
+		}
+		g.gdesc = nil
+	}
+
+	return gs
+}
+
+// RelatedGoroutines finds a set of goroutines related to goroutine goid.
+func RelatedGoroutines(events []*Event, goid uint64) map[uint64]bool {
+	// BFS of depth 2 over "unblock" edges
+	// (what goroutines unblock goroutine goid?).
+	gmap := make(map[uint64]bool)
+	gmap[goid] = true
+	for i := 0; i < 2; i++ {
+		gmap1 := make(map[uint64]bool)
+		for g := range gmap {
+			gmap1[g] = true
+		}
+		for _, ev := range events {
+			if ev.Type == EvGoUnblock && gmap[ev.Args[0]] {
+				gmap1[ev.G] = true
+			}
+		}
+		gmap = gmap1
+	}
+	gmap[0] = true // for GC events
+	return gmap
+}
diff --git a/src/internal/trace/parser.go b/src/internal/trace/parser.go
index 62d063c..f1f709e 100644
--- a/src/internal/trace/parser.go
+++ b/src/internal/trace/parser.go
@@ -56,7 +56,7 @@
 	SyscallP // depicts returns from syscalls
 )
 
-// parseTrace parses, post-processes and verifies the trace.
+// Parse parses, post-processes and verifies the trace.
 func Parse(r io.Reader) ([]*Event, error) {
 	rawEvents, err := readTrace(r)
 	if err != nil {
@@ -66,6 +66,10 @@
 	if err != nil {
 		return nil, err
 	}
+	events, err = removeFutile(events)
+	if err != nil {
+		return nil, err
+	}
 	err = postProcessTrace(events)
 	if err != nil {
 		return nil, err
@@ -265,6 +269,61 @@
 	return
 }
 
+// removeFutile removes all constituents of futile wakeups (block, unblock, start).
+// For example, a goroutine was unblocked on a mutex, but another goroutine got
+// ahead and acquired the mutex before the first goroutine is scheduled,
+// so the first goroutine has to block again. Such wakeups happen on buffered
+// channels and sync.Mutex, but are generally not interesting for end user.
+func removeFutile(events []*Event) ([]*Event, error) {
+	// Two non-trivial aspects:
+	// 1. A goroutine can be preempted during a futile wakeup and migrate to another P.
+	//	We want to remove all of that.
+	// 2. Tracing can start in the middle of a futile wakeup.
+	//	That is, we can see a futile wakeup event w/o the actual wakeup before it.
+	// postProcessTrace runs after us and ensures that we leave the trace in a consistent state.
+
+	// Phase 1: determine futile wakeup sequences.
+	type G struct {
+		futile bool
+		wakeup []*Event // wakeup sequence (subject for removal)
+	}
+	gs := make(map[uint64]G)
+	futile := make(map[*Event]bool)
+	for _, ev := range events {
+		switch ev.Type {
+		case EvGoUnblock:
+			g := gs[ev.Args[0]]
+			g.wakeup = []*Event{ev}
+			gs[ev.Args[0]] = g
+		case EvGoStart, EvGoPreempt, EvFutileWakeup:
+			g := gs[ev.G]
+			g.wakeup = append(g.wakeup, ev)
+			if ev.Type == EvFutileWakeup {
+				g.futile = true
+			}
+			gs[ev.G] = g
+		case EvGoBlock, EvGoBlockSend, EvGoBlockRecv, EvGoBlockSelect, EvGoBlockSync, EvGoBlockCond:
+			g := gs[ev.G]
+			if g.futile {
+				futile[ev] = true
+				for _, ev1 := range g.wakeup {
+					futile[ev1] = true
+				}
+			}
+			delete(gs, ev.G)
+		}
+	}
+
+	// Phase 2: remove futile wakeup sequences.
+	newEvents := events[:0] // overwrite the original slice
+	for _, ev := range events {
+		if !futile[ev] {
+			newEvents = append(newEvents, ev)
+		}
+	}
+	return newEvents, nil
+}
+
 // postProcessTrace does inter-event verification and information restoration.
 // The resulting trace is guaranteed to be consistent
 // (for example, a P does not run two Gs at the same time, or a G is indeed
@@ -277,9 +336,10 @@
 		gWaiting
 	)
 	type gdesc struct {
-		state   int
-		ev      *Event
-		evStart *Event
+		state    int
+		ev       *Event
+		evStart  *Event
+		evCreate *Event
 	}
 	type pdesc struct {
 		running bool
@@ -371,7 +431,7 @@
 			if _, ok := gs[ev.Args[0]]; ok {
 				return fmt.Errorf("g %v already exists (offset %v, time %v)", ev.Args[0], ev.Off, ev.Ts)
 			}
-			gs[ev.Args[0]] = gdesc{state: gRunnable, ev: ev}
+			gs[ev.Args[0]] = gdesc{state: gRunnable, ev: ev, evCreate: ev}
 		case EvGoStart:
 			if g.state != gRunnable {
 				return fmt.Errorf("g %v is not runnable before start (offset %v, time %v)", ev.G, ev.Off, ev.Ts)
@@ -382,11 +442,13 @@
 			g.state = gRunning
 			g.evStart = ev
 			p.g = ev.G
+			if g.evCreate != nil {
+				// +1 because symblizer expects return pc.
+				ev.Stk = []*Frame{&Frame{PC: g.evCreate.Args[1] + 1}}
+				g.evCreate = nil
+			}
+
 			if g.ev != nil {
-				if g.ev.Type == EvGoCreate {
-					// +1 because symblizer expects return pc.
-					ev.Stk = []*Frame{&Frame{PC: g.ev.Args[1] + 1}}
-				}
 				g.ev.Link = ev
 				g.ev = nil
 			}
@@ -584,7 +646,7 @@
 	EvFrequency      = 2  // contains tracer timer frequency [frequency (ticks per second)]
 	EvStack          = 3  // stack [stack id, number of PCs, array of PCs]
 	EvGomaxprocs     = 4  // current value of GOMAXPROCS [timestamp, GOMAXPROCS, stack id]
-	EvProcStart      = 5  // start of P [timestamp]
+	EvProcStart      = 5  // start of P [timestamp, thread id]
 	EvProcStop       = 6  // stop of P [timestamp]
 	EvGCStart        = 7  // GC start [timestamp, stack id]
 	EvGCDone         = 8  // GC done [timestamp]
@@ -609,13 +671,14 @@
 	EvGoBlockNet     = 27 // goroutine blocks on network [timestamp, stack]
 	EvGoSysCall      = 28 // syscall enter [timestamp, stack]
 	EvGoSysExit      = 29 // syscall exit [timestamp, goroutine id]
-	EvGoSysBlock     = 30 // syscall blocks [timestamp, stack]
+	EvGoSysBlock     = 30 // syscall blocks [timestamp]
 	EvGoWaiting      = 31 // denotes that goroutine is blocked when tracing starts [goroutine id]
 	EvGoInSyscall    = 32 // denotes that goroutine is in syscall when tracing starts [goroutine id]
 	EvHeapAlloc      = 33 // memstats.heap_alloc change [timestamp, heap_alloc]
 	EvNextGC         = 34 // memstats.next_gc change [timestamp, next_gc]
 	EvTimerGoroutine = 35 // denotes timer goroutine [timer goroutine id]
-	EvCount          = 36
+	EvFutileWakeup   = 36 // denotes that the revious wakeup of this goroutine was futile [timestamp]
+	EvCount          = 37
 )
 
 var EventDescriptions = [EvCount]struct {
@@ -628,7 +691,7 @@
 	EvFrequency:      {"Frequency", false, []string{"freq"}},
 	EvStack:          {"Stack", false, []string{"id", "siz"}},
 	EvGomaxprocs:     {"Gomaxprocs", true, []string{"procs"}},
-	EvProcStart:      {"ProcStart", false, []string{}},
+	EvProcStart:      {"ProcStart", false, []string{"thread"}},
 	EvProcStop:       {"ProcStop", false, []string{}},
 	EvGCStart:        {"GCStart", true, []string{}},
 	EvGCDone:         {"GCDone", false, []string{}},
@@ -653,10 +716,11 @@
 	EvGoBlockNet:     {"GoBlockNet", true, []string{}},
 	EvGoSysCall:      {"GoSysCall", true, []string{}},
 	EvGoSysExit:      {"GoSysExit", false, []string{"g"}},
-	EvGoSysBlock:     {"GoSysBlock", true, []string{}},
+	EvGoSysBlock:     {"GoSysBlock", false, []string{}},
 	EvGoWaiting:      {"GoWaiting", false, []string{"g"}},
 	EvGoInSyscall:    {"GoInSyscall", false, []string{"g"}},
 	EvHeapAlloc:      {"HeapAlloc", false, []string{"mem"}},
 	EvNextGC:         {"NextGC", false, []string{"mem"}},
 	EvTimerGoroutine: {"TimerGoroutine", false, []string{"g"}},
+	EvFutileWakeup:   {"FutileWakeup", false, []string{}},
 }
diff --git a/src/io/pipe.go b/src/io/pipe.go
index f65354a..179515e 100644
--- a/src/io/pipe.go
+++ b/src/io/pipe.go
@@ -168,7 +168,10 @@
 }
 
 // CloseWithError closes the writer; subsequent reads from the
-// read half of the pipe will return no bytes and the error err.
+// read half of the pipe will return no bytes and the error err,
+// or EOF if err is nil.
+//
+// CloseWithError always returns nil.
 func (w *PipeWriter) CloseWithError(err error) error {
 	w.p.wclose(err)
 	return nil
diff --git a/src/iostest.bash b/src/iostest.bash
new file mode 100755
index 0000000..13f5e0c
--- /dev/null
+++ b/src/iostest.bash
@@ -0,0 +1,58 @@
+#!/usr/bin/env bash
+# Copyright 2015 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.
+
+# For testing darwin/arm{,64} on iOS.
+
+set -e
+ulimit -c 0 # no core files
+
+if [ ! -f make.bash ]; then
+	echo 'iostest.bash must be run from $GOROOT/src' 1>&2
+	exit 1
+fi
+
+if [ -z $GOOS ]; then
+	export GOOS=darwin
+fi
+if [ "$GOOS" != "darwin" ]; then
+	echo "iostest.bash requires GOOS=darwin, got GOOS=$GOOS" 1>&2
+	exit 1
+fi
+if [ "$GOARCH" == "arm" ]; then
+	export GOARM=7
+fi
+
+# Reboot to make sure previous runs do not interfere with the current run.
+# It is reasonably easy for a bad program leave an iOS device in an
+# almost unusable state.
+idevicediagnostics restart
+# Initial sleep to make sure we are restarting before we start polling.
+sleep 30
+# Poll until the device has restarted.
+until idevicediagnostics diagnostics; do
+	# TODO(crawshaw): replace with a test app using go_darwin_arm_exec.
+	echo "waiting for idevice to come online"
+	sleep 10
+done
+# Diagnostics are reported during boot before the device can start an
+# app. Wait a little longer before trying to use the device.
+sleep 30
+
+unset GOBIN
+export GOROOT=$(dirname $(pwd))
+export PATH=$GOROOT/bin:$PATH
+export CGO_ENABLED=1
+export CC_FOR_TARGET=$GOROOT/misc/ios/clangwrap.sh
+
+# Run the build for the host bootstrap, so we can build go_darwin_arm_exec.
+# Also lets us fail early before the (slow) adb push if the build is broken.
+./make.bash
+
+GOOS=$GOHOSTOS GOARCH=$GOHOSTARCH go build \
+	-o ../bin/go_darwin_${GOARCH}_exec \
+	../misc/ios/go_darwin_arm_exec.go
+
+# Run standard build and tests.
+./all.bash --no-clean
diff --git a/src/log/syslog/syslog_test.go b/src/log/syslog/syslog_test.go
index 6a863fe..7f7d7fd 100644
--- a/src/log/syslog/syslog_test.go
+++ b/src/log/syslog/syslog_test.go
@@ -14,6 +14,7 @@
 	"log"
 	"net"
 	"os"
+	"runtime"
 	"sync"
 	"testing"
 	"time"
@@ -120,6 +121,10 @@
 	msg := "Test 123"
 	transport := []string{"unix", "unixgram", "udp", "tcp"}
 
+	if runtime.GOOS == "darwin" && runtime.GOARCH == "arm" {
+		transport = []string{"udp", "tcp"}
+	}
+
 	for _, tr := range transport {
 		done := make(chan string)
 		addr, sock, srvWG := startServer(tr, "", done)
@@ -142,6 +147,10 @@
 }
 
 func TestFlap(t *testing.T) {
+	if runtime.GOOS == "darwin" && runtime.GOARCH == "arm" {
+		t.Skipf("skipping on %s/%s", runtime.GOOS, runtime.GOARCH)
+	}
+
 	net := "unix"
 	done := make(chan string)
 	addr, sock, srvWG := startServer(net, "", done)
@@ -306,9 +315,14 @@
 	const N = 10
 	const M = 100
 	net := "unix"
+	if runtime.GOOS == "darwin" && runtime.GOARCH == "arm" {
+		net = "tcp"
+	}
 	done := make(chan string, N*M)
 	addr, sock, srvWG := startServer(net, "", done)
-	defer os.Remove(addr)
+	if net == "unix" {
+		defer os.Remove(addr)
+	}
 
 	// count all the messages arriving
 	count := make(chan int)
diff --git a/src/make.bat b/src/make.bat
index 7056955..dca7f66 100644
--- a/src/make.bat
+++ b/src/make.bat
@@ -25,6 +25,12 @@
 :: CGO_ENABLED: Controls cgo usage during the build. Set it to 1
 :: to include all cgo related files, .c and .go file with "cgo"
 :: build directive, in the build. Set it to 0 to ignore them.
+::
+:: CC: Command line to run to compile C code for GOHOSTARCH.
+:: Default is "gcc".
+::
+:: CC_FOR_TARGET: Command line to run compile C code for GOARCH.
+:: This is used by cgo. Default is CC.
 
 @echo off
 
@@ -84,7 +90,9 @@
 goto mainbuild
 
 :localbuild
-echo ##### Building tools for local system. %GOHOSTOS%/%GOHOSTARCH%
+echo ##### Building packages and commands for host, %GOHOSTOS%/%GOHOSTARCH%.
+:: CC_FOR_TARGET is recorded as the default compiler for the go tool. When building for the
+:: host, however, use the host compiler, CC, from `cmd/dist/dist env` instead.
 setlocal
 set GOOS=%GOHOSTOS%
 set GOARCH=%GOHOSTARCH%
@@ -94,8 +102,11 @@
 echo.
 
 :mainbuild
-echo ##### Building packages and commands.
+echo ##### Building packages and commands for %GOOS%/%GOARCH%.
+setlocal
+set CC=%CC_FOR_TARGET%
 "%GOTOOLDIR%\go_bootstrap" install -gcflags "%GO_GCFLAGS%" -ldflags "%GO_LDFLAGS%" -a -v std cmd
+endlocal
 if errorlevel 1 goto fail
 del "%GOTOOLDIR%\go_bootstrap.exe"
 echo.
diff --git a/src/math/abs_arm64.s b/src/math/abs_arm64.s
new file mode 100644
index 0000000..d8f9382
--- /dev/null
+++ b/src/math/abs_arm64.s
@@ -0,0 +1,11 @@
+// Copyright 2011 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.
+
+#include "textflag.h"
+
+TEXT ·Abs(SB),NOSPLIT,$0-16
+	FMOVD	x+0(FP), F3
+	FABSD	F3, F3
+	FMOVD	F3, ret+8(FP)
+	RET
diff --git a/src/math/big/accuracy_string.go b/src/math/big/accuracy_string.go
new file mode 100644
index 0000000..24ef7f1
--- /dev/null
+++ b/src/math/big/accuracy_string.go
@@ -0,0 +1,17 @@
+// generated by stringer -type=Accuracy; DO NOT EDIT
+
+package big
+
+import "fmt"
+
+const _Accuracy_name = "BelowExactAbove"
+
+var _Accuracy_index = [...]uint8{0, 5, 10, 15}
+
+func (i Accuracy) String() string {
+	i -= -1
+	if i < 0 || i+1 >= Accuracy(len(_Accuracy_index)) {
+		return fmt.Sprintf("Accuracy(%d)", i+-1)
+	}
+	return _Accuracy_name[_Accuracy_index[i]:_Accuracy_index[i+1]]
+}
diff --git a/src/math/big/arith_386.s b/src/math/big/arith_386.s
index eb17bc1..7c8ab8f 100644
--- a/src/math/big/arith_386.s
+++ b/src/math/big/arith_386.s
@@ -2,6 +2,8 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
+// +build !math_big_pure_go
+
 #include "textflag.h"
 
 // This file provides fast assembly versions for the elementary
diff --git a/src/math/big/arith_amd64.s b/src/math/big/arith_amd64.s
index bb06e69..d2d5187 100644
--- a/src/math/big/arith_amd64.s
+++ b/src/math/big/arith_amd64.s
@@ -2,6 +2,8 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
+// +build !math_big_pure_go
+
 #include "textflag.h"
 
 // This file provides fast assembly versions for the elementary
diff --git a/src/math/big/arith_amd64p32.s b/src/math/big/arith_amd64p32.s
index 908dbbd..8610e90 100644
--- a/src/math/big/arith_amd64p32.s
+++ b/src/math/big/arith_amd64p32.s
@@ -2,6 +2,8 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
+// +build !math_big_pure_go
+
 #include "textflag.h"
 
 TEXT ·mulWW(SB),NOSPLIT,$0
diff --git a/src/math/big/arith_arm.s b/src/math/big/arith_arm.s
index a4c51c2..69590ff 100644
--- a/src/math/big/arith_arm.s
+++ b/src/math/big/arith_arm.s
@@ -2,6 +2,8 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
+// +build !math_big_pure_go
+
 #include "textflag.h"
 
 // This file provides fast assembly versions for the elementary
diff --git a/src/math/big/arith_arm64.s b/src/math/big/arith_arm64.s
new file mode 100644
index 0000000..6e10e47
--- /dev/null
+++ b/src/math/big/arith_arm64.s
@@ -0,0 +1,46 @@
+// Copyright 2013 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.
+
+// +build !math_big_pure_go
+
+#include "textflag.h"
+
+// This file provides fast assembly versions for the elementary
+// arithmetic operations on vectors implemented in arith.go.
+
+TEXT ·mulWW(SB),NOSPLIT,$0
+	B ·mulWW_g(SB)
+
+TEXT ·divWW(SB),NOSPLIT,$0
+	B ·divWW_g(SB)
+
+TEXT ·addVV(SB),NOSPLIT,$0
+	B ·addVV_g(SB)
+
+TEXT ·subVV(SB),NOSPLIT,$0
+	B ·subVV_g(SB)
+
+TEXT ·addVW(SB),NOSPLIT,$0
+	B ·addVW_g(SB)
+
+TEXT ·subVW(SB),NOSPLIT,$0
+	B ·subVW_g(SB)
+
+TEXT ·shlVU(SB),NOSPLIT,$0
+	B ·shlVU_g(SB)
+
+TEXT ·shrVU(SB),NOSPLIT,$0
+	B ·shrVU_g(SB)
+
+TEXT ·mulAddVWW(SB),NOSPLIT,$0
+	B ·mulAddVWW_g(SB)
+
+TEXT ·addMulVVW(SB),NOSPLIT,$0
+	B ·addMulVVW_g(SB)
+
+TEXT ·divWVW(SB),NOSPLIT,$0
+	B ·divWVW_g(SB)
+
+TEXT ·bitLen(SB),NOSPLIT,$0
+	B ·bitLen_g(SB)
diff --git a/src/math/big/arith_decl.go b/src/math/big/arith_decl.go
index 068cc8d..1707aa4 100644
--- a/src/math/big/arith_decl.go
+++ b/src/math/big/arith_decl.go
@@ -2,6 +2,8 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
+// +build !math_big_pure_go
+
 package big
 
 // implemented in arith_$GOARCH.s
diff --git a/src/math/big/arith_decl_pure.go b/src/math/big/arith_decl_pure.go
new file mode 100644
index 0000000..e760a38
--- /dev/null
+++ b/src/math/big/arith_decl_pure.go
@@ -0,0 +1,55 @@
+// Copyright 2015 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.
+
+// +build math_big_pure_go
+
+package big
+
+func mulWW(x, y Word) (z1, z0 Word) {
+	return mulWW_g(x, y)
+}
+
+func divWW(x1, x0, y Word) (q, r Word) {
+	return divWW_g(x1, x0, y)
+}
+
+func addVV(z, x, y []Word) (c Word) {
+	return addVV_g(z, x, y)
+}
+
+func subVV(z, x, y []Word) (c Word) {
+	return subVV_g(z, x, y)
+}
+
+func addVW(z, x []Word, y Word) (c Word) {
+	return addVW_g(z, x, y)
+}
+
+func subVW(z, x []Word, y Word) (c Word) {
+	return subVW_g(z, x, y)
+}
+
+func shlVU(z, x []Word, s uint) (c Word) {
+	return shlVU_g(z, x, s)
+}
+
+func shrVU(z, x []Word, s uint) (c Word) {
+	return shrVU_g(z, x, s)
+}
+
+func mulAddVWW(z, x []Word, y, r Word) (c Word) {
+	return mulAddVWW_g(z, x, y, r)
+}
+
+func addMulVVW(z, x []Word, y Word) (c Word) {
+	return addMulVVW_g(z, x, y)
+}
+
+func divWVW(z []Word, xn Word, x []Word, y Word) (r Word) {
+	return divWVW_g(z, xn, x, y)
+}
+
+func bitLen(x Word) (n int) {
+	return bitLen_g(x)
+}
diff --git a/src/math/big/arith_ppc64x.s b/src/math/big/arith_ppc64x.s
index 0cbd126..d4d4171 100644
--- a/src/math/big/arith_ppc64x.s
+++ b/src/math/big/arith_ppc64x.s
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// +build ppc64 ppc64le
+// +build !math_big_pure_go,ppc64 !math_big_pure_go,ppc64le
 
 #include "textflag.h"
 
diff --git a/src/math/big/bits_test.go b/src/math/big/bits_test.go
new file mode 100644
index 0000000..3ce2422
--- /dev/null
+++ b/src/math/big/bits_test.go
@@ -0,0 +1,224 @@
+// Copyright 2015 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.
+
+// This file implements the Bits type used for testing Float operations
+// via an independent (albeit slower) representations for floating-point
+// numbers.
+
+package big
+
+import (
+	"fmt"
+	"sort"
+	"testing"
+)
+
+// A Bits value b represents a finite floating-point number x of the form
+//
+//	x = 2**b[0] + 2**b[1] + ... 2**b[len(b)-1]
+//
+// The order of slice elements is not significant. Negative elements may be
+// used to form fractions. A Bits value is normalized if each b[i] occurs at
+// most once. For instance Bits{0, 0, 1} is not normalized but represents the
+// same floating-point number as Bits{2}, which is normalized. The zero (nil)
+// value of Bits is a ready to use Bits value and represents the value 0.
+type Bits []int
+
+func (x Bits) add(y Bits) Bits {
+	return append(x, y...)
+}
+
+func (x Bits) mul(y Bits) Bits {
+	var p Bits
+	for _, x := range x {
+		for _, y := range y {
+			p = append(p, x+y)
+		}
+	}
+	return p
+}
+
+func TestMulBits(t *testing.T) {
+	for _, test := range []struct {
+		x, y, want Bits
+	}{
+		{nil, nil, nil},
+		{Bits{}, Bits{}, nil},
+		{Bits{0}, Bits{0}, Bits{0}},
+		{Bits{0}, Bits{1}, Bits{1}},
+		{Bits{1}, Bits{1, 2, 3}, Bits{2, 3, 4}},
+		{Bits{-1}, Bits{1}, Bits{0}},
+		{Bits{-10, -1, 0, 1, 10}, Bits{1, 2, 3}, Bits{-9, -8, -7, 0, 1, 2, 1, 2, 3, 2, 3, 4, 11, 12, 13}},
+	} {
+		got := fmt.Sprintf("%v", test.x.mul(test.y))
+		want := fmt.Sprintf("%v", test.want)
+		if got != want {
+			t.Errorf("%v * %v = %s; want %s", test.x, test.y, got, want)
+		}
+
+	}
+}
+
+// norm returns the normalized bits for x: It removes multiple equal entries
+// by treating them as an addition (e.g., Bits{5, 5} => Bits{6}), and it sorts
+// the result list for reproducible results.
+func (x Bits) norm() Bits {
+	m := make(map[int]bool)
+	for _, b := range x {
+		for m[b] {
+			m[b] = false
+			b++
+		}
+		m[b] = true
+	}
+	var z Bits
+	for b, set := range m {
+		if set {
+			z = append(z, b)
+		}
+	}
+	sort.Ints([]int(z))
+	return z
+}
+
+func TestNormBits(t *testing.T) {
+	for _, test := range []struct {
+		x, want Bits
+	}{
+		{nil, nil},
+		{Bits{}, Bits{}},
+		{Bits{0}, Bits{0}},
+		{Bits{0, 0}, Bits{1}},
+		{Bits{3, 1, 1}, Bits{2, 3}},
+		{Bits{10, 9, 8, 7, 6, 6}, Bits{11}},
+	} {
+		got := fmt.Sprintf("%v", test.x.norm())
+		want := fmt.Sprintf("%v", test.want)
+		if got != want {
+			t.Errorf("normBits(%v) = %s; want %s", test.x, got, want)
+		}
+
+	}
+}
+
+// round returns the Float value corresponding to x after rounding x
+// to prec bits according to mode.
+func (x Bits) round(prec uint, mode RoundingMode) *Float {
+	x = x.norm()
+
+	// determine range
+	var min, max int
+	for i, b := range x {
+		if i == 0 || b < min {
+			min = b
+		}
+		if i == 0 || b > max {
+			max = b
+		}
+	}
+	prec0 := uint(max + 1 - min)
+	if prec >= prec0 {
+		return x.Float()
+	}
+	// prec < prec0
+
+	// determine bit 0, rounding, and sticky bit, and result bits z
+	var bit0, rbit, sbit uint
+	var z Bits
+	r := max - int(prec)
+	for _, b := range x {
+		switch {
+		case b == r:
+			rbit = 1
+		case b < r:
+			sbit = 1
+		default:
+			// b > r
+			if b == r+1 {
+				bit0 = 1
+			}
+			z = append(z, b)
+		}
+	}
+
+	// round
+	f := z.Float() // rounded to zero
+	if mode == ToNearestAway {
+		panic("not yet implemented")
+	}
+	if mode == ToNearestEven && rbit == 1 && (sbit == 1 || sbit == 0 && bit0 != 0) || mode == AwayFromZero {
+		// round away from zero
+		f.SetMode(ToZero).SetPrec(prec)
+		f.Add(f, Bits{int(r) + 1}.Float())
+	}
+	return f
+}
+
+// Float returns the *Float z of the smallest possible precision such that
+// z = sum(2**bits[i]), with i = range bits. If multiple bits[i] are equal,
+// they are added: Bits{0, 1, 0}.Float() == 2**0 + 2**1 + 2**0 = 4.
+func (bits Bits) Float() *Float {
+	// handle 0
+	if len(bits) == 0 {
+		return new(Float)
+	}
+	// len(bits) > 0
+
+	// determine lsb exponent
+	var min int
+	for i, b := range bits {
+		if i == 0 || b < min {
+			min = b
+		}
+	}
+
+	// create bit pattern
+	x := NewInt(0)
+	for _, b := range bits {
+		badj := b - min
+		// propagate carry if necessary
+		for x.Bit(badj) != 0 {
+			x.SetBit(x, badj, 0)
+			badj++
+		}
+		x.SetBit(x, badj, 1)
+	}
+
+	// create corresponding float
+	z := new(Float).SetInt(x) // normalized
+	if e := int64(z.exp) + int64(min); MinExp <= e && e <= MaxExp {
+		z.exp = int32(e)
+	} else {
+		// this should never happen for our test cases
+		panic("exponent out of range")
+	}
+	return z
+}
+
+func TestFromBits(t *testing.T) {
+	for _, test := range []struct {
+		bits Bits
+		want string
+	}{
+		// all different bit numbers
+		{nil, "0"},
+		{Bits{0}, "0x.8p1"},
+		{Bits{1}, "0x.8p2"},
+		{Bits{-1}, "0x.8p0"},
+		{Bits{63}, "0x.8p64"},
+		{Bits{33, -30}, "0x.8000000000000001p34"},
+		{Bits{255, 0}, "0x.8000000000000000000000000000000000000000000000000000000000000001p256"},
+
+		// multiple equal bit numbers
+		{Bits{0, 0}, "0x.8p2"},
+		{Bits{0, 0, 0, 0}, "0x.8p3"},
+		{Bits{0, 1, 0}, "0x.8p3"},
+		{append(Bits{2, 1, 0} /* 7 */, Bits{3, 1} /* 10 */ ...), "0x.88p5" /* 17 */},
+	} {
+		f := test.bits.Float()
+		if got := f.Format('p', 0); got != test.want {
+			t.Errorf("setBits(%v) = %s; want %s", test.bits, got, test.want)
+		}
+	}
+}
diff --git a/src/math/big/decimal.go b/src/math/big/decimal.go
index 670668b..3d024dc 100644
--- a/src/math/big/decimal.go
+++ b/src/math/big/decimal.go
@@ -37,6 +37,9 @@
 // precision argument and keeping track of when a number was truncated early
 // (equivalent of "sticky bit" in binary rounding).
 
+// TODO(gri) Along the same lines, enforce some limit to shift magnitudes
+// to avoid "infinitely" long running conversions (until we run out of space).
+
 // Init initializes x to the decimal representation of m << shift (for
 // shift >= 0), or m >> -shift (for shift < 0).
 func (x *decimal) init(m nat, shift int) {
diff --git a/src/math/big/float.go b/src/math/big/float.go
index c1a1979..2e536e0 100644
--- a/src/math/big/float.go
+++ b/src/math/big/float.go
@@ -9,8 +9,6 @@
 // rounding mode of the result operand determines the rounding
 // mode of an operation. This is a from-scratch implementation.
 
-// CAUTION: WORK IN PROGRESS - USE AT YOUR OWN RISK.
-
 package big
 
 import (
@@ -20,105 +18,107 @@
 
 const debugFloat = true // enable for debugging
 
-// A Float represents a multi-precision floating point number of the form
+// A nonzero finite Float represents a multi-precision floating point number
 //
 //   sign × mantissa × 2**exponent
 //
-// with 0.5 <= mantissa < 1.0, and MinExp <= exponent <= MaxExp (with the
-// exception of 0 and Inf which have a 0 mantissa and special exponents).
+// with 0.5 <= mantissa < 1.0, and MinExp <= exponent <= MaxExp.
+// A Float may also be zero (+0, -0) or infinite (+Inf, -Inf).
+// All Floats are ordered, and the ordering of two Floats x and y
+// is defined by x.Cmp(y).
 //
 // Each Float value also has a precision, rounding mode, and accuracy.
-//
 // The precision is the maximum number of mantissa bits available to
 // represent the value. The rounding mode specifies how a result should
 // be rounded to fit into the mantissa bits, and accuracy describes the
 // rounding error with respect to the exact result.
 //
-// All operations, including setters, that specify a *Float variable for
-// the result (usually via the receiver with the exception of MantExp),
-// round the numeric result according to the precision and rounding mode
-// of the result variable, unless specified otherwise.
+// Unless specified otherwise, all operations (including setters) that
+// specify a *Float variable for the result (usually via the receiver
+// with the exception of MantExp), round the numeric result according
+// to the precision and rounding mode of the result variable.
 //
-// If the result precision is 0 (see below), it is set to the precision of
-// the argument with the largest precision value before any rounding takes
-// place, and the rounding mode remains unchanged. Thus, uninitialized Floats
-// provided as result arguments will have their precision set to a reasonable
-// value determined by the operands and their mode is the zero value for
-// RoundingMode (ToNearestEven).
+// If the provided result precision is 0 (see below), it is set to the
+// precision of the argument with the largest precision value before any
+// rounding takes place, and the rounding mode remains unchanged. Thus,
+// uninitialized Floats provided as result arguments will have their
+// precision set to a reasonable value determined by the operands and
+// their mode is the zero value for RoundingMode (ToNearestEven).
 //
 // By setting the desired precision to 24 or 53 and using matching rounding
 // mode (typically ToNearestEven), Float operations produce the same results
-// as the corresponding float32 or float64 IEEE-754 arithmetic for normalized
-// operands (no NaNs or denormalized numbers). Additionally, positive and
-// negative zeros and infinities are fully supported.
+// as the corresponding float32 or float64 IEEE-754 arithmetic for operands
+// that correspond to normal (i.e., not denormal) float32 or float64 numbers.
+// Exponent underflow and overflow lead to a 0 or an Infinity for different
+// values than IEEE-754 because Float exponents have a much larger range.
 //
 // The zero (uninitialized) value for a Float is ready to use and represents
 // the number +0.0 exactly, with precision 0 and rounding mode ToNearestEven.
 //
 type Float struct {
+	prec uint32
 	mode RoundingMode
 	acc  Accuracy
+	form form
 	neg  bool
 	mant nat
 	exp  int32
-	prec uint32
 }
 
-// TODO(gri) provide a couple of Example tests showing typical Float intialization
-// and use.
+// Float operations that would lead to a NaN under IEEE-754 rules cause
+// a run-time panic of ErrNaN type.
+type ErrNaN struct {
+	msg string
+}
 
-// Internal representation: The mantissa bits x.mant of a Float x are stored
-// in a nat slice long enough to hold up to x.prec bits; the slice may (but
-// doesn't have to) be shorter if the mantissa contains trailing 0 bits.
-// Unless x is a zero or an infinity, x.mant is normalized such that the
-// msb of x.mant == 1 (i.e., the msb is shifted all the way "to the left").
-// Thus, if the mantissa has trailing 0 bits or x.prec is not a multiple
-// of the the Word size _W, x.mant[0] has trailing zero bits. Zero and Inf
-// values have an empty mantissa and a 0 or infExp exponent, respectively.
+// NewFloat allocates and returns a new Float set to x,
+// with precision 53 and rounding mode ToNearestEven.
+// NewFloat panics with ErrNan if x is a NaN.
+func NewFloat(x float64) *Float {
+	if math.IsNaN(x) {
+		panic(ErrNaN{"NewFloat(NaN)"})
+	}
+	return new(Float).SetFloat64(x)
+}
 
+// Exponent and precision limits.
 const (
-	MaxExp  = math.MaxInt32  // largest supported exponent magnitude
-	infExp  = -MaxExp - 1    // exponent for Inf values
+	MaxExp  = math.MaxInt32  // largest supported exponent
+	MinExp  = math.MinInt32  // smallest supported exponent
 	MaxPrec = math.MaxUint32 // largest (theoretically) supported precision; likely memory-limited
 )
 
-// NewInf returns a new infinite Float value with value +Inf (sign >= 0),
-// or -Inf (sign < 0).
-func NewInf(sign int) *Float {
-	return &Float{neg: sign < 0, exp: infExp}
-}
-
-// Accuracy describes the rounding error produced by the most recent
-// operation that generated a Float value, relative to the exact value:
+// Internal representation: The mantissa bits x.mant of a nonzero finite
+// Float x are stored in a nat slice long enough to hold up to x.prec bits;
+// the slice may (but doesn't have to) be shorter if the mantissa contains
+// trailing 0 bits. x.mant is normalized if the msb of x.mant == 1 (i.e.,
+// the msb is shifted all the way "to the left"). Thus, if the mantissa has
+// trailing 0 bits or x.prec is not a multiple of the the Word size _W,
+// x.mant[0] has trailing zero bits. The msb of the mantissa corresponds
+// to the value 0.5; the exponent x.exp shifts the binary point as needed.
 //
-//  -1: below exact value
-//   0: exact value
-//  +1: above exact value
+// A zero or non-finite Float x ignores x.mant and x.exp.
 //
-type Accuracy int8
+// x                 form      neg      mant         exp
+// ----------------------------------------------------------
+// ±0                zero      sign     -            -
+// 0 < |x| < +Inf    finite    sign     mantissa     exponent
+// ±Inf              inf       sign     -            -
 
-// Constants describing the Accuracy of a Float.
+// A form value describes the internal representation.
+type form byte
+
+// The form value order is relevant - do not change!
 const (
-	Below Accuracy = -1
-	Exact Accuracy = 0
-	Above Accuracy = +1
+	zero form = iota
+	finite
+	inf
 )
 
-func (a Accuracy) String() string {
-	switch {
-	case a < 0:
-		return "below"
-	default:
-		return "exact"
-	case a > 0:
-		return "above"
-	}
-}
-
 // RoundingMode determines how a Float value is rounded to the
 // desired precision. Rounding may change the Float value; the
 // rounding error is described by the Float's Accuracy.
-type RoundingMode uint8
+type RoundingMode byte
 
 // The following rounding modes are supported.
 const (
@@ -130,46 +130,40 @@
 	ToPositiveInf                     // == IEEE 754-2008 roundTowardPositive
 )
 
-func (mode RoundingMode) String() string {
-	switch mode {
-	case ToNearestEven:
-		return "ToNearestEven"
-	case ToNearestAway:
-		return "ToNearestAway"
-	case ToZero:
-		return "ToZero"
-	case AwayFromZero:
-		return "AwayFromZero"
-	case ToNegativeInf:
-		return "ToNegativeInf"
-	case ToPositiveInf:
-		return "ToPositiveInf"
-	}
-	panic("unreachable")
-}
+//go:generate stringer -type=RoundingMode
+
+// Accuracy describes the rounding error produced by the most recent
+// operation that generated a Float value, relative to the exact value.
+type Accuracy int8
+
+// Constants describing the Accuracy of a Float.
+const (
+	Below Accuracy = -1
+	Exact Accuracy = 0
+	Above Accuracy = +1
+)
+
+//go:generate stringer -type=Accuracy
 
 // SetPrec sets z's precision to prec and returns the (possibly) rounded
 // value of z. Rounding occurs according to z's rounding mode if the mantissa
 // cannot be represented in prec bits without loss of precision.
-// If prec == 0, the result is ±0 for finite z, and ±Inf for infinite z,
-// with the sign set according to z. If prec > MaxPrec, it is set to MaxPrec.
+// SetPrec(0) maps all finite values to ±0; infinite values remain unchanged.
+// If prec > MaxPrec, it is set to MaxPrec.
 func (z *Float) SetPrec(prec uint) *Float {
 	z.acc = Exact // optimistically assume no rounding is needed
-	// handle special case
+
+	// special case
 	if prec == 0 {
 		z.prec = 0
-		if len(z.mant) != 0 {
-			// truncate and compute accuracy
-			z.mant = z.mant[:0]
-			z.exp = 0
-			acc := Below
-			if z.neg {
-				acc = Above
-			}
-			z.acc = acc
+		if z.form == finite {
+			// truncate z to 0
+			z.acc = makeAcc(z.neg)
+			z.form = zero
 		}
 		return z
 	}
+
 	// general case
 	if prec > MaxPrec {
 		prec = MaxPrec
@@ -182,154 +176,193 @@
 	return z
 }
 
+func makeAcc(above bool) Accuracy {
+	if above {
+		return Above
+	}
+	return Below
+}
+
 // SetMode sets z's rounding mode to mode and returns an exact z.
 // z remains unchanged otherwise.
+// z.SetMode(z.Mode()) is a cheap way to set z's accuracy to Exact.
 func (z *Float) SetMode(mode RoundingMode) *Float {
-	z.acc = Exact // TODO(gri) should we not do this? what's the general rule for setting accuracy?
 	z.mode = mode
+	z.acc = Exact
 	return z
 }
 
 // Prec returns the mantissa precision of x in bits.
-// The result may be 0 for |x| == 0 or |x| == Inf.
+// The result may be 0 for |x| == 0 and |x| == Inf.
 func (x *Float) Prec() uint {
 	return uint(x.prec)
 }
 
 // MinPrec returns the minimum precision required to represent x exactly
 // (i.e., the smallest prec before x.SetPrec(prec) would start rounding x).
-// The result is 0 for ±0 and ±Inf.
+// The result is 0 for |x| == 0 and |x| == Inf.
 func (x *Float) MinPrec() uint {
+	if x.form != finite {
+		return 0
+	}
 	return uint(len(x.mant))*_W - x.mant.trailingZeroBits()
 }
 
-// Acc returns the accuracy of x produced by the most recent operation.
-func (x *Float) Acc() Accuracy {
-	return x.acc
-}
-
 // Mode returns the rounding mode of x.
 func (x *Float) Mode() RoundingMode {
 	return x.mode
 }
 
-// Sign returns:
-//
-//	-1 if x <  0
-//	 0 if x == 0 or x == -0
-//	+1 if x >  0
-//
-func (x *Float) Sign() int {
-	s := 0
-	if len(x.mant) != 0 || x.exp == infExp {
-		s = 1 // non-zero x
-	}
-	if x.neg {
-		s = -s
-	}
-	return s
+// Acc returns the accuracy of x produced by the most recent operation.
+func (x *Float) Acc() Accuracy {
+	return x.acc
 }
 
-// MantExp breaks x into its mantissa and exponent components.
-// It returns mant and exp satisfying x == mant × 2**exp, with
-// the absolute value of mant satisfying 0.5 <= |mant| < 1.0.
-// mant has the same precision and rounding mode as x.
-// If a non-nil *Float argument z is provided, MantExp stores
-// the result mant in z instead of allocating a new Float.
+// Sign returns:
+//
+//	-1 if x <   0
+//	 0 if x is ±0
+//	+1 if x >   0
+//
+func (x *Float) Sign() int {
+	if debugFloat {
+		x.validate()
+	}
+	if x.form == zero {
+		return 0
+	}
+	if x.neg {
+		return -1
+	}
+	return 1
+}
+
+// MantExp breaks x into its mantissa and exponent components
+// and returns the exponent. If a non-nil mant argument is
+// provided its value is set to the mantissa of x, with the
+// same precision and rounding mode as x. The components
+// satisfy x == mant × 2**exp, with 0.5 <= |mant| < 1.0.
+// Calling MantExp with a nil argument is an efficient way to
+// get the exponent of the receiver.
 //
 // Special cases are:
 //
-//	(  ±0).MantExp() =   ±0, 0
-//	(±Inf).MantExp() = ±Inf, 0
+//	(  ±0).MantExp(mant) = 0, with mant set to   ±0
+//	(±Inf).MantExp(mant) = 0, with mant set to ±Inf
 //
-// MantExp does not modify x; the result mant is a new Float.
-func (x *Float) MantExp(z *Float) (mant *Float, exp int) {
-	if z == nil {
-		z = new(Float)
+// x and mant may be the same in which case x is set to its
+// mantissa value.
+func (x *Float) MantExp(mant *Float) (exp int) {
+	if debugFloat {
+		x.validate()
 	}
-	mant = z.Copy(x)
-	if x.exp != infExp {
+	if x.form == finite {
 		exp = int(x.exp)
-		mant.exp = 0 // after reading x.exp (x and mant may be aliases)
+	}
+	if mant != nil {
+		mant.Copy(x)
+		if mant.form == finite {
+			mant.exp = 0
+		}
 	}
 	return
 }
 
+func (z *Float) setExpAndRound(exp int64, sbit uint) {
+	if exp < MinExp {
+		// underflow
+		z.acc = makeAcc(z.neg)
+		z.form = zero
+		return
+	}
+
+	if exp > MaxExp {
+		// overflow
+		z.acc = makeAcc(!z.neg)
+		z.form = inf
+		return
+	}
+
+	z.form = finite
+	z.exp = int32(exp)
+	z.round(sbit)
+}
+
 // SetMantExp sets z to mant × 2**exp and and returns z.
 // The result z has the same precision and rounding mode
 // as mant. SetMantExp is an inverse of MantExp but does
 // not require 0.5 <= |mant| < 1.0. Specifically:
 //
-//	new(Float).SetMantExp(x.MantExp()).Cmp(x) == 0
+//	mant := new(Float)
+//	new(Float).SetMantExp(mant, x.SetMantExp(mant)).Cmp(x).Eql() is true
 //
 // Special cases are:
 //
 //	z.SetMantExp(  ±0, exp) =   ±0
 //	z.SetMantExp(±Inf, exp) = ±Inf
 //
+// z and mant may be the same in which case z's exponent
+// is set to exp.
 func (z *Float) SetMantExp(mant *Float, exp int) *Float {
+	if debugFloat {
+		z.validate()
+		mant.validate()
+	}
 	z.Copy(mant)
-	if len(z.mant) == 0 || z.exp == infExp {
+	if z.form != finite {
 		return z
 	}
-	z.setExp(int64(z.exp) + int64(exp))
+	z.setExpAndRound(int64(z.exp)+int64(exp), 0)
 	return z
 }
 
+// Signbit returns true if x is negative or negative zero.
+func (x *Float) Signbit() bool {
+	return x.neg
+}
+
+// IsInf reports whether x is +Inf or -Inf.
+func (x *Float) IsInf() bool {
+	return x.form == inf
+}
+
 // IsInt reports whether x is an integer.
-// ±Inf are not considered integers.
+// ±Inf values are not integers.
 func (x *Float) IsInt() bool {
 	if debugFloat {
-		validate(x)
+		x.validate()
 	}
-	// pick off easy cases
+	// special cases
+	if x.form != finite {
+		return x.form == zero
+	}
+	// x.form == finite
 	if x.exp <= 0 {
-		// |x| < 1 || |x| == Inf
-		return len(x.mant) == 0 && x.exp != infExp
+		return false
 	}
 	// x.exp > 0
 	return x.prec <= uint32(x.exp) || x.MinPrec() <= uint(x.exp) // not enough bits for fractional mantissa
 }
 
-// IsInf reports whether x is an infinity, according to sign.
-// If sign > 0, IsInf reports whether x is positive infinity.
-// If sign < 0, IsInf reports whether x is negative infinity.
-// If sign == 0, IsInf reports whether x is either infinity.
-func (x *Float) IsInf(sign int) bool {
-	return x.exp == infExp && (sign == 0 || x.neg == (sign < 0))
-}
-
-// setExp sets the exponent for z.
-// If the exponent's magnitude is too large, z becomes ±Inf.
-func (z *Float) setExp(e int64) {
-	if -MaxExp <= e && e <= MaxExp {
-		if len(z.mant) == 0 {
-			e = 0
-		}
-		z.exp = int32(e)
+// debugging support
+func (x *Float) validate() {
+	if !debugFloat {
+		// avoid performance bugs
+		panic("validate called but debugFloat is not set")
+	}
+	if x.form != finite {
 		return
 	}
-	// Inf
-	z.mant = z.mant[:0]
-	z.exp = infExp
-}
-
-// debugging support
-func validate(x *Float) {
-	const msb = 1 << (_W - 1)
 	m := len(x.mant)
 	if m == 0 {
-		// 0.0 or Inf
-		if x.exp != 0 && x.exp != infExp {
-			panic(fmt.Sprintf("empty matissa with invalid exponent %d", x.exp))
-		}
-		return
+		panic("nonzero finite number with empty mantissa")
 	}
+	const msb = 1 << (_W - 1)
 	if x.mant[m-1]&msb == 0 {
 		panic(fmt.Sprintf("msb not set in last word %#x of %s", x.mant[m-1], x.Format('p', 0)))
 	}
-	if x.prec <= 0 {
-		panic(fmt.Sprintf("invalid precision %d", x.prec))
+	if x.prec == 0 {
+		panic("zero precision finite number")
 	}
 }
 
@@ -343,22 +376,22 @@
 // calling round.
 func (z *Float) round(sbit uint) {
 	if debugFloat {
-		validate(z)
+		z.validate()
+		if z.form > finite {
+			panic(fmt.Sprintf("round called for non-finite value %s", z))
+		}
 	}
+	// z.form <= finite
 
 	z.acc = Exact
-
-	// handle zero and Inf
-	m := uint32(len(z.mant)) // present mantissa length in words
-	if m == 0 {
-		if z.exp != infExp {
-			z.exp = 0
-		}
+	if z.form == zero {
 		return
 	}
+	// z.form == finite && len(z.mant) > 0
 	// m > 0 implies z.prec > 0 (checked by validate)
 
-	bits := m * _W // present mantissa bits
+	m := uint32(len(z.mant)) // present mantissa length in words
+	bits := m * _W           // present mantissa bits
 	if bits <= z.prec {
 		// mantissa fits => nothing to do
 		return
@@ -415,7 +448,7 @@
 	lsb := Word(1) << t
 
 	// make rounding decision
-	// TODO(gri) This can be simplified (see roundBits in float_test.go).
+	// TODO(gri) This can be simplified (see Bits.round in bits_test.go).
 	switch mode {
 	case ToZero:
 		// nothing to do
@@ -461,7 +494,14 @@
 			shrVU(z.mant, z.mant, 1)
 			z.mant[n-1] |= 1 << (_W - 1)
 			// adjust exponent
-			z.exp++
+			if z.exp < MaxExp {
+				z.exp++
+			} else {
+				// exponent overflow
+				z.acc = makeAcc(!z.neg)
+				z.form = inf
+				return
+			}
 		}
 		z.acc = Above
 	}
@@ -470,12 +510,12 @@
 	z.mant[0] &^= lsb - 1
 
 	// update accuracy
-	if z.neg {
+	if z.acc != Exact && z.neg {
 		z.acc = -z.acc
 	}
 
 	if debugFloat {
-		validate(z)
+		z.validate()
 	}
 
 	return
@@ -507,11 +547,11 @@
 	z.acc = Exact
 	z.neg = neg
 	if x == 0 {
-		z.mant = z.mant[:0]
-		z.exp = 0
+		z.form = zero
 		return z
 	}
 	// x != 0
+	z.form = finite
 	s := nlz64(x)
 	z.mant = z.mant.setUint64(x << s)
 	z.exp = int32(64 - s) // always fits
@@ -543,26 +583,26 @@
 
 // SetFloat64 sets z to the (possibly rounded) value of x and returns z.
 // If z's precision is 0, it is changed to 53 (and rounding will have
-// no effect).
-// If x is denormalized or NaN, the result is unspecified.
-// TODO(gri) should return nil in those cases
+// no effect). SetFloat64 panics with ErrNaN if x is a NaN.
 func (z *Float) SetFloat64(x float64) *Float {
 	if z.prec == 0 {
 		z.prec = 53
 	}
+	if math.IsNaN(x) {
+		panic(ErrNaN{"Float.SetFloat64(NaN)"})
+	}
 	z.acc = Exact
-	z.neg = math.Signbit(x) // handle -0 correctly
-	if math.IsInf(x, 0) {
-		z.mant = z.mant[:0]
-		z.exp = infExp
-		return z
-	}
+	z.neg = math.Signbit(x) // handle -0, -Inf correctly
 	if x == 0 {
-		z.mant = z.mant[:0]
-		z.exp = 0
+		z.form = zero
 		return z
 	}
-	// x != 0
+	if math.IsInf(x, 0) {
+		z.form = inf
+		return z
+	}
+	// normalized x != 0
+	z.form = finite
 	fmant, exp := math.Frexp(x) // get normalized mantissa
 	z.mant = z.mant.setUint64(1<<63 | math.Float64bits(fmant)<<11)
 	z.exp = int32(exp) // always fits
@@ -603,17 +643,13 @@
 	z.acc = Exact
 	z.neg = x.neg
 	if len(x.abs) == 0 {
-		z.mant = z.mant[:0]
-		z.exp = 0
+		z.form = zero
 		return z
 	}
 	// x != 0
 	z.mant = z.mant.set(x.abs)
 	fnorm(z.mant)
-	z.setExp(int64(bits))
-	if z.prec < bits {
-		z.round(0)
-	}
+	z.setExpAndRound(int64(bits), 0)
 	return z
 }
 
@@ -633,6 +669,17 @@
 	return z.Quo(&a, &b)
 }
 
+// SetInf sets z to the infinite Float -Inf if signbit is
+// set, or +Inf if signbit is not set, and returns z. The
+// precision of z is unchanged and the result is always
+// Exact.
+func (z *Float) SetInf(signbit bool) *Float {
+	z.acc = Exact
+	z.form = inf
+	z.neg = signbit
+	return z
+}
+
 // Set sets z to the (possibly rounded) value of x and returns z.
 // If z's precision is 0, it is changed to the precision of x
 // before setting z (and rounding will have no effect).
@@ -640,37 +687,52 @@
 // mode; and z's accuracy reports the result error relative to the
 // exact (not rounded) result.
 func (z *Float) Set(x *Float) *Float {
-	// TODO(gri) what about z.acc? should it be always Exact?
+	if debugFloat {
+		x.validate()
+	}
+	z.acc = Exact
 	if z != x {
+		z.form = x.form
+		z.neg = x.neg
+		if x.form == finite {
+			z.exp = x.exp
+			z.mant = z.mant.set(x.mant)
+		}
 		if z.prec == 0 {
 			z.prec = x.prec
-		}
-		z.acc = Exact
-		z.neg = x.neg
-		z.exp = x.exp
-		z.mant = z.mant.set(x.mant)
-		if z.prec < x.prec {
+		} else if z.prec < x.prec {
 			z.round(0)
 		}
 	}
 	return z
 }
 
-// Copy sets z to x, with the same precision and rounding mode as x,
-// and returns z.
+// Copy sets z to x, with the same precision, rounding mode, and
+// accuracy as x, and returns z. x is not changed even if z and
+// x are the same.
 func (z *Float) Copy(x *Float) *Float {
-	// TODO(gri) what about z.acc? should it be always Exact?
+	if debugFloat {
+		x.validate()
+	}
 	if z != x {
-		z.acc = Exact
-		z.neg = x.neg
-		z.exp = x.exp
-		z.mant = z.mant.set(x.mant)
 		z.prec = x.prec
 		z.mode = x.mode
+		z.acc = x.acc
+		z.form = x.form
+		z.neg = x.neg
+		if z.form == finite {
+			z.mant = z.mant.set(x.mant)
+			z.exp = x.exp
+		}
 	}
 	return z
 }
 
+func high32(x nat) uint32 {
+	// TODO(gri) This can be done more efficiently on 32bit platforms.
+	return uint32(high64(x) >> 32)
+}
+
 func high64(x nat) uint64 {
 	i := len(x)
 	if i == 0 {
@@ -694,22 +756,20 @@
 // for x > math.MaxUint64.
 func (x *Float) Uint64() (uint64, Accuracy) {
 	if debugFloat {
-		validate(x)
+		x.validate()
 	}
-	switch x.ord() {
-	case -2, -1:
-		// x < 0
-		return 0, Above
-	case 0:
-		// x == 0 || x == -0
-		return 0, Exact
-	case 1:
+
+	switch x.form {
+	case finite:
+		if x.neg {
+			return 0, Above
+		}
 		// 0 < x < +Inf
 		if x.exp <= 0 {
 			// 0 < x < 1
 			return 0, Below
 		}
-		// 1 <= x < +Inf
+		// 1 <= x < Inf
 		if x.exp <= 64 {
 			// u = trunc(x) fits into a uint64
 			u := high64(x.mant) >> (64 - uint32(x.exp))
@@ -718,41 +778,42 @@
 			}
 			return u, Below // x truncated
 		}
-		fallthrough // x too large
-	case 2:
-		// x == +Inf
+		// x too large
+		return math.MaxUint64, Below
+
+	case zero:
+		return 0, Exact
+
+	case inf:
+		if x.neg {
+			return 0, Above
+		}
 		return math.MaxUint64, Below
 	}
+
 	panic("unreachable")
 }
 
 // Int64 returns the integer resulting from truncating x towards zero.
 // If math.MinInt64 <= x <= math.MaxInt64, the result is Exact if x is
 // an integer, and Above (x < 0) or Below (x > 0) otherwise.
-// The result is (math.MinInt64, Above) for x < math.MinInt64, and
-// (math.MaxInt64, Below) for x > math.MaxInt64.
+// The result is (math.MinInt64, Above) for x < math.MinInt64,
+// and (math.MaxInt64, Below) for x > math.MaxInt64.
 func (x *Float) Int64() (int64, Accuracy) {
 	if debugFloat {
-		validate(x)
+		x.validate()
 	}
 
-	switch x.ord() {
-	case -2:
-		// x == -Inf
-		return math.MinInt64, Above
-	case 0:
-		// x == 0 || x == -0
-		return 0, Exact
-	case -1, 1:
+	switch x.form {
+	case finite:
 		// 0 < |x| < +Inf
-		acc := Below
-		if x.neg {
-			acc = Above
-		}
+		acc := makeAcc(x.neg)
 		if x.exp <= 0 {
 			// 0 < |x| < 1
 			return 0, acc
 		}
+		// x.exp > 0
+
 		// 1 <= |x| < +Inf
 		if x.exp <= 63 {
 			// i = trunc(x) fits into an int64 (excluding math.MinInt64)
@@ -760,7 +821,7 @@
 			if x.neg {
 				i = -i
 			}
-			if x.MinPrec() <= 63 {
+			if x.MinPrec() <= uint(x.exp) {
 				return i, Exact
 			}
 			return i, acc // x truncated
@@ -772,41 +833,223 @@
 			}
 			return math.MinInt64, acc
 		}
-		fallthrough
-	case 2:
-		// x == +Inf
+		// x too large
+		return math.MaxInt64, Below
+
+	case zero:
+		return 0, Exact
+
+	case inf:
+		if x.neg {
+			return math.MinInt64, Above
+		}
 		return math.MaxInt64, Below
 	}
+
 	panic("unreachable")
 }
 
-// Float64 returns the closest float64 value of x
-// by rounding to nearest with 53 bits precision.
-// TODO(gri) implement/document error scenarios.
-func (x *Float) Float64() (float64, Accuracy) {
-	// x == ±Inf
-	if x.exp == infExp {
-		var sign int
-		if x.neg {
-			sign = -1
+// TODO(gri) Float32 and Float64 are very similar internally but for the
+// floatxx parameters and some conversions. Should factor out shared code.
+
+// Float32 returns the float32 value nearest to x. If x is too small to be
+// represented by a float32 (|x| < math.SmallestNonzeroFloat32), the result
+// is (0, Below) or (-0, Above), respectively, depending on the sign of x.
+// If x is too large to be represented by a float32 (|x| > math.MaxFloat32),
+// the result is (+Inf, Above) or (-Inf, Below), depending on the sign of x.
+func (x *Float) Float32() (float32, Accuracy) {
+	if debugFloat {
+		x.validate()
+	}
+
+	switch x.form {
+	case finite:
+		// 0 < |x| < +Inf
+
+		const (
+			fbits = 32                //        float size
+			mbits = 23                //        mantissa size (excluding implicit msb)
+			ebits = fbits - mbits - 1 //     8  exponent size
+			bias  = 1<<(ebits-1) - 1  //   127  exponent bias
+			dmin  = 1 - bias - mbits  //  -149  smallest unbiased exponent (denormal)
+			emin  = 1 - bias          //  -126  smallest unbiased exponent (normal)
+			emax  = bias              //   127  largest unbiased exponent (normal)
+		)
+
+		// Float mantissae m have an explicit msb and are in the range 0.5 <= m < 1.0.
+		// floatxx mantissae have an implicit msb and are in the range 1.0 <= m < 2.0.
+		// For a given mantissa m, we need to add 1 to a floatxx exponent to get the
+		// corresponding Float exponent.
+		// (see also implementation of math.Ldexp for similar code)
+
+		if x.exp < dmin+1 {
+			// underflow
+			if x.neg {
+				var z float32
+				return -z, Above
+			}
+			return 0.0, Below
 		}
-		return math.Inf(sign), Exact
+		// x.exp >= dmin+1
+
+		var r Float
+		r.prec = mbits + 1 // +1 for implicit msb
+		if x.exp < emin+1 {
+			// denormal number - round to fewer bits
+			r.prec = uint32(x.exp - dmin)
+		}
+		r.Set(x)
+
+		// Rounding may have caused r to overflow to ±Inf
+		// (rounding never causes underflows to 0).
+		if r.form == inf {
+			r.exp = emax + 2 // cause overflow below
+		}
+
+		if r.exp > emax+1 {
+			// overflow
+			if x.neg {
+				return float32(math.Inf(-1)), Below
+			}
+			return float32(math.Inf(+1)), Above
+		}
+		// dmin+1 <= r.exp <= emax+1
+
+		var s uint32
+		if r.neg {
+			s = 1 << (fbits - 1)
+		}
+
+		m := high32(r.mant) >> ebits & (1<<mbits - 1) // cut off msb (implicit 1 bit)
+
+		// Rounding may have caused a denormal number to
+		// become normal. Check again.
+		c := float32(1.0)
+		if r.exp < emin+1 {
+			// denormal number
+			r.exp += mbits
+			c = 1.0 / (1 << mbits) // 2**-mbits
+		}
+		// emin+1 <= r.exp <= emax+1
+		e := uint32(r.exp-emin) << mbits
+
+		return c * math.Float32frombits(s|e|m), r.acc
+
+	case zero:
+		if x.neg {
+			var z float32
+			return -z, Exact
+		}
+		return 0.0, Exact
+
+	case inf:
+		if x.neg {
+			return float32(math.Inf(-1)), Exact
+		}
+		return float32(math.Inf(+1)), Exact
 	}
-	// x == 0
-	if len(x.mant) == 0 {
-		return 0, Exact
+
+	panic("unreachable")
+}
+
+// Float64 returns the float64 value nearest to x. If x is too small to be
+// represented by a float64 (|x| < math.SmallestNonzeroFloat64), the result
+// is (0, Below) or (-0, Above), respectively, depending on the sign of x.
+// If x is too large to be represented by a float64 (|x| > math.MaxFloat64),
+// the result is (+Inf, Above) or (-Inf, Below), depending on the sign of x.
+func (x *Float) Float64() (float64, Accuracy) {
+	if debugFloat {
+		x.validate()
 	}
-	// x != 0
-	var r Float
-	r.prec = 53
-	r.Set(x)
-	var s uint64
-	if r.neg {
-		s = 1 << 63
+
+	switch x.form {
+	case finite:
+		// 0 < |x| < +Inf
+
+		const (
+			fbits = 64                //        float size
+			mbits = 52                //        mantissa size (excluding implicit msb)
+			ebits = fbits - mbits - 1 //    11  exponent size
+			bias  = 1<<(ebits-1) - 1  //  1023  exponent bias
+			dmin  = 1 - bias - mbits  // -1074  smallest unbiased exponent (denormal)
+			emin  = 1 - bias          // -1022  smallest unbiased exponent (normal)
+			emax  = bias              //  1023  largest unbiased exponent (normal)
+		)
+
+		// Float mantissae m have an explicit msb and are in the range 0.5 <= m < 1.0.
+		// floatxx mantissae have an implicit msb and are in the range 1.0 <= m < 2.0.
+		// For a given mantissa m, we need to add 1 to a floatxx exponent to get the
+		// corresponding Float exponent.
+		// (see also implementation of math.Ldexp for similar code)
+
+		if x.exp < dmin+1 {
+			// underflow
+			if x.neg {
+				var z float64
+				return -z, Above
+			}
+			return 0.0, Below
+		}
+		// x.exp >= dmin+1
+
+		var r Float
+		r.prec = mbits + 1 // +1 for implicit msb
+		if x.exp < emin+1 {
+			// denormal number - round to fewer bits
+			r.prec = uint32(x.exp - dmin)
+		}
+		r.Set(x)
+
+		// Rounding may have caused r to overflow to ±Inf
+		// (rounding never causes underflows to 0).
+		if r.form == inf {
+			r.exp = emax + 2 // cause overflow below
+		}
+
+		if r.exp > emax+1 {
+			// overflow
+			if x.neg {
+				return math.Inf(-1), Below
+			}
+			return math.Inf(+1), Above
+		}
+		// dmin+1 <= r.exp <= emax+1
+
+		var s uint64
+		if r.neg {
+			s = 1 << (fbits - 1)
+		}
+
+		m := high64(r.mant) >> ebits & (1<<mbits - 1) // cut off msb (implicit 1 bit)
+
+		// Rounding may have caused a denormal number to
+		// become normal. Check again.
+		c := 1.0
+		if r.exp < emin+1 {
+			// denormal number
+			r.exp += mbits
+			c = 1.0 / (1 << mbits) // 2**-mbits
+		}
+		// emin+1 <= r.exp <= emax+1
+		e := uint64(r.exp-emin) << mbits
+
+		return c * math.Float64frombits(s|e|m), r.acc
+
+	case zero:
+		if x.neg {
+			var z float64
+			return -z, Exact
+		}
+		return 0.0, Exact
+
+	case inf:
+		if x.neg {
+			return math.Inf(-1), Exact
+		}
+		return math.Inf(+1), Exact
 	}
-	e := uint64(1022+r.exp) & 0x7ff // TODO(gri) check for overflow
-	m := high64(r.mant) >> 11 & (1<<52 - 1)
-	return math.Float64frombits(s | e<<52 | m), r.acc
+
+	panic("unreachable")
 }
 
 // Int returns the result of truncating x towards zero;
@@ -817,93 +1060,100 @@
 // the result in z instead of allocating a new Int.
 func (x *Float) Int(z *Int) (*Int, Accuracy) {
 	if debugFloat {
-		validate(x)
+		x.validate()
 	}
-	// accuracy for inexact results
-	acc := Below // truncation
-	if x.neg {
-		acc = Above
-	}
-	// pick off easy cases
-	if x.exp <= 0 {
-		// |x| < 1 || |x| == Inf
-		if x.exp == infExp {
-			return nil, acc // ±Inf
-		}
-		if len(x.mant) == 0 {
-			acc = Exact // ±0
-		}
-		// ±0.xxx
-		if z == nil {
-			return new(Int), acc
-		}
-		return z.SetUint64(0), acc
-	}
-	// x.exp > 0
-	// x.mant[len(x.mant)-1] != 0
-	// determine minimum required precision for x
-	allBits := uint(len(x.mant)) * _W
-	exp := uint(x.exp)
-	if x.MinPrec() <= exp {
-		acc = Exact
-	}
-	// shift mantissa as needed
-	if z == nil {
+
+	if z == nil && x.form <= finite {
 		z = new(Int)
 	}
-	z.neg = x.neg
-	// TODO(gri) should have a shift that takes positive and negative shift counts
-	switch {
-	case exp > allBits:
-		z.abs = z.abs.shl(x.mant, exp-allBits)
-	default:
-		z.abs = z.abs.set(x.mant)
-	case exp < allBits:
-		z.abs = z.abs.shr(x.mant, allBits-exp)
+
+	switch x.form {
+	case finite:
+		// 0 < |x| < +Inf
+		acc := makeAcc(x.neg)
+		if x.exp <= 0 {
+			// 0 < |x| < 1
+			return z.SetInt64(0), acc
+		}
+		// x.exp > 0
+
+		// 1 <= |x| < +Inf
+		// determine minimum required precision for x
+		allBits := uint(len(x.mant)) * _W
+		exp := uint(x.exp)
+		if x.MinPrec() <= exp {
+			acc = Exact
+		}
+		// shift mantissa as needed
+		if z == nil {
+			z = new(Int)
+		}
+		z.neg = x.neg
+		switch {
+		case exp > allBits:
+			z.abs = z.abs.shl(x.mant, exp-allBits)
+		default:
+			z.abs = z.abs.set(x.mant)
+		case exp < allBits:
+			z.abs = z.abs.shr(x.mant, allBits-exp)
+		}
+		return z, acc
+
+	case zero:
+		return z.SetInt64(0), Exact
+
+	case inf:
+		return nil, makeAcc(x.neg)
 	}
-	return z, acc
+
+	panic("unreachable")
 }
 
 // Rat returns the rational number corresponding to x;
 // or nil if x is an infinity.
+// The result is Exact is x is not an Inf.
 // If a non-nil *Rat argument z is provided, Rat stores
 // the result in z instead of allocating a new Rat.
-func (x *Float) Rat(z *Rat) *Rat {
+func (x *Float) Rat(z *Rat) (*Rat, Accuracy) {
 	if debugFloat {
-		validate(x)
+		x.validate()
 	}
-	// pick off easy cases
-	switch x.ord() {
-	case -2, +2:
-		return nil // ±Inf
-	case 0:
-		if z == nil {
-			return new(Rat)
-		}
-		return z.SetInt64(0)
-	}
-	// x != 0 && x != ±Inf
-	allBits := int32(len(x.mant)) * _W
-	// build up numerator and denominator
-	if z == nil {
+
+	if z == nil && x.form <= finite {
 		z = new(Rat)
 	}
-	z.a.neg = x.neg
-	switch {
-	case x.exp > allBits:
-		z.a.abs = z.a.abs.shl(x.mant, uint(x.exp-allBits))
-		z.b.abs = z.b.abs[:0] // == 1 (see Rat)
-		return z              // already in normal form
-	default:
-		z.a.abs = z.a.abs.set(x.mant)
-		z.b.abs = z.b.abs[:0] // == 1 (see Rat)
-		return z              // already in normal form
-	case x.exp < allBits:
-		z.a.abs = z.a.abs.set(x.mant)
-		t := z.b.abs.setUint64(1)
-		z.b.abs = t.shl(t, uint(allBits-x.exp))
-		return z.norm()
+
+	switch x.form {
+	case finite:
+		// 0 < |x| < +Inf
+		allBits := int32(len(x.mant)) * _W
+		// build up numerator and denominator
+		z.a.neg = x.neg
+		switch {
+		case x.exp > allBits:
+			z.a.abs = z.a.abs.shl(x.mant, uint(x.exp-allBits))
+			z.b.abs = z.b.abs[:0] // == 1 (see Rat)
+			// z already in normal form
+		default:
+			z.a.abs = z.a.abs.set(x.mant)
+			z.b.abs = z.b.abs[:0] // == 1 (see Rat)
+			// z already in normal form
+		case x.exp < allBits:
+			z.a.abs = z.a.abs.set(x.mant)
+			t := z.b.abs.setUint64(1)
+			z.b.abs = t.shl(t, uint(allBits-x.exp))
+			z.norm()
+		}
+		return z, Exact
+
+	case zero:
+		return z.SetInt64(0), Exact
+
+	case inf:
+		return nil, makeAcc(x.neg)
 	}
+
+	panic("unreachable")
 }
 
 // Abs sets z to the (possibly rounded) value |x| (the absolute value of x)
@@ -922,8 +1172,22 @@
 	return z
 }
 
-// z = x + y, ignoring signs of x and y.
-// x and y must not be 0 or an Inf.
+func validateBinaryOperands(x, y *Float) {
+	if !debugFloat {
+		// avoid performance bugs
+		panic("validateBinaryOperands called but debugFloat is not set")
+	}
+	if len(x.mant) == 0 {
+		panic("empty mantissa for x")
+	}
+	if len(y.mant) == 0 {
+		panic("empty mantissa for y")
+	}
+}
+
+// z = x + y, ignoring signs of x and y for the addition
+// but using the sign of z for rounding the result.
+// x and y must have a non-empty mantissa and valid exponent.
 func (z *Float) uadd(x, y *Float) {
 	// Note: This implementation requires 2 shifts most of the
 	// time. It is also inefficient if exponents or precisions
@@ -935,8 +1199,8 @@
 	// Point Addition With Exact Rounding (as in the MPFR Library)"
 	// http://www.vinc17.net/research/papers/rnc6.pdf
 
-	if debugFloat && (len(x.mant) == 0 || len(y.mant) == 0) {
-		panic("uadd called with 0 argument")
+	if debugFloat {
+		validateBinaryOperands(x, y)
 	}
 
 	// compute exponents ex, ey for mantissa with "binary point"
@@ -962,20 +1226,20 @@
 	}
 	// len(z.mant) > 0
 
-	z.setExp(ex + int64(len(z.mant))*_W - fnorm(z.mant))
-	z.round(0)
+	z.setExpAndRound(ex+int64(len(z.mant))*_W-fnorm(z.mant), 0)
 }
 
-// z = x - y for x >= y, ignoring signs of x and y.
-// x and y must not be 0 or an Inf.
+// z = x - y for |x| > |y|, ignoring signs of x and y for the subtraction
+// but using the sign of z for rounding the result.
+// x and y must have a non-empty mantissa and valid exponent.
 func (z *Float) usub(x, y *Float) {
 	// This code is symmetric to uadd.
 	// We have not factored the common code out because
 	// eventually uadd (and usub) should be optimized
 	// by special-casing, and the code will diverge.
 
-	if debugFloat && (len(x.mant) == 0 || len(y.mant) == 0) {
-		panic("usub called with 0 argument")
+	if debugFloat {
+		validateBinaryOperands(x, y)
 	}
 
 	ex := int64(x.exp) - int64(len(x.mant))*_W
@@ -999,20 +1263,21 @@
 	// operands may have cancelled each other out
 	if len(z.mant) == 0 {
 		z.acc = Exact
-		z.setExp(0)
+		z.form = zero
+		z.neg = false
 		return
 	}
 	// len(z.mant) > 0
 
-	z.setExp(ex + int64(len(z.mant))*_W - fnorm(z.mant))
-	z.round(0)
+	z.setExpAndRound(ex+int64(len(z.mant))*_W-fnorm(z.mant), 0)
 }
 
-// z = x * y, ignoring signs of x and y.
-// x and y must not be 0 or an Inf.
+// z = x * y, ignoring signs of x and y for the multiplication
+// but using the sign of z for rounding the result.
+// x and y must have a non-empty mantissa and valid exponent.
 func (z *Float) umul(x, y *Float) {
-	if debugFloat && (len(x.mant) == 0 || len(y.mant) == 0) {
-		panic("umul called with 0 argument")
+	if debugFloat {
+		validateBinaryOperands(x, y)
 	}
 
 	// Note: This is doing too much work if the precision
@@ -1024,16 +1289,15 @@
 	e := int64(x.exp) + int64(y.exp)
 	z.mant = z.mant.mul(x.mant, y.mant)
 
-	// normalize mantissa
-	z.setExp(e - fnorm(z.mant))
-	z.round(0)
+	z.setExpAndRound(e-fnorm(z.mant), 0)
 }
 
-// z = x / y, ignoring signs of x and y.
-// x and y must not be 0 or an Inf.
+// z = x / y, ignoring signs of x and y for the division
+// but using the sign of z for rounding the result.
+// x and y must have a non-empty mantissa and valid exponent.
 func (z *Float) uquo(x, y *Float) {
-	if debugFloat && (len(x.mant) == 0 || len(y.mant) == 0) {
-		panic("uquo called with 0 argument")
+	if debugFloat {
+		validateBinaryOperands(x, y)
 	}
 
 	// mantissa length in words for desired result precision + 1
@@ -1059,13 +1323,8 @@
 	// divide
 	var r nat
 	z.mant, r = z.mant.div(nil, xadj, y.mant)
-
-	// determine exponent
 	e := int64(x.exp) - int64(y.exp) - int64(d-len(z.mant))*_W
 
-	// normalize mantissa
-	z.setExp(e - fnorm(z.mant))
-
 	// The result is long enough to include (at least) the rounding bit.
 	// If there's a non-zero remainder, the corresponding fractional part
 	// (if it were computed), would have a non-zero sticky bit (if it were
@@ -1074,21 +1333,23 @@
 	if len(r) > 0 {
 		sbit = 1
 	}
-	z.round(sbit)
+
+	z.setExpAndRound(e-fnorm(z.mant), sbit)
 }
 
-// ucmp returns -1, 0, or 1, depending on whether x < y, x == y, or x > y,
-// while ignoring the signs of x and y. x and y must not be 0 or an Inf.
+// ucmp returns -1, 0, or +1, depending on whether
+// |x| < |y|, |x| == |y|, or |x| > |y|.
+// x and y must have a non-empty mantissa and valid exponent.
 func (x *Float) ucmp(y *Float) int {
-	if debugFloat && (len(x.mant) == 0 || len(y.mant) == 0) {
-		panic("ucmp called with 0 argument")
+	if debugFloat {
+		validateBinaryOperands(x, y)
 	}
 
 	switch {
 	case x.exp < y.exp:
 		return -1
 	case x.exp > y.exp:
-		return 1
+		return +1
 	}
 	// x.exp == y.exp
 
@@ -1109,15 +1370,14 @@
 		case xm < ym:
 			return -1
 		case xm > ym:
-			return 1
+			return +1
 		}
 	}
 
 	return 0
 }
 
-// Handling of sign bit as defined by IEEE 754-2008,
-// section 6.3 (note that there are no NaN Floats):
+// Handling of sign bit as defined by IEEE 754-2008, section 6.3:
 //
 // When neither the inputs nor result are NaN, the sign of a product or
 // quotient is the exclusive OR of the operands’ signs; the sign of a sum,
@@ -1133,33 +1393,42 @@
 // roundTowardNegative; under that attribute, the sign of an exact zero
 // sum (or difference) shall be −0. However, x+x = x−(−x) retains the same
 // sign as x even when x is zero.
+//
+// See also: http://play.golang.org/p/RtH3UCt5IH
 
-// Add sets z to the rounded sum x+y and returns z.
-// If z's precision is 0, it is changed to the larger
-// of x's or y's precision before the operation.
-// Rounding is performed according to z's precision
-// and rounding mode; and z's accuracy reports the
-// result error relative to the exact (not rounded)
+// Add sets z to the rounded sum x+y and returns z. If z's precision is 0,
+// it is changed to the larger of x's or y's precision before the operation.
+// Rounding is performed according to z's precision and rounding mode; and
+// z's accuracy reports the result error relative to the exact (not rounded)
 // result.
+// BUG(gri) Float.Add panics if an operand is Inf.
+// BUG(gri) When rounding ToNegativeInf, the sign of Float values rounded to 0 is incorrect.
 func (z *Float) Add(x, y *Float) *Float {
 	if debugFloat {
-		validate(x)
-		validate(y)
+		x.validate()
+		y.validate()
 	}
 
 	if z.prec == 0 {
 		z.prec = umax32(x.prec, y.prec)
 	}
 
-	// TODO(gri) what about -0?
-	if len(y.mant) == 0 {
-		// TODO(gri) handle Inf
+	// special cases
+	if x.form != finite || y.form != finite {
+		if x.form > finite || y.form > finite {
+			// TODO(gri) handle Inf separately
+			panic("Inf operand")
+		}
+		if x.form == zero {
+			z.Set(y)
+			if z.form == zero {
+				z.neg = x.neg && y.neg // -0 + -0 == -0
+			}
+			return z
+		}
+		// y == ±0
 		return z.Set(x)
 	}
-	if len(x.mant) == 0 {
-		// TODO(gri) handle Inf
-		return z.Set(y)
-	}
 
 	// x, y != 0
 	z.neg = x.neg
@@ -1170,36 +1439,46 @@
 	} else {
 		// x + (-y) == x - y == -(y - x)
 		// (-x) + y == y - x == -(x - y)
-		if x.ucmp(y) >= 0 {
+		if x.ucmp(y) > 0 {
 			z.usub(x, y)
 		} else {
 			z.neg = !z.neg
 			z.usub(y, x)
 		}
 	}
+
 	return z
 }
 
 // Sub sets z to the rounded difference x-y and returns z.
 // Precision, rounding, and accuracy reporting are as for Add.
+// BUG(gri) Float.Sub panics if an operand is Inf.
 func (z *Float) Sub(x, y *Float) *Float {
 	if debugFloat {
-		validate(x)
-		validate(y)
+		x.validate()
+		y.validate()
 	}
 
 	if z.prec == 0 {
 		z.prec = umax32(x.prec, y.prec)
 	}
 
-	// TODO(gri) what about -0?
-	if len(y.mant) == 0 {
-		// TODO(gri) handle Inf
+	// special cases
+	if x.form != finite || y.form != finite {
+		if x.form > finite || y.form > finite {
+			// TODO(gri) handle Inf separately
+			panic("Inf operand")
+		}
+		if x.form == zero {
+			z.Neg(y)
+			if z.form == zero {
+				z.neg = x.neg && !y.neg // -0 - 0 == -0
+			}
+			return z
+		}
+		// y == ±0
 		return z.Set(x)
 	}
-	if len(x.mant) == 0 {
-		return z.Neg(y)
-	}
 
 	// x, y != 0
 	z.neg = x.neg
@@ -1210,132 +1489,102 @@
 	} else {
 		// x - y == x - y == -(y - x)
 		// (-x) - (-y) == y - x == -(x - y)
-		if x.ucmp(y) >= 0 {
+		if x.ucmp(y) > 0 {
 			z.usub(x, y)
 		} else {
 			z.neg = !z.neg
 			z.usub(y, x)
 		}
 	}
+
 	return z
 }
 
 // Mul sets z to the rounded product x*y and returns z.
 // Precision, rounding, and accuracy reporting are as for Add.
+// BUG(gri) Float.Mul panics if an operand is Inf.
 func (z *Float) Mul(x, y *Float) *Float {
 	if debugFloat {
-		validate(x)
-		validate(y)
+		x.validate()
+		y.validate()
 	}
 
 	if z.prec == 0 {
 		z.prec = umax32(x.prec, y.prec)
 	}
 
-	// TODO(gri) handle Inf
+	z.neg = x.neg != y.neg
 
-	// TODO(gri) what about -0?
-	if len(x.mant) == 0 || len(y.mant) == 0 {
-		z.neg = false
-		z.mant = z.mant[:0]
-		z.exp = 0
+	// special cases
+	if x.form != finite || y.form != finite {
+		if x.form > finite || y.form > finite {
+			// TODO(gri) handle Inf separately
+			panic("Inf operand")
+		}
+		// x == ±0 || y == ±0
 		z.acc = Exact
+		z.form = zero
 		return z
 	}
 
 	// x, y != 0
-	z.neg = x.neg != y.neg
 	z.umul(x, y)
+
 	return z
 }
 
 // Quo sets z to the rounded quotient x/y and returns z.
 // Precision, rounding, and accuracy reporting are as for Add.
+// Quo panics is both operands are 0.
+// BUG(gri) Float.Quo panics if an operand is Inf.
 func (z *Float) Quo(x, y *Float) *Float {
 	if debugFloat {
-		validate(x)
-		validate(y)
+		x.validate()
+		y.validate()
 	}
 
 	if z.prec == 0 {
 		z.prec = umax32(x.prec, y.prec)
 	}
 
-	// TODO(gri) handle Inf
-
-	// TODO(gri) check that this is correct
 	z.neg = x.neg != y.neg
 
-	if len(y.mant) == 0 {
-		z.setExp(infExp)
-		return z
-	}
-
-	if len(x.mant) == 0 {
-		z.mant = z.mant[:0]
-		z.exp = 0
-		z.acc = Exact
+	// special cases
+	z.acc = Exact
+	if x.form != finite || y.form != finite {
+		if x.form > finite || y.form > finite {
+			// TODO(gri) handle Inf separately
+			panic("Inf operand")
+		}
+		// x == ±0 || y == ±0
+		if x.form == zero {
+			if y.form == zero {
+				panic("0/0")
+			}
+			z.form = zero
+			return z
+		}
+		// y == ±0
+		z.form = inf
 		return z
 	}
 
 	// x, y != 0
 	z.uquo(x, y)
-	return z
-}
 
-// Lsh sets z to the rounded x * (1<<s) and returns z.
-// If z's precision is 0, it is changed to x's precision.
-// Rounding is performed according to z's precision
-// and rounding mode; and z's accuracy reports the
-// result error relative to the exact (not rounded)
-// result.
-// BUG(gri) Lsh is not tested and may not work correctly.
-func (z *Float) Lsh(x *Float, s uint) *Float {
-	if debugFloat {
-		validate(x)
-	}
-
-	if z.prec == 0 {
-		z.prec = x.prec
-	}
-
-	// TODO(gri) handle Inf
-
-	z.round(0)
-	z.setExp(int64(z.exp) + int64(s))
-	return z
-}
-
-// Rsh sets z to the rounded x / (1<<s) and returns z.
-// Precision, rounding, and accuracy reporting are as for Lsh.
-// BUG(gri) Rsh is not tested and may not work correctly.
-func (z *Float) Rsh(x *Float, s uint) *Float {
-	if debugFloat {
-		validate(x)
-	}
-
-	if z.prec == 0 {
-		z.prec = x.prec
-	}
-
-	// TODO(gri) handle Inf
-
-	z.round(0)
-	z.setExp(int64(z.exp) - int64(s))
 	return z
 }
 
 // Cmp compares x and y and returns:
 //
 //   -1 if x <  y
-//    0 if x == y (incl. -0 == 0)
+//    0 if x == y (incl. -0 == 0, -Inf == -Inf, and +Inf == +Inf)
 //   +1 if x >  y
 //
-// Infinities with matching sign are equal.
 func (x *Float) Cmp(y *Float) int {
 	if debugFloat {
-		validate(x)
-		validate(y)
+		x.validate()
+		y.validate()
 	}
 
 	mx := x.ord()
@@ -1351,21 +1600,14 @@
 	// only if |mx| == 1 we have to compare the mantissae
 	switch mx {
 	case -1:
-		return -x.ucmp(y)
+		return y.ucmp(x)
 	case +1:
-		return +x.ucmp(y)
+		return x.ucmp(y)
 	}
 
 	return 0
 }
 
-func umax32(x, y uint32) uint32 {
-	if x > y {
-		return x
-	}
-	return y
-}
-
 // ord classifies x and returns:
 //
 //	-2 if -Inf == x
@@ -1374,17 +1616,25 @@
 //	+1 if 0 < x < +Inf
 //	+2 if x == +Inf
 //
-// TODO(gri) export (and remove IsInf)?
 func (x *Float) ord() int {
-	m := 1 // common case
-	if len(x.mant) == 0 {
-		m = 0
-		if x.exp == infExp {
-			m = 2
-		}
+	var m int
+	switch x.form {
+	case finite:
+		m = 1
+	case zero:
+		return 0
+	case inf:
+		m = 2
 	}
 	if x.neg {
 		m = -m
 	}
 	return m
 }
+
+func umax32(x, y uint32) uint32 {
+	if x > y {
+		return x
+	}
+	return y
+}
diff --git a/src/math/big/float_test.go b/src/math/big/float_test.go
index cc58d96..b3f1a60 100644
--- a/src/math/big/float_test.go
+++ b/src/math/big/float_test.go
@@ -7,7 +7,6 @@
 import (
 	"fmt"
 	"math"
-	"sort"
 	"strconv"
 	"strings"
 	"testing"
@@ -70,7 +69,7 @@
 		{1, 2, 0, 0, '*', (*Float).Mul},
 		{2, 0, 1, 0, '*', (*Float).Mul},
 
-		{0, 0, 0, 0, '/', (*Float).Quo}, // = +Inf
+		// {0, 0, 0, 0, '/', (*Float).Quo}, // panics
 		{0, 2, 1, 2, '/', (*Float).Quo},
 		{1, 2, 0, 0, '/', (*Float).Quo}, // = +Inf
 		{2, 0, 1, 0, '/', (*Float).Quo},
@@ -78,7 +77,7 @@
 		z := make(test.z)
 		test.op(z, make(test.x), make(test.y))
 		got := 0
-		if !z.IsInf(0) {
+		if !z.IsInf() {
 			got = int(z.int64())
 		}
 		if got != test.want {
@@ -90,13 +89,19 @@
 }
 
 func makeFloat(s string) *Float {
-	if s == "Inf" || s == "+Inf" {
-		return NewInf(+1)
-	}
-	if s == "-Inf" {
-		return NewInf(-1)
-	}
 	var x Float
+
+	switch s {
+	case "0":
+		return &x
+	case "-0":
+		return x.Neg(&x)
+	case "Inf", "+Inf":
+		return x.SetInf(false)
+	case "-Inf":
+		return x.SetInf(true)
+	}
+
 	x.SetPrec(1000)
 	if _, ok := x.SetString(s); !ok {
 		panic(fmt.Sprintf("%q is not a valid float", s))
@@ -123,7 +128,7 @@
 		{"0", MaxPrec, "0", Exact},
 		{"-0", MaxPrec, "-0", Exact},
 		{"-Inf", MaxPrec, "-Inf", Exact},
-		{"-Inf", MaxPrec, "-Inf", Exact},
+		{"+Inf", MaxPrec, "+Inf", Exact},
 
 		// just a few regular cases - general rounding is tested elsewhere
 		{"1.5", 1, "2", Above},
@@ -142,13 +147,6 @@
 		if got, acc := x.String(), x.Acc(); got != test.want || acc != test.acc {
 			t.Errorf("%s.SetPrec(%d) = %s (%s); want %s (%s)", test.x, test.prec, got, acc, test.want, test.acc)
 		}
-		// look inside x and check correct value for x.exp
-		if len(x.mant) == 0 {
-			// ±0 or ±Inf
-			if x.exp != 0 && x.exp != infExp {
-				t.Errorf("%s.SetPrec(%d): incorrect exponent %d", test.x, test.prec, x.exp)
-			}
-		}
 	}
 }
 
@@ -197,15 +195,15 @@
 	}
 }
 
-// feq(x, y) is like x.Cmp(y) == 0 but it also considers the sign of 0 (0 != -0).
-func feq(x, y *Float) bool {
-	return x.Cmp(y) == 0 && x.neg == y.neg
+// alike(x, y) is like x.Cmp(y) == 0 but also considers the sign of 0 (0 != -0).
+func alike(x, y *Float) bool {
+	return x.Cmp(y) == 0 && x.Signbit() == y.Signbit()
 }
 
 func TestFloatMantExp(t *testing.T) {
 	for _, test := range []struct {
 		x    string
-		frac string
+		mant string
 		exp  int
 	}{
 		{"0", "0", 0},
@@ -219,23 +217,23 @@
 		{"-0.125", "-0.5", -2},
 	} {
 		x := makeFloat(test.x)
-		frac := makeFloat(test.frac)
-		f, e := x.MantExp(nil)
-		if !feq(f, frac) || e != test.exp {
-			t.Errorf("%s.MantExp(nil) = %s, %d; want %s, %d", test.x, f.Format('g', 10), e, test.frac, test.exp)
+		mant := makeFloat(test.mant)
+		m := new(Float)
+		e := x.MantExp(m)
+		if !alike(m, mant) || e != test.exp {
+			t.Errorf("%s.MantExp() = %s, %d; want %s, %d", test.x, m.Format('g', 10), e, test.mant, test.exp)
 		}
 	}
 }
 
 func TestFloatMantExpAliasing(t *testing.T) {
 	x := makeFloat("0.5p10")
-	z := new(Float)
-	if m, _ := x.MantExp(z); m != z {
-		t.Fatalf("Float.MantExp didn't use supplied *Float")
-	}
-	if _, e := x.MantExp(x); e != 10 {
+	if e := x.MantExp(x); e != 10 {
 		t.Fatalf("Float.MantExp aliasing error: got %d; want 10", e)
 	}
+	if want := makeFloat("0.5"); !alike(x, want) {
+		t.Fatalf("Float.MantExp aliasing error: got %s; want %s", x.Format('g', 10), want.Format('g', 10))
+	}
 }
 
 func TestFloatSetMantExp(t *testing.T) {
@@ -250,11 +248,11 @@
 		{"Inf", 1234, "+Inf"},
 		{"+Inf", -1234, "+Inf"},
 		{"-Inf", -1234, "-Inf"},
-		{"0", -MaxExp - 1, "0"},
-		{"0.5", -MaxExp - 1, "+Inf"},  // exponent overflow
-		{"-0.5", -MaxExp - 1, "-Inf"}, // exponent overflow
-		{"1", MaxExp, "+Inf"},         // exponent overflow
-		{"2", MaxExp - 1, "+Inf"},     // exponent overflow
+		{"0", MinExp, "0"},
+		{"0.25", MinExp, "+0"},    // exponent underflow
+		{"-0.25", MinExp, "-0"},   // exponent underflow
+		{"1", MaxExp, "+Inf"},     // exponent overflow
+		{"2", MaxExp - 1, "+Inf"}, // exponent overflow
 		{"0.75", 1, "1.5"},
 		{"0.5", 11, "1024"},
 		{"-0.5", -2, "-0.125"},
@@ -265,16 +263,43 @@
 		want := makeFloat(test.z)
 		var z Float
 		z.SetMantExp(frac, test.exp)
-		if !feq(&z, want) {
+		if !alike(&z, want) {
 			t.Errorf("SetMantExp(%s, %d) = %s; want %s", test.frac, test.exp, z.Format('g', 10), test.z)
 		}
 		// test inverse property
-		if z.SetMantExp(want.MantExp(nil)).Cmp(want) != 0 {
+		mant := new(Float)
+		if z.SetMantExp(mant, want.MantExp(mant)).Cmp(want) != 0 {
 			t.Errorf("Inverse property not satisfied: got %s; want %s", z.Format('g', 10), test.z)
 		}
 	}
 }
 
+func TestFloatPredicates(t *testing.T) {
+	for _, test := range []struct {
+		x            string
+		sign         int
+		signbit, inf bool
+	}{
+		{x: "-Inf", sign: -1, signbit: true, inf: true},
+		{x: "-1", sign: -1, signbit: true},
+		{x: "-0", signbit: true},
+		{x: "0"},
+		{x: "1", sign: 1},
+		{x: "+Inf", sign: 1, inf: true},
+	} {
+		x := makeFloat(test.x)
+		if got := x.Signbit(); got != test.signbit {
+			t.Errorf("(%s).Signbit() = %v; want %v", test.x, got, test.signbit)
+		}
+		if got := x.Sign(); got != test.sign {
+			t.Errorf("(%s).Sign() = %d; want %d", test.x, got, test.sign)
+		}
+		if got := x.IsInf(); got != test.inf {
+			t.Errorf("(%s).IsInf() = %v; want %v", test.x, got, test.inf)
+		}
+	}
+}
+
 func TestFloatIsInt(t *testing.T) {
 	for _, test := range []string{
 		"0 int",
@@ -300,10 +325,6 @@
 	}
 }
 
-func TestFloatIsInf(t *testing.T) {
-	// TODO(gri) implement this
-}
-
 func fromBinary(s string) int64 {
 	x, err := strconv.ParseInt(s, 2, 64)
 	if err != nil {
@@ -374,7 +395,7 @@
 	// should be the same as rounding by SetInt64 after setting the
 	// precision)
 	g := new(Float).SetMode(mode).SetPrec(prec).SetInt64(x)
-	if !feq(g, f) {
+	if !alike(g, f) {
 		t.Errorf("round %s (%d bits, %s) not symmetric: got %s and %s; want %s",
 			toBinary(x), prec, mode,
 			toBinary(g.int64()),
@@ -387,7 +408,7 @@
 	// h and f should be the same
 	// (repeated rounding should be idempotent)
 	h := new(Float).SetMode(mode).SetPrec(prec).Set(f)
-	if !feq(h, f) {
+	if !alike(h, f) {
 		t.Errorf("round %s (%d bits, %s) not idempotent: got %s and %s; want %s",
 			toBinary(x), prec, mode,
 			toBinary(h.int64()),
@@ -498,14 +519,14 @@
 
 // TestFloatRound24 tests that rounding a float64 to 24 bits
 // matches IEEE-754 rounding to nearest when converting a
-// float64 to a float32.
+// float64 to a float32 (excluding denormal numbers).
 func TestFloatRound24(t *testing.T) {
 	const x0 = 1<<26 - 0x10 // 11...110000 (26 bits)
 	for d := 0; d <= 0x10; d++ {
 		x := float64(x0 + d)
 		f := new(Float).SetPrec(24).SetFloat64(x)
-		got, _ := f.Float64()
-		want := float64(float32(x))
+		got, _ := f.Float32()
+		want := float32(x)
 		if got != want {
 			t.Errorf("Round(%g, 24) = %g; want %g", x, got, want)
 		}
@@ -588,6 +609,10 @@
 		3.14159265e10,
 		2.718281828e-123,
 		1.0 / 3,
+		math.MaxFloat32,
+		math.MaxFloat64,
+		math.SmallestNonzeroFloat32,
+		math.SmallestNonzeroFloat64,
 		math.Inf(-1),
 		math.Inf(0),
 		-math.Inf(1),
@@ -598,8 +623,8 @@
 			}
 			var f Float
 			f.SetFloat64(want)
-			if got, _ := f.Float64(); got != want {
-				t.Errorf("got %g (%s); want %g", got, f.Format('p', 0), want)
+			if got, acc := f.Float64(); got != want || acc != Exact {
+				t.Errorf("got %g (%s, %s); want %g (Exact)", got, f.Format('p', 0), acc, want)
 			}
 		}
 	}
@@ -614,6 +639,17 @@
 			t.Errorf("got %g (%s); want %g", got, f.Format('p', 0), want)
 		}
 	}
+
+	// test NaN
+	defer func() {
+		if p, ok := recover().(ErrNaN); !ok {
+			t.Errorf("got %v; want ErrNaN panic", p)
+		}
+	}()
+	var f Float
+	f.SetFloat64(math.NaN())
+	// should not reach here
+	t.Errorf("got %s; want ErrNaN panic", f.Format('p', 0))
 }
 
 func TestFloatSetInt(t *testing.T) {
@@ -694,6 +730,25 @@
 	}
 }
 
+func TestFloatSetInf(t *testing.T) {
+	var f Float
+	for _, test := range []struct {
+		signbit bool
+		prec    uint
+		want    string
+	}{
+		{false, 0, "+Inf"},
+		{true, 0, "-Inf"},
+		{false, 10, "+Inf"},
+		{true, 30, "-Inf"},
+	} {
+		x := f.SetPrec(test.prec).SetInf(test.signbit)
+		if got := x.String(); got != test.want || x.Prec() != test.prec {
+			t.Errorf("SetInf(%v) = %s (prec = %d); want %s (prec = %d)", test.signbit, got, x.Prec(), test.want, test.prec)
+		}
+	}
+}
+
 func TestFloatUint64(t *testing.T) {
 	for _, test := range []struct {
 		x   string
@@ -740,12 +795,14 @@
 		{"-12345.000000000000000000001", -12345, Above},
 		{"-12345.0", -12345, Exact},
 		{"-1.000000000000000000001", -1, Above},
+		{"-1.5", -1, Above},
 		{"-1", -1, Exact},
 		{"-1e-1000", 0, Above},
 		{"0", 0, Exact},
 		{"1e-1000", 0, Below},
 		{"1", 1, Exact},
 		{"1.000000000000000000001", 1, Below},
+		{"1.5", 1, Below},
 		{"12345.0", 12345, Exact},
 		{"12345.000000000000000000001", 12345, Below},
 		{"9223372036854775807", 9223372036854775807, Exact},
@@ -762,6 +819,128 @@
 	}
 }
 
+func TestFloatFloat32(t *testing.T) {
+	for _, test := range []struct {
+		x   string
+		out float32
+		acc Accuracy
+	}{
+		{"-Inf", float32(math.Inf(-1)), Exact},
+		{"-0x1.ffffff0p2147483646", float32(-math.Inf(+1)), Below}, // overflow in rounding
+		{"-1e10000", float32(math.Inf(-1)), Below},                 // overflow
+		{"-0x1p128", float32(math.Inf(-1)), Below},                 // overflow
+		{"-0x1.ffffff0p127", float32(-math.Inf(+1)), Below},        // overflow
+		{"-0x1.fffffe8p127", -math.MaxFloat32, Above},
+		{"-0x1.fffffe0p127", -math.MaxFloat32, Exact},
+		{"-12345.000000000000000000001", -12345, Above},
+		{"-12345.0", -12345, Exact},
+		{"-1.000000000000000000001", -1, Above},
+		{"-1", -1, Exact},
+		{"-0x0.000002p-126", -math.SmallestNonzeroFloat32, Exact},
+		{"-0x0.000002p-127", -0, Above}, // underflow
+		{"-1e-1000", -0, Above},         // underflow
+		{"0", 0, Exact},
+		{"1e-1000", 0, Below},         // underflow
+		{"0x0.000002p-127", 0, Below}, // underflow
+		{"0x0.000002p-126", math.SmallestNonzeroFloat32, Exact},
+		{"1", 1, Exact},
+		{"1.000000000000000000001", 1, Below},
+		{"12345.0", 12345, Exact},
+		{"12345.000000000000000000001", 12345, Below},
+		{"0x1.fffffe0p127", math.MaxFloat32, Exact},
+		{"0x1.fffffe8p127", math.MaxFloat32, Below},
+		{"0x1.ffffff0p127", float32(math.Inf(+1)), Above},        // overflow
+		{"0x1p128", float32(math.Inf(+1)), Above},                // overflow
+		{"1e10000", float32(math.Inf(+1)), Above},                // overflow
+		{"0x1.ffffff0p2147483646", float32(math.Inf(+1)), Above}, // overflow in rounding
+		{"+Inf", float32(math.Inf(+1)), Exact},
+	} {
+		// conversion should match strconv where syntax is agreeable
+		if f, err := strconv.ParseFloat(test.x, 32); err == nil && float32(f) != test.out {
+			t.Errorf("%s: got %g; want %g (incorrect test data)", test.x, f, test.out)
+		}
+
+		x := makeFloat(test.x)
+		out, acc := x.Float32()
+		if out != test.out || acc != test.acc {
+			t.Errorf("%s: got %g (%#x, %s); want %g (%#x, %s)", test.x, out, math.Float32bits(out), acc, test.out, math.Float32bits(test.out), test.acc)
+		}
+
+		// test that x.SetFloat64(float64(f)).Float32() == f
+		var x2 Float
+		out2, acc2 := x2.SetFloat64(float64(out)).Float32()
+		if out2 != out || acc2 != Exact {
+			t.Errorf("idempotency test: got %g (%s); want %g (Exact)", out2, acc2, out)
+		}
+	}
+}
+
+func TestFloatFloat64(t *testing.T) {
+	const smallestNormalFloat64 = 2.2250738585072014e-308 // 1p-1022
+	for _, test := range []struct {
+		x   string
+		out float64
+		acc Accuracy
+	}{
+		{"-Inf", math.Inf(-1), Exact},
+		{"-0x1.fffffffffffff8p2147483646", -math.Inf(+1), Below}, // overflow in rounding
+		{"-1e10000", math.Inf(-1), Below},                        // overflow
+		{"-0x1p1024", math.Inf(-1), Below},                       // overflow
+		{"-0x1.fffffffffffff8p1023", -math.Inf(+1), Below},       // overflow
+		{"-0x1.fffffffffffff4p1023", -math.MaxFloat64, Above},
+		{"-0x1.fffffffffffff0p1023", -math.MaxFloat64, Exact},
+		{"-12345.000000000000000000001", -12345, Above},
+		{"-12345.0", -12345, Exact},
+		{"-1.000000000000000000001", -1, Above},
+		{"-1", -1, Exact},
+		{"-0x0.0000000000001p-1022", -math.SmallestNonzeroFloat64, Exact},
+		{"-0x0.0000000000001p-1023", -0, Above}, // underflow
+		{"-1e-1000", -0, Above},                 // underflow
+		{"0", 0, Exact},
+		{"1e-1000", 0, Below},                 // underflow
+		{"0x0.0000000000001p-1023", 0, Below}, // underflow
+		{"0x0.0000000000001p-1022", math.SmallestNonzeroFloat64, Exact},
+		{"1", 1, Exact},
+		{"1.000000000000000000001", 1, Below},
+		{"12345.0", 12345, Exact},
+		{"12345.000000000000000000001", 12345, Below},
+		{"0x1.fffffffffffff0p1023", math.MaxFloat64, Exact},
+		{"0x1.fffffffffffff4p1023", math.MaxFloat64, Below},
+		{"0x1.fffffffffffff8p1023", math.Inf(+1), Above},       // overflow
+		{"0x1p1024", math.Inf(+1), Above},                      // overflow
+		{"1e10000", math.Inf(+1), Above},                       // overflow
+		{"0x1.fffffffffffff8p2147483646", math.Inf(+1), Above}, // overflow in rounding
+		{"+Inf", math.Inf(+1), Exact},
+
+		// selected denormalized values that were handled incorrectly in the past
+		{"0x.fffffffffffffp-1022", smallestNormalFloat64 - math.SmallestNonzeroFloat64, Exact},
+		{"4503599627370495p-1074", smallestNormalFloat64 - math.SmallestNonzeroFloat64, Exact},
+
+		// http://www.exploringbinary.com/php-hangs-on-numeric-value-2-2250738585072011e-308/
+		{"2.2250738585072011e-308", 2.225073858507201e-308, Below},
+		// http://www.exploringbinary.com/java-hangs-when-converting-2-2250738585072012e-308/
+		{"2.2250738585072012e-308", 2.2250738585072014e-308, Above},
+	} {
+		// conversion should match strconv where syntax is agreeable
+		if f, err := strconv.ParseFloat(test.x, 64); err == nil && f != test.out {
+			t.Errorf("%s: got %g; want %g (incorrect test data)", test.x, f, test.out)
+		}
+
+		x := makeFloat(test.x)
+		out, acc := x.Float64()
+		if out != test.out || acc != test.acc {
+			t.Errorf("%s: got %g (%#x, %s); want %g (%#x, %s)", test.x, out, math.Float64bits(out), acc, test.out, math.Float64bits(test.out), test.acc)
+		}
+
+		// test that x.SetFloat64(f).Float64() == f
+		var x2 Float
+		out2, acc2 := x2.SetFloat64(out).Float64()
+		if out2 != out || acc2 != Exact {
+			t.Errorf("idempotency test: got %g (%s); want %g (Exact)", out2, acc2, out)
+		}
+	}
+}
+
 func TestFloatInt(t *testing.T) {
 	for _, test := range []struct {
 		x    string
@@ -810,24 +989,25 @@
 func TestFloatRat(t *testing.T) {
 	for _, test := range []struct {
 		x, want string
+		acc     Accuracy
 	}{
-		{"0", "0/1"},
-		{"+0", "0/1"},
-		{"-0", "0/1"},
-		{"Inf", "nil"},
-		{"+Inf", "nil"},
-		{"-Inf", "nil"},
-		{"1", "1/1"},
-		{"-1", "-1/1"},
-		{"1.25", "5/4"},
-		{"-1.25", "-5/4"},
-		{"1e10", "10000000000/1"},
-		{"1p10", "1024/1"},
-		{"-1p-10", "-1/1024"},
-		{"3.14159265", "7244019449799623199/2305843009213693952"},
+		{"0", "0/1", Exact},
+		{"+0", "0/1", Exact},
+		{"-0", "0/1", Exact},
+		{"Inf", "nil", Below},
+		{"+Inf", "nil", Below},
+		{"-Inf", "nil", Above},
+		{"1", "1/1", Exact},
+		{"-1", "-1/1", Exact},
+		{"1.25", "5/4", Exact},
+		{"-1.25", "-5/4", Exact},
+		{"1e10", "10000000000/1", Exact},
+		{"1p10", "1024/1", Exact},
+		{"-1p-10", "-1/1024", Exact},
+		{"3.14159265", "7244019449799623199/2305843009213693952", Exact},
 	} {
 		x := makeFloat(test.x).SetPrec(64)
-		res := x.Rat(nil)
+		res, acc := x.Rat(nil)
 		got := "nil"
 		if res != nil {
 			got = res.String()
@@ -836,6 +1016,10 @@
 			t.Errorf("%s: got %s; want %s", test.x, got, test.want)
 			continue
 		}
+		if acc != test.acc {
+			t.Errorf("%s: got %s; want %s", test.x, acc, test.acc)
+			continue
+		}
 
 		// inverse conversion
 		if res != nil {
@@ -850,7 +1034,7 @@
 	for _, f := range []string{"0", "1", "-1", "1234"} {
 		x := makeFloat(f)
 		r := new(Rat)
-		if res := x.Rat(r); res != r {
+		if res, _ := x.Rat(r); res != r {
 			t.Errorf("(%s).Rat is not using supplied *Rat", f)
 		}
 	}
@@ -868,13 +1052,13 @@
 	} {
 		p := makeFloat(test)
 		a := new(Float).Abs(p)
-		if !feq(a, p) {
+		if !alike(a, p) {
 			t.Errorf("%s: got %s; want %s", test, a.Format('g', 10), test)
 		}
 
 		n := makeFloat("-" + test)
 		a.Abs(n)
-		if !feq(a, p) {
+		if !alike(a, p) {
 			t.Errorf("-%s: got %s; want %s", test, a.Format('g', 10), test)
 		}
 	}
@@ -894,10 +1078,10 @@
 		n1 := makeFloat("-" + test)
 		n2 := new(Float).Neg(p1)
 		p2 := new(Float).Neg(n2)
-		if !feq(n2, n1) {
+		if !alike(n2, n1) {
 			t.Errorf("%s: got %s; want %s", test, n2.Format('g', 10), n1.Format('g', 10))
 		}
-		if !feq(p2, p1) {
+		if !alike(p2, p1) {
 			t.Errorf("%s: got %s; want %s", test, p2.Format('g', 10), p1.Format('g', 10))
 		}
 	}
@@ -926,7 +1110,7 @@
 
 // Selected bits with which to run various tests.
 // Each entry is a list of bits representing a floating-point number (see fromBits).
-var bitsList = [...][]int{
+var bitsList = [...]Bits{
 	{},           // = 0
 	{0},          // = 1
 	{1},          // = 2
@@ -939,31 +1123,30 @@
 }
 
 // TestFloatAdd tests Float.Add/Sub by comparing the result of a "manual"
-// addition/subtraction of arguments represented by bits lists with the
-// respective floating-point addition/subtraction for a variety of precisions
+// addition/subtraction of arguments represented by Bits values with the
+// respective Float addition/subtraction for a variety of precisions
 // and rounding modes.
 func TestFloatAdd(t *testing.T) {
 	for _, xbits := range bitsList {
 		for _, ybits := range bitsList {
 			// exact values
-			x := fromBits(xbits...)
-			y := fromBits(ybits...)
-			zbits := append(xbits, ybits...)
-			z := fromBits(zbits...)
+			x := xbits.Float()
+			y := ybits.Float()
+			zbits := xbits.add(ybits)
+			z := zbits.Float()
 
 			for i, mode := range [...]RoundingMode{ToZero, ToNearestEven, AwayFromZero} {
 				for _, prec := range precList {
 					got := new(Float).SetPrec(prec).SetMode(mode)
 					got.Add(x, y)
-					want := roundBits(zbits, prec, mode)
+					want := zbits.round(prec, mode)
 					if got.Cmp(want) != 0 {
 						t.Errorf("i = %d, prec = %d, %s:\n\t     %s %v\n\t+    %s %v\n\t=    %s\n\twant %s",
 							i, prec, mode, x, xbits, y, ybits, got, want)
-						return
 					}
 
 					got.Sub(z, x)
-					want = roundBits(ybits, prec, mode)
+					want = ybits.round(prec, mode)
 					if got.Cmp(want) != 0 {
 						t.Errorf("i = %d, prec = %d, %s:\n\t     %s %v\n\t-    %s %v\n\t=    %s\n\twant %s",
 							i, prec, mode, z, zbits, x, xbits, got, want)
@@ -975,13 +1158,9 @@
 }
 
 // TestFloatAdd32 tests that Float.Add/Sub of numbers with
-// 24bit mantissa behaves like float32 addition/subtraction.
+// 24bit mantissa behaves like float32 addition/subtraction
+// (excluding denormal numbers).
 func TestFloatAdd32(t *testing.T) {
-	// TODO(gri) fix test for 32bit platforms
-	if _W == 32 {
-		return
-	}
-
 	// chose base such that we cross the mantissa precision limit
 	const base = 1<<26 - 0x10 // 11...110000 (26 bits)
 	for d := 0; d <= 0x10; d++ {
@@ -991,22 +1170,22 @@
 				x0, y0 = y0, x0
 			}
 
-			x := new(Float).SetFloat64(x0)
-			y := new(Float).SetFloat64(y0)
+			x := NewFloat(x0)
+			y := NewFloat(y0)
 			z := new(Float).SetPrec(24)
 
 			z.Add(x, y)
-			got, acc := z.Float64()
-			want := float64(float32(y0) + float32(x0))
+			got, acc := z.Float32()
+			want := float32(y0) + float32(x0)
 			if got != want || acc != Exact {
-				t.Errorf("d = %d: %g + %g = %g (%s); want %g exactly", d, x0, y0, got, acc, want)
+				t.Errorf("d = %d: %g + %g = %g (%s); want %g (Exact)", d, x0, y0, got, acc, want)
 			}
 
 			z.Sub(z, y)
-			got, acc = z.Float64()
-			want = float64(float32(want) - float32(y0))
+			got, acc = z.Float32()
+			want = float32(want) - float32(y0)
 			if got != want || acc != Exact {
-				t.Errorf("d = %d: %g - %g = %g (%s); want %g exactly", d, x0+y0, y0, got, acc, want)
+				t.Errorf("d = %d: %g - %g = %g (%s); want %g (Exact)", d, x0+y0, y0, got, acc, want)
 			}
 		}
 	}
@@ -1024,29 +1203,63 @@
 				x0, y0 = y0, x0
 			}
 
-			x := new(Float).SetFloat64(x0)
-			y := new(Float).SetFloat64(y0)
+			x := NewFloat(x0)
+			y := NewFloat(y0)
 			z := new(Float).SetPrec(53)
 
 			z.Add(x, y)
 			got, acc := z.Float64()
 			want := x0 + y0
 			if got != want || acc != Exact {
-				t.Errorf("d = %d: %g + %g = %g (%s); want %g exactly", d, x0, y0, got, acc, want)
+				t.Errorf("d = %d: %g + %g = %g (%s); want %g (Exact)", d, x0, y0, got, acc, want)
 			}
 
 			z.Sub(z, y)
 			got, acc = z.Float64()
 			want -= y0
 			if got != want || acc != Exact {
-				t.Errorf("d = %d: %g - %g = %g (%s); want %g exactly", d, x0+y0, y0, got, acc, want)
+				t.Errorf("d = %d: %g - %g = %g (%s); want %g (Exact)", d, x0+y0, y0, got, acc, want)
 			}
 		}
 	}
 }
 
+// TestFloatMul tests Float.Mul/Quo by comparing the result of a "manual"
+// multiplication/division of arguments represented by Bits values with the
+// respective Float multiplication/division for a variety of precisions
+// and rounding modes.
 func TestFloatMul(t *testing.T) {
-	// TODO(gri) implement this
+	for _, xbits := range bitsList {
+		for _, ybits := range bitsList {
+			// exact values
+			x := xbits.Float()
+			y := ybits.Float()
+			zbits := xbits.mul(ybits)
+			z := zbits.Float()
+
+			for i, mode := range [...]RoundingMode{ToZero, ToNearestEven, AwayFromZero} {
+				for _, prec := range precList {
+					got := new(Float).SetPrec(prec).SetMode(mode)
+					got.Mul(x, y)
+					want := zbits.round(prec, mode)
+					if got.Cmp(want) != 0 {
+						t.Errorf("i = %d, prec = %d, %s:\n\t     %s %v\n\t*    %s %v\n\t=    %s\n\twant %s",
+							i, prec, mode, x, xbits, y, ybits, got, want)
+					}
+
+					if x.Sign() == 0 {
+						continue // ignore div-0 case (not invertable)
+					}
+					got.Quo(z, x)
+					want = ybits.round(prec, mode)
+					if got.Cmp(want) != 0 {
+						t.Errorf("i = %d, prec = %d, %s:\n\t     %s %v\n\t/    %s %v\n\t=    %s\n\twant %s",
+							i, prec, mode, z, zbits, x, xbits, got, want)
+					}
+				}
+			}
+		}
+	}
 }
 
 // TestFloatMul64 tests that Float.Mul/Quo of numbers with
@@ -1076,8 +1289,8 @@
 				x0, y0 = y0, x0
 			}
 
-			x := new(Float).SetFloat64(x0)
-			y := new(Float).SetFloat64(y0)
+			x := NewFloat(x0)
+			y := NewFloat(y0)
 			z := new(Float).SetPrec(53)
 
 			z.Mul(x, y)
@@ -1141,7 +1354,7 @@
 
 	for i := 0; i < 8; i++ {
 		// compute accurate (not rounded) result z
-		bits := []int{preci - 1}
+		bits := Bits{preci - 1}
 		if i&3 != 0 {
 			bits = append(bits, 0)
 		}
@@ -1151,10 +1364,10 @@
 		if i&1 != 0 {
 			bits = append(bits, -precf)
 		}
-		z := fromBits(bits...)
+		z := bits.Float()
 
 		// compute accurate x as z*y
-		y := new(Float).SetFloat64(3.14159265358979323e123)
+		y := NewFloat(3.14159265358979323e123)
 
 		x := new(Float).SetPrec(z.Prec() + y.Prec()).SetMode(ToZero)
 		x.Mul(z, y)
@@ -1172,7 +1385,7 @@
 			for d := -5; d < 5; d++ {
 				prec := uint(preci + d)
 				got := new(Float).SetPrec(prec).SetMode(mode).Quo(x, y)
-				want := roundBits(bits, prec, mode)
+				want := bits.round(prec, mode)
 				if got.Cmp(want) != 0 {
 					t.Errorf("i = %d, prec = %d, %s:\n\t     %s\n\t/    %s\n\t=    %s\n\twant %s",
 						i, prec, mode, x, y, got, want)
@@ -1223,6 +1436,129 @@
 	}
 }
 
+// TestFloatArithmeticSpecialValues tests that Float operations produce the
+// correct results for combinations of zero (±0), finite (±1 and ±2.71828),
+// and non-finite (±Inf) operands.
+func TestFloatArithmeticSpecialValues(t *testing.T) {
+	zero := 0.0
+	args := []float64{math.Inf(-1), -2.71828, -1, -zero, zero, 1, 2.71828, math.Inf(1)}
+	xx := new(Float)
+	yy := new(Float)
+	got := new(Float)
+	want := new(Float)
+	for i := 0; i < 4; i++ {
+		for _, x := range args {
+			xx.SetFloat64(x)
+			// check conversion is correct
+			// (no need to do this for y, since we see exactly the
+			// same values there)
+			if got, acc := xx.Float64(); got != x || acc != Exact {
+				t.Errorf("Float(%g) == %g (%s)", x, got, acc)
+			}
+			for _, y := range args {
+				// At the moment an Inf operand always leads to a panic (known bug).
+				// TODO(gri) remove this once the bug is fixed.
+				if math.IsInf(x, 0) || math.IsInf(y, 0) {
+					continue
+				}
+				yy.SetFloat64(y)
+				var op string
+				var z float64
+				switch i {
+				case 0:
+					op = "+"
+					z = x + y
+					got.Add(xx, yy)
+				case 1:
+					op = "-"
+					z = x - y
+					got.Sub(xx, yy)
+				case 2:
+					op = "*"
+					z = x * y
+					got.Mul(xx, yy)
+				case 3:
+					if x == 0 && y == 0 {
+						// TODO(gri) check for ErrNaN
+						continue // 0/0 panics with ErrNaN
+					}
+					op = "/"
+					z = x / y
+					got.Quo(xx, yy)
+				default:
+					panic("unreachable")
+				}
+				want.SetFloat64(z)
+				if !alike(got, want) {
+					t.Errorf("%5g %s %5g = %5s; want %5s", x, op, y, got, want)
+				}
+			}
+		}
+	}
+}
+
+func TestFloatArithmeticOverflow(t *testing.T) {
+	for _, test := range []struct {
+		prec       uint
+		mode       RoundingMode
+		op         byte
+		x, y, want string
+		acc        Accuracy
+	}{
+		{4, ToNearestEven, '+', "0", "0", "0", Exact},                // smoke test
+		{4, ToNearestEven, '+', "0x.8p0", "0x.8p0", "0x.8p1", Exact}, // smoke test
+
+		{4, ToNearestEven, '+', "0", "0x.8p2147483647", "0x.8p2147483647", Exact},
+		{4, ToNearestEven, '+', "0x.8p2147483500", "0x.8p2147483647", "0x.8p2147483647", Below}, // rounded to zero
+		{4, ToNearestEven, '+', "0x.8p2147483647", "0x.8p2147483647", "+Inf", Above},            // exponent overflow in +
+		{4, ToNearestEven, '+', "-0x.8p2147483647", "-0x.8p2147483647", "-Inf", Below},          // exponent overflow in +
+		{4, ToNearestEven, '-', "-0x.8p2147483647", "0x.8p2147483647", "-Inf", Below},           // exponent overflow in -
+
+		{4, ToZero, '+', "0x.fp2147483647", "0x.8p2147483643", "0x.fp2147483647", Below}, // rounded to zero
+		{4, ToNearestEven, '+', "0x.fp2147483647", "0x.8p2147483643", "+Inf", Above},     // exponent overflow in rounding
+		{4, AwayFromZero, '+', "0x.fp2147483647", "0x.8p2147483643", "+Inf", Above},      // exponent overflow in rounding
+
+		{4, AwayFromZero, '-', "-0x.fp2147483647", "0x.8p2147483644", "-Inf", Below},       // exponent overflow in rounding
+		{4, ToNearestEven, '-', "-0x.fp2147483647", "0x.8p2147483643", "-Inf", Below},      // exponent overflow in rounding
+		{4, ToZero, '-', "-0x.fp2147483647", "0x.8p2147483643", "-0x.fp2147483647", Above}, // rounded to zero
+
+		{4, ToNearestEven, '+', "0", "0x.8p-2147483648", "0x.8p-2147483648", Exact},
+		{4, ToNearestEven, '+', "0x.8p-2147483648", "0x.8p-2147483648", "0x.8p-2147483647", Exact},
+
+		{4, ToNearestEven, '*', "1", "0x.8p2147483647", "0x.8p2147483647", Exact},
+		{4, ToNearestEven, '*', "2", "0x.8p2147483647", "+Inf", Above},  // exponent overflow in *
+		{4, ToNearestEven, '*', "-2", "0x.8p2147483647", "-Inf", Below}, // exponent overflow in *
+
+		{4, ToNearestEven, '/', "0.5", "0x.8p2147483647", "0x.8p-2147483646", Exact},
+		{4, ToNearestEven, '/', "0x.8p0", "0x.8p2147483647", "0x.8p-2147483646", Exact},
+		{4, ToNearestEven, '/', "0x.8p-1", "0x.8p2147483647", "0x.8p-2147483647", Exact},
+		{4, ToNearestEven, '/', "0x.8p-2", "0x.8p2147483647", "0x.8p-2147483648", Exact},
+		{4, ToNearestEven, '/', "0x.8p-3", "0x.8p2147483647", "0", Below}, // exponent underflow in /
+	} {
+		x := makeFloat(test.x)
+		y := makeFloat(test.y)
+		z := new(Float).SetPrec(test.prec).SetMode(test.mode)
+		switch test.op {
+		case '+':
+			z.Add(x, y)
+		case '-':
+			z.Sub(x, y)
+		case '*':
+			z.Mul(x, y)
+		case '/':
+			z.Quo(x, y)
+		default:
+			panic("unreachable")
+		}
+		if got := z.Format('p', 0); got != test.want || z.Acc() != test.acc {
+			t.Errorf(
+				"prec = %d (%s): %s %c %s = %s (%s); want %s (%s)",
+				test.prec, test.mode, x.Format('p', 0), test.op, y.Format('p', 0), got, z.Acc(), test.want, test.acc,
+			)
+		}
+	}
+}
+
 // TODO(gri) Add tests that check correctness in the presence of aliasing.
 
 // For rounding modes ToNegativeInf and ToPositiveInf, rounding is affected
@@ -1277,167 +1613,37 @@
 	}
 }
 
-func TestFloatCmp(t *testing.T) {
-	// TODO(gri) implement this
-}
-
-// normBits returns the normalized bits for x: It
-// removes multiple equal entries by treating them
-// as an addition (e.g., []int{5, 5} => []int{6}),
-// and it sorts the result list for reproducible
-// results.
-func normBits(x []int) []int {
-	m := make(map[int]bool)
-	for _, b := range x {
-		for m[b] {
-			m[b] = false
-			b++
-		}
-		m[b] = true
-	}
-	var z []int
-	for b, set := range m {
-		if set {
-			z = append(z, b)
-		}
-	}
-	sort.Ints(z)
-	return z
-}
-
-func TestNormBits(t *testing.T) {
-	for _, test := range []struct {
-		x, want []int
-	}{
-		{nil, nil},
-		{[]int{}, []int{}},
-		{[]int{0}, []int{0}},
-		{[]int{0, 0}, []int{1}},
-		{[]int{3, 1, 1}, []int{2, 3}},
-		{[]int{10, 9, 8, 7, 6, 6}, []int{11}},
-	} {
-		got := fmt.Sprintf("%v", normBits(test.x))
-		want := fmt.Sprintf("%v", test.want)
-		if got != want {
-			t.Errorf("normBits(%v) = %s; want %s", test.x, got, want)
-		}
-
-	}
-}
-
-// roundBits returns the Float value rounded to prec bits
-// according to mode from the bit set x.
-func roundBits(x []int, prec uint, mode RoundingMode) *Float {
-	x = normBits(x)
-
-	// determine range
-	var min, max int
-	for i, b := range x {
-		if i == 0 || b < min {
-			min = b
-		}
-		if i == 0 || b > max {
-			max = b
-		}
-	}
-	prec0 := uint(max + 1 - min)
-	if prec >= prec0 {
-		return fromBits(x...)
-	}
-	// prec < prec0
-
-	// determine bit 0, rounding, and sticky bit, and result bits z
-	var bit0, rbit, sbit uint
-	var z []int
-	r := max - int(prec)
-	for _, b := range x {
-		switch {
-		case b == r:
-			rbit = 1
-		case b < r:
-			sbit = 1
-		default:
-			// b > r
-			if b == r+1 {
-				bit0 = 1
+// TestFloatCmpSpecialValues tests that Cmp produces the correct results for
+// combinations of zero (±0), finite (±1 and ±2.71828), and non-finite (±Inf)
+// operands.
+func TestFloatCmpSpecialValues(t *testing.T) {
+	zero := 0.0
+	args := []float64{math.Inf(-1), -2.71828, -1, -zero, zero, 1, 2.71828, math.Inf(1)}
+	xx := new(Float)
+	yy := new(Float)
+	for i := 0; i < 4; i++ {
+		for _, x := range args {
+			xx.SetFloat64(x)
+			// check conversion is correct
+			// (no need to do this for y, since we see exactly the
+			// same values there)
+			if got, acc := xx.Float64(); got != x || acc != Exact {
+				t.Errorf("Float(%g) == %g (%s)", x, got, acc)
 			}
-			z = append(z, b)
-		}
-	}
-
-	// round
-	f := fromBits(z...) // rounded to zero
-	if mode == ToNearestAway {
-		panic("not yet implemented")
-	}
-	if mode == ToNearestEven && rbit == 1 && (sbit == 1 || sbit == 0 && bit0 != 0) || mode == AwayFromZero {
-		// round away from zero
-		f.SetMode(ToZero).SetPrec(prec)
-		f.Add(f, fromBits(int(r)+1))
-	}
-	return f
-}
-
-// fromBits returns the *Float z of the smallest possible precision
-// such that z = sum(2**bits[i]), with i = range bits.
-// If multiple bits[i] are equal, they are added: fromBits(0, 1, 0)
-// == 2**1 + 2**0 + 2**0 = 4.
-func fromBits(bits ...int) *Float {
-	// handle 0
-	if len(bits) == 0 {
-		return new(Float)
-	}
-	// len(bits) > 0
-
-	// determine lsb exponent
-	var min int
-	for i, b := range bits {
-		if i == 0 || b < min {
-			min = b
-		}
-	}
-
-	// create bit pattern
-	x := NewInt(0)
-	for _, b := range bits {
-		badj := b - min
-		// propagate carry if necessary
-		for x.Bit(badj) != 0 {
-			x.SetBit(x, badj, 0)
-			badj++
-		}
-		x.SetBit(x, badj, 1)
-	}
-
-	// create corresponding float
-	z := new(Float).SetInt(x) // normalized
-	z.setExp(int64(z.exp) + int64(min))
-	return z
-}
-
-func TestFromBits(t *testing.T) {
-	for _, test := range []struct {
-		bits []int
-		want string
-	}{
-		// all different bit numbers
-		{nil, "0"},
-		{[]int{0}, "0x.8p1"},
-		{[]int{1}, "0x.8p2"},
-		{[]int{-1}, "0x.8p0"},
-		{[]int{63}, "0x.8p64"},
-		{[]int{33, -30}, "0x.8000000000000001p34"},
-		{[]int{255, 0}, "0x.8000000000000000000000000000000000000000000000000000000000000001p256"},
-
-		// multiple equal bit numbers
-		{[]int{0, 0}, "0x.8p2"},
-		{[]int{0, 0, 0, 0}, "0x.8p3"},
-		{[]int{0, 1, 0}, "0x.8p3"},
-		{append([]int{2, 1, 0} /* 7 */, []int{3, 1} /* 10 */ ...), "0x.88p5" /* 17 */},
-	} {
-		f := fromBits(test.bits...)
-		if got := f.Format('p', 0); got != test.want {
-			t.Errorf("setBits(%v) = %s; want %s", test.bits, got, test.want)
+			for _, y := range args {
+				yy.SetFloat64(y)
+				got := xx.Cmp(yy)
+				want := 0
+				switch {
+				case x < y:
+					want = -1
+				case x > y:
+					want = +1
+				}
+				if got != want {
+					t.Errorf("(%g).Cmp(%g) = %s; want %s", x, y, got, want)
+				}
+			}
 		}
 	}
 }
diff --git a/src/math/big/floatconv.go b/src/math/big/floatconv.go
index b1b028c..7dc9a28 100644
--- a/src/math/big/floatconv.go
+++ b/src/math/big/floatconv.go
@@ -63,12 +63,19 @@
 // be binary, if present (an "e" or "E" exponent indicator cannot be
 // distinguished from a mantissa digit).
 //
-// BUG(gri) This signature conflicts with Scan(s fmt.ScanState, ch rune) error.
+// The returned *Float f is nil and the value of z is valid but not
+// defined if an error is reported.
+//
+// BUG(gri) The Float.Scan signature conflicts with Scan(s fmt.ScanState, ch rune) error.
 func (z *Float) Scan(r io.ByteScanner, base int) (f *Float, b int, err error) {
-	if z.prec == 0 {
-		z.prec = 64
+	prec := z.prec
+	if prec == 0 {
+		prec = 64
 	}
 
+	// A reasonable value in case of an error.
+	z.form = zero
+
 	// sign
 	z.neg, err = scanSign(r)
 	if err != nil {
@@ -90,13 +97,12 @@
 		return
 	}
 
-	// set result
-	f = z
-
 	// special-case 0
 	if len(z.mant) == 0 {
+		z.prec = prec
 		z.acc = Exact
-		z.exp = 0
+		z.form = zero
+		f = z
 		return
 	}
 	// len(z.mant) > 0
@@ -140,7 +146,15 @@
 	// we don't need exp anymore
 
 	// apply 2**exp2
-	z.setExp(exp2)
+	if MinExp <= exp2 && exp2 <= MaxExp {
+		z.prec = prec
+		z.form = finite
+		z.exp = int32(exp2)
+		f = z
+	} else {
+		err = fmt.Errorf("exponent overflow")
+		return
+	}
 
 	if exp10 == 0 {
 		// no decimal exponent to consider
@@ -158,7 +172,6 @@
 	fpowTen := new(Float).SetInt(new(Int).SetBits(powTen))
 
 	// apply 10**exp10
-	// (uquo and umul do the rounding)
 	if exp10 < 0 {
 		z.uquo(z, fpowTen)
 	} else {
@@ -169,8 +182,8 @@
 }
 
 // Parse is like z.Scan(r, base), but instead of reading from an
-// io.ByteScanner, it parses the string s. An error is returned if
-// the string contains invalid or trailing bytes not belonging to
+// io.ByteScanner, it parses the string s. An error is also returned
+// if the string contains invalid or trailing bytes not belonging to
 // the number.
 func (z *Float) Parse(s string, base int) (f *Float, b int, err error) {
 	r := strings.NewReader(s)
@@ -224,7 +237,7 @@
 // number of digits necessary such that ParseFloat will return f exactly.
 // The prec value is ignored for the 'b' or 'p' format.
 //
-// BUG(gri) Currently, Format does not accept negative precisions.
+// BUG(gri) Float.Format does not accept negative precisions.
 func (x *Float) Format(format byte, prec int) string {
 	const extra = 10 // TODO(gri) determine a good/better value here
 	return string(x.Append(make([]byte, 0, prec+extra), format, prec))
@@ -236,7 +249,7 @@
 	// TODO(gri) factor out handling of sign?
 
 	// Inf
-	if x.IsInf(0) {
+	if x.IsInf() {
 		var ch byte = '+'
 		if x.neg {
 			ch = '-'
@@ -256,7 +269,7 @@
 	return x.bigFtoa(buf, format, prec)
 }
 
-// BUG(gri): Currently, String uses x.Format('g', 10) rather than x.Format('g', -1).
+// BUG(gri): Float.String uses x.Format('g', 10) rather than x.Format('g', -1).
 func (x *Float) String() string {
 	return x.Format('g', 10)
 }
@@ -270,9 +283,13 @@
 	if x.neg {
 		buf = append(buf, '-')
 	}
-	if len(x.mant) == 0 {
+	if x.form == zero {
 		return append(buf, '0')
 	}
+
+	if debugFloat && x.form != finite {
+		panic("non-finite float")
+	}
 	// x != 0
 
 	// adjust mantissa to use exactly x.prec bits
@@ -301,9 +318,13 @@
 	if x.neg {
 		buf = append(buf, '-')
 	}
-	if len(x.mant) == 0 {
+	if x.form == zero {
 		return append(buf, '0')
 	}
+
+	if debugFloat && x.form != finite {
+		panic("non-finite float")
+	}
 	// x != 0
 
 	// remove trailing 0 words early
diff --git a/src/math/big/floatexample_test.go b/src/math/big/floatexample_test.go
new file mode 100644
index 0000000..7db1023
--- /dev/null
+++ b/src/math/big/floatexample_test.go
@@ -0,0 +1,111 @@
+// Copyright 2015 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 big_test
+
+import (
+	"fmt"
+	"math"
+	"math/big"
+)
+
+func ExampleFloat_Add() {
+	// Operating on numbers of different precision.
+	var x, y, z big.Float
+	x.SetInt64(1000)          // x is automatically set to 64bit precision
+	y.SetFloat64(2.718281828) // y is automatically set to 53bit precision
+	z.SetPrec(32)
+	z.Add(&x, &y)
+	fmt.Printf("x = %s (%s, prec = %d, acc = %s)\n", &x, x.Format('p', 0), x.Prec(), x.Acc())
+	fmt.Printf("y = %s (%s, prec = %d, acc = %s)\n", &y, y.Format('p', 0), y.Prec(), y.Acc())
+	fmt.Printf("z = %s (%s, prec = %d, acc = %s)\n", &z, z.Format('p', 0), z.Prec(), z.Acc())
+	// Output:
+	// x = 1000 (0x.fap10, prec = 64, acc = Exact)
+	// y = 2.718281828 (0x.adf85458248cd8p2, prec = 53, acc = Exact)
+	// z = 1002.718282 (0x.faadf854p10, prec = 32, acc = Below)
+}
+
+func Example_Shift() {
+	// Implementing Float "shift" by modifying the (binary) exponents directly.
+	for s := -5; s <= 5; s++ {
+		x := big.NewFloat(0.5)
+		x.SetMantExp(x, x.MantExp(nil)+s) // shift x by s
+		fmt.Println(x)
+	}
+	// Output:
+	// 0.015625
+	// 0.03125
+	// 0.0625
+	// 0.125
+	// 0.25
+	// 0.5
+	// 1
+	// 2
+	// 4
+	// 8
+	// 16
+}
+
+func ExampleFloat_Cmp() {
+	inf := math.Inf(1)
+	zero := 0.0
+
+	operands := []float64{-inf, -1.2, -zero, 0, +1.2, +inf}
+
+	fmt.Println("   x     y  cmp")
+	fmt.Println("---------------")
+	for _, x64 := range operands {
+		x := big.NewFloat(x64)
+		for _, y64 := range operands {
+			y := big.NewFloat(y64)
+			fmt.Printf("%4s  %4s  %3d\n", x, y, x.Cmp(y))
+		}
+		fmt.Println()
+	}
+
+	// Output:
+	//    x     y  cmp
+	// ---------------
+	// -Inf  -Inf    0
+	// -Inf  -1.2   -1
+	// -Inf    -0   -1
+	// -Inf     0   -1
+	// -Inf   1.2   -1
+	// -Inf  +Inf   -1
+	//
+	// -1.2  -Inf    1
+	// -1.2  -1.2    0
+	// -1.2    -0   -1
+	// -1.2     0   -1
+	// -1.2   1.2   -1
+	// -1.2  +Inf   -1
+	//
+	//   -0  -Inf    1
+	//   -0  -1.2    1
+	//   -0    -0    0
+	//   -0     0    0
+	//   -0   1.2   -1
+	//   -0  +Inf   -1
+	//
+	//    0  -Inf    1
+	//    0  -1.2    1
+	//    0    -0    0
+	//    0     0    0
+	//    0   1.2   -1
+	//    0  +Inf   -1
+	//
+	//  1.2  -Inf    1
+	//  1.2  -1.2    1
+	//  1.2    -0    1
+	//  1.2     0    1
+	//  1.2   1.2    0
+	//  1.2  +Inf   -1
+	//
+	// +Inf  -Inf    1
+	// +Inf  -1.2    1
+	// +Inf    -0    1
+	// +Inf     0    1
+	// +Inf   1.2    1
+	// +Inf  +Inf    0
+}
diff --git a/src/math/big/ftoa.go b/src/math/big/ftoa.go
index 1480815..0a9edfd 100644
--- a/src/math/big/ftoa.go
+++ b/src/math/big/ftoa.go
@@ -19,11 +19,17 @@
 
 // bigFtoa formats a float for the %e, %E, %f, %g, and %G formats.
 func (f *Float) bigFtoa(buf []byte, fmt byte, prec int) []byte {
-	// TODO(gri) handle Inf.
+	if debugFloat && f.IsInf() {
+		panic("non-finite float")
+	}
 
 	// 1) convert Float to multiprecision decimal
+	var mant nat
+	if f.form == finite {
+		mant = f.mant
+	}
 	var d decimal
-	d.init(f.mant, int(f.exp)-f.mant.bitLen())
+	d.init(mant, int(f.exp)-f.mant.bitLen())
 
 	// 2) round to desired precision
 	shortest := false
diff --git a/src/math/big/int.go b/src/math/big/int.go
index 0695d78..3410ec4 100644
--- a/src/math/big/int.go
+++ b/src/math/big/int.go
@@ -184,6 +184,10 @@
 
 // Binomial sets z to the binomial coefficient of (n, k) and returns z.
 func (z *Int) Binomial(n, k int64) *Int {
+	// reduce the number of multiplications by reducing k
+	if n/2 < k && k <= n {
+		k = n - k // Binomial(n, k) == Binomial(n, n-k)
+	}
 	var a, b Int
 	a.MulRange(n-k+1, n)
 	b.MulRange(1, k)
diff --git a/src/math/big/int_test.go b/src/math/big/int_test.go
index dff8057..a972a72 100644
--- a/src/math/big/int_test.go
+++ b/src/math/big/int_test.go
@@ -219,6 +219,45 @@
 	}
 }
 
+func TestBinomial(t *testing.T) {
+	var z Int
+	for _, test := range []struct {
+		n, k int64
+		want string
+	}{
+		{0, 0, "1"},
+		{0, 1, "0"},
+		{1, 0, "1"},
+		{1, 1, "1"},
+		{1, 10, "0"},
+		{4, 0, "1"},
+		{4, 1, "4"},
+		{4, 2, "6"},
+		{4, 3, "4"},
+		{4, 4, "1"},
+		{10, 1, "10"},
+		{10, 9, "10"},
+		{10, 5, "252"},
+		{11, 5, "462"},
+		{11, 6, "462"},
+		{100, 10, "17310309456440"},
+		{100, 90, "17310309456440"},
+		{1000, 10, "263409560461970212832400"},
+		{1000, 990, "263409560461970212832400"},
+	} {
+		if got := z.Binomial(test.n, test.k).String(); got != test.want {
+			t.Errorf("Binomial(%d, %d) = %s; want %s", test.n, test.k, got, test.want)
+		}
+	}
+}
+
+func BenchmarkBinomial(b *testing.B) {
+	var z Int
+	for i := b.N - 1; i >= 0; i-- {
+		z.Binomial(1000, 990)
+	}
+}
+
 // Examples from the Go Language Spec, section "Arithmetic operators"
 var divisionSignsTests = []struct {
 	x, y int64
@@ -353,7 +392,7 @@
 }
 
 func TestBytes(t *testing.T) {
-	if err := quick.Check(checkSetBytes, nil); err != nil {
+	if err := quick.Check(checkBytes, nil); err != nil {
 		t.Error(err)
 	}
 }
diff --git a/src/math/big/nat.go b/src/math/big/nat.go
index db730d1..2a279d1 100644
--- a/src/math/big/nat.go
+++ b/src/math/big/nat.go
@@ -335,7 +335,7 @@
 	}
 }
 
-// alias returns true if x and y share the same base array.
+// alias reports whether x and y share the same base array.
 func alias(x, y nat) bool {
 	return cap(x) > 0 && cap(y) > 0 && &x[0:cap(x)][cap(x)-1] == &y[0:cap(y)][cap(y)-1]
 }
@@ -819,7 +819,7 @@
 	return z.norm()
 }
 
-// greaterThan returns true iff (x1<<_W + x2) > (y1<<_W + y2)
+// greaterThan reports whether (x1<<_W + x2) > (y1<<_W + y2)
 func greaterThan(x1, x2, y1, y2 Word) bool {
 	return x1 > y1 || x1 == y1 && x2 > y2
 }
diff --git a/src/math/big/rat.go b/src/math/big/rat.go
index b73377e..748796c 100644
--- a/src/math/big/rat.go
+++ b/src/math/big/rat.go
@@ -385,7 +385,7 @@
 	return x.a.Sign()
 }
 
-// IsInt returns true if the denominator of x is 1.
+// IsInt reports whether the denominator of x is 1.
 func (x *Rat) IsInt() bool {
 	return len(x.b.abs) == 0 || x.b.abs.cmp(natOne) == 0
 }
diff --git a/src/math/big/roundingmode_string.go b/src/math/big/roundingmode_string.go
new file mode 100644
index 0000000..05024b8
--- /dev/null
+++ b/src/math/big/roundingmode_string.go
@@ -0,0 +1,16 @@
+// generated by stringer -type=RoundingMode; DO NOT EDIT
+
+package big
+
+import "fmt"
+
+const _RoundingMode_name = "ToNearestEvenToNearestAwayToZeroAwayFromZeroToNegativeInfToPositiveInf"
+
+var _RoundingMode_index = [...]uint8{0, 13, 26, 32, 44, 57, 70}
+
+func (i RoundingMode) String() string {
+	if i+1 >= RoundingMode(len(_RoundingMode_index)) {
+		return fmt.Sprintf("RoundingMode(%d)", i)
+	}
+	return _RoundingMode_name[_RoundingMode_index[i]:_RoundingMode_index[i+1]]
+}
diff --git a/src/math/stubs_arm64.s b/src/math/stubs_arm64.s
new file mode 100644
index 0000000..2ffd228
--- /dev/null
+++ b/src/math/stubs_arm64.s
@@ -0,0 +1,91 @@
+// 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.
+
+// +build arm64
+
+#include "textflag.h"
+
+TEXT ·Asin(SB),NOSPLIT,$0
+	B ·asin(SB)
+
+TEXT ·Acos(SB),NOSPLIT,$0
+	B ·acos(SB)
+
+TEXT ·Atan2(SB),NOSPLIT,$0
+	B ·atan2(SB)
+
+TEXT ·Atan(SB),NOSPLIT,$0
+	B ·atan(SB)
+
+TEXT ·Dim(SB),NOSPLIT,$0
+	B ·dim(SB)
+
+TEXT ·Min(SB),NOSPLIT,$0
+	B ·min(SB)
+
+TEXT ·Max(SB),NOSPLIT,$0
+	B ·max(SB)
+
+TEXT ·Exp2(SB),NOSPLIT,$0
+	B ·exp2(SB)
+
+TEXT ·Expm1(SB),NOSPLIT,$0
+	B ·expm1(SB)
+
+TEXT ·Exp(SB),NOSPLIT,$0
+	B ·exp(SB)
+
+TEXT ·Floor(SB),NOSPLIT,$0
+	B ·floor(SB)
+
+TEXT ·Ceil(SB),NOSPLIT,$0
+	B ·ceil(SB)
+
+TEXT ·Trunc(SB),NOSPLIT,$0
+	B ·trunc(SB)
+
+TEXT ·Frexp(SB),NOSPLIT,$0
+	B ·frexp(SB)
+
+TEXT ·Hypot(SB),NOSPLIT,$0
+	B ·hypot(SB)
+
+TEXT ·Ldexp(SB),NOSPLIT,$0
+	B ·ldexp(SB)
+
+TEXT ·Log10(SB),NOSPLIT,$0
+	B ·log10(SB)
+
+TEXT ·Log2(SB),NOSPLIT,$0
+	B ·log2(SB)
+
+TEXT ·Log1p(SB),NOSPLIT,$0
+	B ·log1p(SB)
+
+TEXT ·Log(SB),NOSPLIT,$0
+	B ·log(SB)
+
+TEXT ·Modf(SB),NOSPLIT,$0
+	B ·modf(SB)
+
+TEXT ·Mod(SB),NOSPLIT,$0
+	B ·mod(SB)
+
+TEXT ·Remainder(SB),NOSPLIT,$0
+	B ·remainder(SB)
+
+TEXT ·Sincos(SB),NOSPLIT,$0
+	B ·sincos(SB)
+
+TEXT ·Sin(SB),NOSPLIT,$0
+	B ·sin(SB)
+
+TEXT ·Cos(SB),NOSPLIT,$0
+	B ·cos(SB)
+
+TEXT ·Sqrt(SB),NOSPLIT,$0
+	B ·sqrt(SB)
+
+TEXT ·Tan(SB),NOSPLIT,$0
+	B ·tan(SB)
diff --git a/src/mime/grammar.go b/src/mime/grammar.go
index 2347324..31b66e8 100644
--- a/src/mime/grammar.go
+++ b/src/mime/grammar.go
@@ -8,13 +8,13 @@
 	"strings"
 )
 
-// isTSpecial returns true if rune is in 'tspecials' as defined by RFC
+// isTSpecial reports whether rune is in 'tspecials' as defined by RFC
 // 1521 and RFC 2045.
 func isTSpecial(r rune) bool {
 	return strings.IndexRune(`()<>@,;:\"/[]?=`, r) != -1
 }
 
-// isTokenChar returns true if rune is in 'token' as defined by RFC
+// isTokenChar reports whether rune is in 'token' as defined by RFC
 // 1521 and RFC 2045.
 func isTokenChar(r rune) bool {
 	// token := 1*<any (US-ASCII) CHAR except SPACE, CTLs,
@@ -22,7 +22,7 @@
 	return r > 0x20 && r < 0x7f && !isTSpecial(r)
 }
 
-// isToken returns true if s is a 'token' as defined by RFC 1521
+// isToken reports whether s is a 'token' as defined by RFC 1521
 // and RFC 2045.
 func isToken(s string) bool {
 	if s == "" {
diff --git a/src/mime/quotedprintable/reader.go b/src/mime/quotedprintable/reader.go
index 86c7f58..a39a20e 100644
--- a/src/mime/quotedprintable/reader.go
+++ b/src/mime/quotedprintable/reader.go
@@ -36,6 +36,9 @@
 		return b - '0', nil
 	case b >= 'A' && b <= 'F':
 		return b - 'A' + 10, nil
+	// Accept badly encoded bytes.
+	case b >= 'a' && b <= 'f':
+		return b - 'a' + 10, nil
 	}
 	return 0, fmt.Errorf("quotedprintable: invalid hex byte 0x%02x", b)
 }
diff --git a/src/mime/quotedprintable/reader_test.go b/src/mime/quotedprintable/reader_test.go
index 23dae2b..e77b261 100644
--- a/src/mime/quotedprintable/reader_test.go
+++ b/src/mime/quotedprintable/reader_test.go
@@ -27,10 +27,10 @@
 		{in: "", want: ""},
 		{in: "foo bar", want: "foo bar"},
 		{in: "foo bar=3D", want: "foo bar="},
+		{in: "foo bar=3d", want: "foo bar="}, // lax.
 		{in: "foo bar=\n", want: "foo bar"},
 		{in: "foo bar\n", want: "foo bar\n"}, // somewhat lax.
 		{in: "foo bar=0", want: "foo bar", err: io.ErrUnexpectedEOF},
-		{in: "foo bar=ab", want: "foo bar", err: "quotedprintable: invalid hex byte 0x61"},
 		{in: "foo bar=0D=0A", want: "foo bar\r\n"},
 		{in: " A B        \r\n C ", want: " A B\r\n C"},
 		{in: " A B =\r\n C ", want: " A B  C"},
diff --git a/src/mime/quotedprintable/writer.go b/src/mime/quotedprintable/writer.go
new file mode 100644
index 0000000..16ea0bf
--- /dev/null
+++ b/src/mime/quotedprintable/writer.go
@@ -0,0 +1,172 @@
+// Copyright 2015 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 quotedprintable
+
+import "io"
+
+const lineMaxLen = 76
+
+// A Writer is a quoted-printable writer that implements io.WriteCloser.
+type Writer struct {
+	// Binary mode treats the writer's input as pure binary and processes end of
+	// line bytes as binary data.
+	Binary bool
+
+	w    io.Writer
+	i    int
+	line [78]byte
+	cr   bool
+}
+
+// NewWriter returns a new Writer that writes to w.
+func NewWriter(w io.Writer) *Writer {
+	return &Writer{w: w}
+}
+
+// Write encodes p using quoted-printable encoding and writes it to the
+// underlying io.Writer. It limits line length to 76 characters. The encoded
+// bytes are not necessarily flushed until the Writer is closed.
+func (w *Writer) Write(p []byte) (n int, err error) {
+	for i, b := range p {
+		switch {
+		// Simple writes are done in batch.
+		case b >= '!' && b <= '~' && b != '=':
+			continue
+		case isWhitespace(b) || !w.Binary && (b == '\n' || b == '\r'):
+			continue
+		}
+
+		if i > n {
+			if err := w.write(p[n:i]); err != nil {
+				return n, err
+			}
+			n = i
+		}
+
+		if err := w.encode(b); err != nil {
+			return n, err
+		}
+		n++
+	}
+
+	if n == len(p) {
+		return n, nil
+	}
+
+	if err := w.write(p[n:]); err != nil {
+		return n, err
+	}
+
+	return len(p), nil
+}
+
+// Close closes the Writer, flushing any unwritten data to the underlying
+// io.Writer, but does not close the underlying io.Writer.
+func (w *Writer) Close() error {
+	if err := w.checkLastByte(); err != nil {
+		return err
+	}
+
+	return w.flush()
+}
+
+// write limits text encoded in quoted-printable to 76 characters per line.
+func (w *Writer) write(p []byte) error {
+	for _, b := range p {
+		if b == '\n' || b == '\r' {
+			// If the previous byte was \r, the CRLF has already been inserted.
+			if w.cr && b == '\n' {
+				w.cr = false
+				continue
+			}
+
+			if b == '\r' {
+				w.cr = true
+			}
+
+			if err := w.checkLastByte(); err != nil {
+				return err
+			}
+			if err := w.insertCRLF(); err != nil {
+				return err
+			}
+			continue
+		}
+
+		if w.i == lineMaxLen-1 {
+			if err := w.insertSoftLineBreak(); err != nil {
+				return err
+			}
+		}
+
+		w.line[w.i] = b
+		w.i++
+		w.cr = false
+	}
+
+	return nil
+}
+
+func (w *Writer) encode(b byte) error {
+	if lineMaxLen-1-w.i < 3 {
+		if err := w.insertSoftLineBreak(); err != nil {
+			return err
+		}
+	}
+
+	w.line[w.i] = '='
+	w.line[w.i+1] = upperhex[b>>4]
+	w.line[w.i+2] = upperhex[b&0x0f]
+	w.i += 3
+
+	return nil
+}
+
+const upperhex = "0123456789ABCDEF"
+
+// checkLastByte encodes the last buffered byte if it is a space or a tab.
+func (w *Writer) checkLastByte() error {
+	if w.i == 0 {
+		return nil
+	}
+
+	b := w.line[w.i-1]
+	if isWhitespace(b) {
+		w.i--
+		if err := w.encode(b); err != nil {
+			return err
+		}
+	}
+
+	return nil
+}
+
+func (w *Writer) insertSoftLineBreak() error {
+	w.line[w.i] = '='
+	w.i++
+
+	return w.insertCRLF()
+}
+
+func (w *Writer) insertCRLF() error {
+	w.line[w.i] = '\r'
+	w.line[w.i+1] = '\n'
+	w.i += 2
+
+	return w.flush()
+}
+
+func (w *Writer) flush() error {
+	if _, err := w.w.Write(w.line[:w.i]); err != nil {
+		return err
+	}
+
+	w.i = 0
+	return nil
+}
+
+func isWhitespace(b byte) bool {
+	return b == ' ' || b == '\t'
+}
diff --git a/src/mime/quotedprintable/writer_test.go b/src/mime/quotedprintable/writer_test.go
new file mode 100644
index 0000000..a9b77b3
--- /dev/null
+++ b/src/mime/quotedprintable/writer_test.go
@@ -0,0 +1,158 @@
+// Copyright 2015 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 quotedprintable
+
+import (
+	"bytes"
+	"io/ioutil"
+	"strings"
+	"testing"
+)
+
+func TestWriter(t *testing.T) {
+	testWriter(t, false)
+}
+
+func TestWriterBinary(t *testing.T) {
+	testWriter(t, true)
+}
+
+func testWriter(t *testing.T, binary bool) {
+	tests := []struct {
+		in, want, wantB string
+	}{
+		{in: "", want: ""},
+		{in: "foo bar", want: "foo bar"},
+		{in: "foo bar=", want: "foo bar=3D"},
+		{in: "foo bar\r", want: "foo bar\r\n", wantB: "foo bar=0D"},
+		{in: "foo bar\r\r", want: "foo bar\r\n\r\n", wantB: "foo bar=0D=0D"},
+		{in: "foo bar\n", want: "foo bar\r\n", wantB: "foo bar=0A"},
+		{in: "foo bar\r\n", want: "foo bar\r\n", wantB: "foo bar=0D=0A"},
+		{in: "foo bar\r\r\n", want: "foo bar\r\n\r\n", wantB: "foo bar=0D=0D=0A"},
+		{in: "foo bar ", want: "foo bar=20"},
+		{in: "foo bar\t", want: "foo bar=09"},
+		{in: "foo bar  ", want: "foo bar =20"},
+		{in: "foo bar \n", want: "foo bar=20\r\n", wantB: "foo bar =0A"},
+		{in: "foo bar \r", want: "foo bar=20\r\n", wantB: "foo bar =0D"},
+		{in: "foo bar \r\n", want: "foo bar=20\r\n", wantB: "foo bar =0D=0A"},
+		{in: "foo bar  \n", want: "foo bar =20\r\n", wantB: "foo bar  =0A"},
+		{in: "foo bar  \n ", want: "foo bar =20\r\n=20", wantB: "foo bar  =0A=20"},
+		{in: "¡Hola Señor!", want: "=C2=A1Hola Se=C3=B1or!"},
+		{
+			in:   "\t !\"#$%&'()*+,-./ :;<>?@[\\]^_`{|}~",
+			want: "\t !\"#$%&'()*+,-./ :;<>?@[\\]^_`{|}~",
+		},
+		{
+			in:   strings.Repeat("a", 75),
+			want: strings.Repeat("a", 75),
+		},
+		{
+			in:   strings.Repeat("a", 76),
+			want: strings.Repeat("a", 75) + "=\r\na",
+		},
+		{
+			in:   strings.Repeat("a", 72) + "=",
+			want: strings.Repeat("a", 72) + "=3D",
+		},
+		{
+			in:   strings.Repeat("a", 73) + "=",
+			want: strings.Repeat("a", 73) + "=\r\n=3D",
+		},
+		{
+			in:   strings.Repeat("a", 74) + "=",
+			want: strings.Repeat("a", 74) + "=\r\n=3D",
+		},
+		{
+			in:   strings.Repeat("a", 75) + "=",
+			want: strings.Repeat("a", 75) + "=\r\n=3D",
+		},
+		{
+			in:   strings.Repeat(" ", 73),
+			want: strings.Repeat(" ", 72) + "=20",
+		},
+		{
+			in:   strings.Repeat(" ", 74),
+			want: strings.Repeat(" ", 73) + "=\r\n=20",
+		},
+		{
+			in:   strings.Repeat(" ", 75),
+			want: strings.Repeat(" ", 74) + "=\r\n=20",
+		},
+		{
+			in:   strings.Repeat(" ", 76),
+			want: strings.Repeat(" ", 75) + "=\r\n=20",
+		},
+		{
+			in:   strings.Repeat(" ", 77),
+			want: strings.Repeat(" ", 75) + "=\r\n =20",
+		},
+	}
+
+	for _, tt := range tests {
+		buf := new(bytes.Buffer)
+		w := NewWriter(buf)
+
+		want := tt.want
+		if binary {
+			w.Binary = true
+			if tt.wantB != "" {
+				want = tt.wantB
+			}
+		}
+
+		if _, err := w.Write([]byte(tt.in)); err != nil {
+			t.Errorf("Write(%q): %v", tt.in, err)
+			continue
+		}
+		if err := w.Close(); err != nil {
+			t.Errorf("Close(): %v", err)
+			continue
+		}
+		got := buf.String()
+		if got != want {
+			t.Errorf("Write(%q), got:\n%q\nwant:\n%q", tt.in, got, want)
+		}
+	}
+}
+
+func TestRoundTrip(t *testing.T) {
+	buf := new(bytes.Buffer)
+	w := NewWriter(buf)
+	if _, err := w.Write(testMsg); err != nil {
+		t.Fatalf("Write: %v", err)
+	}
+	if err := w.Close(); err != nil {
+		t.Fatalf("Close: %v", err)
+	}
+
+	r := NewReader(buf)
+	gotBytes, err := ioutil.ReadAll(r)
+	if err != nil {
+		t.Fatalf("Error while reading from Reader: %v", err)
+	}
+	got := string(gotBytes)
+	if got != string(testMsg) {
+		t.Errorf("Encoding and decoding changed the message, got:\n%s", got)
+	}
+}
+
+// From http://fr.wikipedia.org/wiki/Quoted-Printable
+var testMsg = []byte("Quoted-Printable (QP) est un format d'encodage de données codées sur 8 bits, qui utilise exclusivement les caractères alphanumériques imprimables du code ASCII (7 bits).\r\n" +
+	"\r\n" +
+	"En effet, les différents codages comprennent de nombreux caractères qui ne sont pas représentables en ASCII (par exemple les caractères accentués), ainsi que des caractères dits « non-imprimables ».\r\n" +
+	"\r\n" +
+	"L'encodage Quoted-Printable permet de remédier à ce problème, en procédant de la manière suivante :\r\n" +
+	"\r\n" +
+	"Un octet correspondant à un caractère imprimable de l'ASCII sauf le signe égal (donc un caractère de code ASCII entre 33 et 60 ou entre 62 et 126) ou aux caractères de saut de ligne (codes ASCII 13 et 10) ou une suite de tabulations et espaces non situées en fin de ligne (de codes ASCII respectifs 9 et 32) est représenté tel quel.\r\n" +
+	"Un octet qui ne correspond pas à la définition ci-dessus (caractère non imprimable de l'ASCII, tabulation ou espaces non suivies d'un caractère imprimable avant la fin de la ligne ou signe égal) est représenté par un signe égal, suivi de son numéro, exprimé en hexadécimal.\r\n" +
+	"Enfin, un signe égal suivi par un saut de ligne (donc la suite des trois caractères de codes ASCII 61, 13 et 10) peut être inséré n'importe où, afin de limiter la taille des lignes produites si nécessaire. Une limite de 76 caractères par ligne est généralement respectée.\r\n")
+
+func BenchmarkWriter(b *testing.B) {
+	for i := 0; i < b.N; i++ {
+		w := NewWriter(ioutil.Discard)
+		w.Write(testMsg)
+		w.Close()
+	}
+}
diff --git a/src/mime/type.go b/src/mime/type.go
index ffda1f0..d369259 100644
--- a/src/mime/type.go
+++ b/src/mime/type.go
@@ -12,34 +12,75 @@
 )
 
 var (
-	mimeLock       sync.RWMutex
-	mimeTypesLower = map[string]string{
-		".css":  "text/css; charset=utf-8",
-		".gif":  "image/gif",
-		".htm":  "text/html; charset=utf-8",
-		".html": "text/html; charset=utf-8",
-		".jpg":  "image/jpeg",
-		".js":   "application/x-javascript",
-		".pdf":  "application/pdf",
-		".png":  "image/png",
-		".xml":  "text/xml; charset=utf-8",
-	}
-	mimeTypes = clone(mimeTypesLower)
+	mimeLock       sync.RWMutex      // guards following 3 maps
+	mimeTypes      map[string]string // ".Z" => "application/x-compress"
+	mimeTypesLower map[string]string // ".z" => "application/x-compress"
+
+	// extensions maps from MIME type to list of lowercase file
+	// extensions: "image/jpeg" => [".jpg", ".jpeg"]
+	extensions map[string][]string
 )
 
+// setMimeTypes is used by initMime's non-test path, and by tests.
+// The two maps must not be the same, or nil.
+func setMimeTypes(lowerExt, mixExt map[string]string) {
+	if lowerExt == nil || mixExt == nil {
+		panic("nil map")
+	}
+	mimeTypesLower = lowerExt
+	mimeTypes = mixExt
+	extensions = invert(lowerExt)
+}
+
+var builtinTypesLower = map[string]string{
+	".css":  "text/css; charset=utf-8",
+	".gif":  "image/gif",
+	".htm":  "text/html; charset=utf-8",
+	".html": "text/html; charset=utf-8",
+	".jpg":  "image/jpeg",
+	".js":   "application/x-javascript",
+	".pdf":  "application/pdf",
+	".png":  "image/png",
+	".svg":  "image/svg+xml",
+	".xml":  "text/xml; charset=utf-8",
+}
+
 func clone(m map[string]string) map[string]string {
 	m2 := make(map[string]string, len(m))
 	for k, v := range m {
 		m2[k] = v
 		if strings.ToLower(k) != k {
-			panic("keys in mimeTypesLower must be lowercase")
+			panic("keys in builtinTypesLower must be lowercase")
 		}
 	}
 	return m2
 }
 
+func invert(m map[string]string) map[string][]string {
+	m2 := make(map[string][]string, len(m))
+	for k, v := range m {
+		justType, _, err := ParseMediaType(v)
+		if err != nil {
+			panic(err)
+		}
+		m2[justType] = append(m2[justType], k)
+	}
+	return m2
+}
+
 var once sync.Once // guards initMime
 
+var testInitMime, osInitMime func()
+
+func initMime() {
+	if fn := testInitMime; fn != nil {
+		fn()
+	} else {
+		setMimeTypes(builtinTypesLower, clone(builtinTypesLower))
+		osInitMime()
+	}
+}
+
 // TypeByExtension returns the MIME type associated with the file extension ext.
 // The extension ext should begin with a leading dot, as in ".html".
 // When ext has no associated type, TypeByExtension returns "".
@@ -63,8 +104,7 @@
 	defer mimeLock.RUnlock()
 
 	// Case-sensitive lookup.
-	v := mimeTypes[ext]
-	if v != "" {
+	if v := mimeTypes[ext]; v != "" {
 		return v
 	}
 
@@ -91,19 +131,39 @@
 	return mimeTypesLower[string(lower)]
 }
 
+// ExtensionsByType returns the extensions known to be associated with the MIME
+// type typ. The returned extensions will each begin with a leading dot, as in
+// ".html". When typ has no associated extensions, ExtensionsByType returns an
+// nil slice.
+func ExtensionsByType(typ string) ([]string, error) {
+	justType, _, err := ParseMediaType(typ)
+	if err != nil {
+		return nil, err
+	}
+
+	once.Do(initMime)
+	mimeLock.RLock()
+	defer mimeLock.RUnlock()
+	s, ok := extensions[justType]
+	if !ok {
+		return nil, nil
+	}
+	return append([]string{}, s...), nil
+}
+
 // AddExtensionType sets the MIME type associated with
 // the extension ext to typ. The extension should begin with
 // a leading dot, as in ".html".
 func AddExtensionType(ext, typ string) error {
 	if !strings.HasPrefix(ext, ".") {
-		return fmt.Errorf(`mime: extension %q misses dot`, ext)
+		return fmt.Errorf("mime: extension %q missing leading dot", ext)
 	}
 	once.Do(initMime)
 	return setExtensionType(ext, typ)
 }
 
 func setExtensionType(extension, mimeType string) error {
-	_, param, err := ParseMediaType(mimeType)
+	justType, param, err := ParseMediaType(mimeType)
 	if err != nil {
 		return err
 	}
@@ -114,8 +174,14 @@
 	extLower := strings.ToLower(extension)
 
 	mimeLock.Lock()
+	defer mimeLock.Unlock()
 	mimeTypes[extension] = mimeType
 	mimeTypesLower[extLower] = mimeType
-	mimeLock.Unlock()
+	for _, v := range extensions[justType] {
+		if v == extLower {
+			return nil
+		}
+	}
+	extensions[justType] = append(extensions[justType], extLower)
 	return nil
 }
diff --git a/src/mime/type_plan9.go b/src/mime/type_plan9.go
index 8cbf677..c3ba186 100644
--- a/src/mime/type_plan9.go
+++ b/src/mime/type_plan9.go
@@ -10,10 +10,29 @@
 	"strings"
 )
 
+func init() {
+	osInitMime = initMimePlan9
+}
+
+func initMimePlan9() {
+	for _, filename := range typeFiles {
+		loadMimeFile(filename)
+	}
+}
+
 var typeFiles = []string{
 	"/sys/lib/mimetypes",
 }
 
+func initMimeForTests() map[string]string {
+	typeFiles = []string{"testdata/test.types.plan9"}
+	return map[string]string{
+		".t1":  "application/test",
+		".t2":  "text/test; charset=utf-8",
+		".pNg": "image/png",
+	}
+}
+
 func loadMimeFile(filename string) {
 	f, err := os.Open(filename)
 	if err != nil {
@@ -36,18 +55,3 @@
 		panic(err)
 	}
 }
-
-func initMime() {
-	for _, filename := range typeFiles {
-		loadMimeFile(filename)
-	}
-}
-
-func initMimeForTests() map[string]string {
-	typeFiles = []string{"testdata/test.types.plan9"}
-	return map[string]string{
-		".t1":  "application/test",
-		".t2":  "text/test; charset=utf-8",
-		".pNg": "image/png",
-	}
-}
diff --git a/src/mime/type_test.go b/src/mime/type_test.go
index d2d254a..c6c1491 100644
--- a/src/mime/type_test.go
+++ b/src/mime/type_test.go
@@ -5,12 +5,41 @@
 package mime
 
 import (
+	"reflect"
+	"strings"
+	"sync"
 	"testing"
 )
 
-var typeTests = initMimeForTests()
+func setMimeInit(fn func()) (cleanup func()) {
+	once = sync.Once{}
+	testInitMime = fn
+	return func() { testInitMime = nil }
+}
+
+func clearMimeTypes() {
+	setMimeTypes(map[string]string{}, map[string]string{})
+}
+
+func setType(ext, typ string) {
+	if !strings.HasPrefix(ext, ".") {
+		panic("missing leading dot")
+	}
+	if err := setExtensionType(ext, typ); err != nil {
+		panic("bad test data: " + err.Error())
+	}
+}
 
 func TestTypeByExtension(t *testing.T) {
+	once = sync.Once{}
+	// initMimeForTests returns the platform-specific extension =>
+	// type tests. On Unix and Plan 9, this also tests the parsing
+	// of MIME text files (in testdata/*). On Windows, we test the
+	// real registry on the machine and assume that ".png" exists
+	// there, which empirically it always has, for all versions of
+	// Windows.
+	typeTests := initMimeForTests()
+
 	for ext, want := range typeTests {
 		val := TypeByExtension(ext)
 		if val != want {
@@ -19,15 +48,41 @@
 	}
 }
 
+func TestTypeByExtension_LocalData(t *testing.T) {
+	cleanup := setMimeInit(func() {
+		clearMimeTypes()
+		setType(".foo", "x/foo")
+		setType(".bar", "x/bar")
+		setType(".Bar", "x/bar; capital=1")
+	})
+	defer cleanup()
+
+	tests := map[string]string{
+		".foo":          "x/foo",
+		".bar":          "x/bar",
+		".Bar":          "x/bar; capital=1",
+		".sdlkfjskdlfj": "",
+		".t1":           "", // testdata shouldn't be used
+	}
+
+	for ext, want := range tests {
+		val := TypeByExtension(ext)
+		if val != want {
+			t.Errorf("TypeByExtension(%q) = %q, want %q", ext, val, want)
+		}
+	}
+}
+
 func TestTypeByExtensionCase(t *testing.T) {
 	const custom = "test/test; charset=iso-8859-1"
 	const caps = "test/test; WAS=ALLCAPS"
-	if err := AddExtensionType(".TEST", caps); err != nil {
-		t.Fatalf("error %s for AddExtension(%s)", err, custom)
-	}
-	if err := AddExtensionType(".tesT", custom); err != nil {
-		t.Fatalf("error %s for AddExtension(%s)", err, custom)
-	}
+
+	cleanup := setMimeInit(func() {
+		clearMimeTypes()
+		setType(".TEST", caps)
+		setType(".tesT", custom)
+	})
+	defer cleanup()
 
 	// case-sensitive lookup
 	if got := TypeByExtension(".tesT"); got != custom {
@@ -43,6 +98,47 @@
 	}
 }
 
+func TestExtensionsByType(t *testing.T) {
+	cleanup := setMimeInit(func() {
+		clearMimeTypes()
+		setType(".gif", "image/gif")
+		setType(".a", "foo/letter")
+		setType(".b", "foo/letter")
+		setType(".B", "foo/letter")
+		setType(".PNG", "image/png")
+	})
+	defer cleanup()
+
+	tests := []struct {
+		typ     string
+		want    []string
+		wantErr string
+	}{
+		{typ: "image/gif", want: []string{".gif"}},
+		{typ: "image/png", want: []string{".png"}}, // lowercase
+		{typ: "foo/letter", want: []string{".a", ".b"}},
+		{typ: "x/unknown", want: nil},
+	}
+
+	for _, tt := range tests {
+		got, err := ExtensionsByType(tt.typ)
+		if err != nil && tt.wantErr != "" && strings.Contains(err.Error(), tt.wantErr) {
+			continue
+		}
+		if err != nil {
+			t.Errorf("ExtensionsByType(%q) error: %v", tt.typ, err)
+			continue
+		}
+		if tt.wantErr != "" {
+			t.Errorf("ExtensionsByType(%q) = %q, %v; want error substring %q", tt.typ, got, err, tt.wantErr)
+			continue
+		}
+		if !reflect.DeepEqual(got, tt.want) {
+			t.Errorf("ExtensionsByType(%q) = %q; want %q", tt.typ, got, tt.want)
+		}
+	}
+}
+
 func TestLookupMallocs(t *testing.T) {
 	n := testing.AllocsPerRun(10000, func() {
 		TypeByExtension(".html")
diff --git a/src/mime/type_unix.go b/src/mime/type_unix.go
index 3e404cf..bb06a77 100644
--- a/src/mime/type_unix.go
+++ b/src/mime/type_unix.go
@@ -12,6 +12,10 @@
 	"strings"
 )
 
+func init() {
+	osInitMime = initMimeUnix
+}
+
 var typeFiles = []string{
 	"/etc/mime.types",
 	"/etc/apache2/mime.types",
@@ -44,7 +48,7 @@
 	}
 }
 
-func initMime() {
+func initMimeUnix() {
 	for _, filename := range typeFiles {
 		loadMimeFile(filename)
 	}
diff --git a/src/mime/type_windows.go b/src/mime/type_windows.go
index ae758d7..60362b4 100644
--- a/src/mime/type_windows.go
+++ b/src/mime/type_windows.go
@@ -9,7 +9,11 @@
 	"unsafe"
 )
 
-func initMime() {
+func init() {
+	osInitMime = initMimeWindows
+}
+
+func initMimeWindows() {
 	var root syscall.Handle
 	rootpathp, _ := syscall.UTF16PtrFromString(`\`)
 	if syscall.RegOpenKeyEx(syscall.HKEY_CLASSES_ROOT, rootpathp,
@@ -21,6 +25,7 @@
 	if syscall.RegQueryInfoKey(root, nil, nil, nil, &count, nil, nil, nil, nil, nil, nil, nil) != nil {
 		return
 	}
+	contenttypep, _ := syscall.UTF16PtrFromString("Content Type")
 	var buf [1 << 10]uint16
 	for i := uint32(0); i < count; i++ {
 		n := uint32(len(buf))
@@ -40,7 +45,6 @@
 		}
 		var typ uint32
 		n = uint32(len(buf) * 2) // api expects array of bytes, not uint16
-		contenttypep, _ := syscall.UTF16PtrFromString("Content Type")
 		if syscall.RegQueryValueEx(
 			h, contenttypep,
 			nil, &typ, (*byte)(unsafe.Pointer(&buf[0])), &n) != nil {
diff --git a/src/nacltest.bash b/src/nacltest.bash
index 534f1ef..eb1ac3d 100755
--- a/src/nacltest.bash
+++ b/src/nacltest.bash
@@ -59,22 +59,22 @@
 	exit 1
 fi
 
-# Run host build to get toolchain for running zip generator.
 unset GOOS GOARCH
 if [ ! -f make.bash ]; then
 	echo 'nacltest.bash must be run from $GOROOT/src' 1>&2
 	exit 1
 fi
-GOOS=$GOHOSTOS GOARCH=$GOHOSTARCH ./make.bash
 
 # the builder might have set GOROOT_FINAL.
 export GOROOT=$(pwd)/..
 
 # Build zip file embedded in package syscall.
-gobin=${GOBIN:-$(pwd)/../bin}
+echo "##### Building fake file system zip for nacl"
 rm -f syscall/fstest_nacl.go
-GOOS=$GOHOSTOS GOARCH=$GOHOSTARCH $gobin/go run ../misc/nacl/mkzip.go -p syscall -r .. ../misc/nacl/testzip.proto syscall/fstest_nacl.go
+GOROOT_BOOTSTRAP=${GOROOT_BOOTSTRAP:-$HOME/go1.4}
+gobin=$GOROOT_BOOTSTRAP/bin
+GOROOT=$GOROOT_BOOTSTRAP $gobin/go run ../misc/nacl/mkzip.go -p syscall -r .. ../misc/nacl/testzip.proto syscall/fstest_nacl.go
 
 # Run standard build and tests.
 export PATH=$(pwd)/../misc/nacl:$PATH
-GOOS=nacl GOARCH=$naclGOARCH ./all.bash --no-clean
+GOOS=nacl GOARCH=$naclGOARCH ./all.bash
diff --git a/src/net/cgo_stub.go b/src/net/cgo_stub.go
index f533c14..d2d40da 100644
--- a/src/net/cgo_stub.go
+++ b/src/net/cgo_stub.go
@@ -16,7 +16,7 @@
 	return 0, nil, false
 }
 
-func cgoLookupIP(name string) (addrs []IP, err error, completed bool) {
+func cgoLookupIP(name string) (addrs []IPAddr, err error, completed bool) {
 	return nil, nil, false
 }
 
diff --git a/src/net/cgo_unix.go b/src/net/cgo_unix.go
index 1f366ee..eba5777 100644
--- a/src/net/cgo_unix.go
+++ b/src/net/cgo_unix.go
@@ -81,7 +81,7 @@
 	return 0, &AddrError{"unknown port", net + "/" + service}, true
 }
 
-func cgoLookupIPCNAME(name string) (addrs []IP, cname string, err error, completed bool) {
+func cgoLookupIPCNAME(name string) (addrs []IPAddr, cname string, err error, completed bool) {
 	acquireThread()
 	defer releaseThread()
 
@@ -135,16 +135,18 @@
 			continue
 		case C.AF_INET:
 			sa := (*syscall.RawSockaddrInet4)(unsafe.Pointer(r.ai_addr))
-			addrs = append(addrs, copyIP(sa.Addr[:]))
+			addr := IPAddr{IP: copyIP(sa.Addr[:])}
+			addrs = append(addrs, addr)
 		case C.AF_INET6:
 			sa := (*syscall.RawSockaddrInet6)(unsafe.Pointer(r.ai_addr))
-			addrs = append(addrs, copyIP(sa.Addr[:]))
+			addr := IPAddr{IP: copyIP(sa.Addr[:]), Zone: zoneToString(int(sa.Scope_id))}
+			addrs = append(addrs, addr)
 		}
 	}
 	return addrs, cname, nil, true
 }
 
-func cgoLookupIP(name string) (addrs []IP, err error, completed bool) {
+func cgoLookupIP(name string) (addrs []IPAddr, err error, completed bool) {
 	addrs, _, err, completed = cgoLookupIPCNAME(name)
 	return
 }
diff --git a/src/net/conn_test.go b/src/net/conn_test.go
index 9c9d1a8..912c084 100644
--- a/src/net/conn_test.go
+++ b/src/net/conn_test.go
@@ -9,7 +9,6 @@
 
 import (
 	"os"
-	"runtime"
 	"testing"
 	"time"
 )
@@ -30,19 +29,9 @@
 
 func TestConnAndListener(t *testing.T) {
 	for _, tt := range connTests {
-		switch tt.net {
-		case "unix":
-			switch runtime.GOOS {
-			case "nacl", "plan9", "windows":
-				continue
-			}
-		case "unixpacket":
-			switch runtime.GOOS {
-			case "android", "darwin", "nacl", "openbsd", "plan9", "windows":
-				continue
-			case "freebsd": // FreeBSD 8 doesn't support unixpacket
-				continue
-			}
+		if !testableNetwork(tt.net) {
+			t.Logf("skipping %s test", tt.net)
+			continue
 		}
 
 		ln, err := Listen(tt.net, tt.addr)
diff --git a/src/net/dnsclient_unix.go b/src/net/dnsclient_unix.go
index 7511083f..30c7ada 100644
--- a/src/net/dnsclient_unix.go
+++ b/src/net/dnsclient_unix.go
@@ -361,13 +361,15 @@
 // Normally we let cgo use the C library resolver instead of
 // depending on our lookup code, so that Go and C get the same
 // answers.
-func goLookupIP(name string) (addrs []IP, err error) {
+func goLookupIP(name string) (addrs []IPAddr, err error) {
 	// Use entries from /etc/hosts if possible.
 	haddrs := lookupStaticHost(name)
 	if len(haddrs) > 0 {
 		for _, haddr := range haddrs {
+			haddr, zone := splitHostZone(haddr)
 			if ip := ParseIP(haddr); ip != nil {
-				addrs = append(addrs, ip)
+				addr := IPAddr{IP: ip, Zone: zone}
+				addrs = append(addrs, addr)
 			}
 		}
 		if len(addrs) > 0 {
@@ -396,9 +398,15 @@
 		}
 		switch racer.qtype {
 		case dnsTypeA:
-			addrs = append(addrs, convertRR_A(racer.rrs)...)
+			for _, ip := range convertRR_A(racer.rrs) {
+				addr := IPAddr{IP: ip}
+				addrs = append(addrs, addr)
+			}
 		case dnsTypeAAAA:
-			addrs = append(addrs, convertRR_AAAA(racer.rrs)...)
+			for _, ip := range convertRR_AAAA(racer.rrs) {
+				addr := IPAddr{IP: ip}
+				addrs = append(addrs, addr)
+			}
 		}
 	}
 	if len(addrs) == 0 && lastErr != nil {
diff --git a/src/net/dnsclient_unix_test.go b/src/net/dnsclient_unix_test.go
index 40b78bd..2934634 100644
--- a/src/net/dnsclient_unix_test.go
+++ b/src/net/dnsclient_unix_test.go
@@ -219,18 +219,27 @@
 }
 
 func BenchmarkGoLookupIP(b *testing.B) {
+	uninstallTestHooks()
+	defer installTestHooks()
+
 	for i := 0; i < b.N; i++ {
 		goLookupIP("www.example.com")
 	}
 }
 
 func BenchmarkGoLookupIPNoSuchHost(b *testing.B) {
+	uninstallTestHooks()
+	defer installTestHooks()
+
 	for i := 0; i < b.N; i++ {
 		goLookupIP("some.nonexistent")
 	}
 }
 
 func BenchmarkGoLookupIPWithBrokenNameServer(b *testing.B) {
+	uninstallTestHooks()
+	defer installTestHooks()
+
 	onceLoadConfig.Do(loadDefaultConfig)
 	if cfg.dnserr != nil || cfg.dnsConfig == nil {
 		b.Fatalf("loadConfig failed: %v", cfg.dnserr)
diff --git a/src/net/dnsname_test.go b/src/net/dnsname_test.go
index 57dd25f..4fecf8d 100644
--- a/src/net/dnsname_test.go
+++ b/src/net/dnsname_test.go
@@ -69,6 +69,9 @@
 }
 
 func BenchmarkDNSNames(b *testing.B) {
+	uninstallTestHooks()
+	defer installTestHooks()
+
 	benchmarks := append(tests, []testCase{
 		{strings.Repeat("a", 63), true},
 		{strings.Repeat("a", 64), false},
diff --git a/src/net/fd_unix.go b/src/net/fd_unix.go
index 24e6c59..9e19761 100644
--- a/src/net/fd_unix.go
+++ b/src/net/fd_unix.go
@@ -72,7 +72,7 @@
 	// Do not need to call fd.writeLock here,
 	// because fd is not yet accessible to user,
 	// so no concurrent operations are possible.
-	switch err := syscall.Connect(fd.sysfd, ra); err {
+	switch err := connectFunc(fd.sysfd, ra); err {
 	case syscall.EINPROGRESS, syscall.EALREADY, syscall.EINTR:
 	case nil, syscall.EISCONN:
 		if !deadline.IsZero() && deadline.Before(time.Now()) {
@@ -114,7 +114,7 @@
 		if err := fd.pd.WaitWrite(); err != nil {
 			return err
 		}
-		nerr, err := syscall.GetsockoptInt(fd.sysfd, syscall.SOL_SOCKET, syscall.SO_ERROR)
+		nerr, err := getsockoptIntFunc(fd.sysfd, syscall.SOL_SOCKET, syscall.SO_ERROR)
 		if err != nil {
 			return err
 		}
@@ -130,9 +130,9 @@
 
 func (fd *netFD) destroy() {
 	// Poller may want to unregister fd in readiness notification mechanism,
-	// so this must be executed before closesocket.
+	// so this must be executed before closeFunc.
 	fd.pd.Close()
-	closesocket(fd.sysfd)
+	closeFunc(fd.sysfd)
 	fd.sysfd = -1
 	runtime.SetFinalizer(fd, nil)
 }
@@ -417,7 +417,7 @@
 	}
 
 	if netfd, err = newFD(s, fd.family, fd.sotype, fd.net); err != nil {
-		closesocket(s)
+		closeFunc(s)
 		return nil, err
 	}
 	if err = netfd.init(); err != nil {
@@ -492,7 +492,3 @@
 
 	return os.NewFile(uintptr(ns), fd.name()), nil
 }
-
-func closesocket(s int) error {
-	return syscall.Close(s)
-}
diff --git a/src/net/fd_windows.go b/src/net/fd_windows.go
index 995bc4a..d685883 100644
--- a/src/net/fd_windows.go
+++ b/src/net/fd_windows.go
@@ -69,10 +69,6 @@
 	}
 }
 
-func closesocket(s syscall.Handle) error {
-	return syscall.Closesocket(s)
-}
-
 func canUseConnectEx(net string) bool {
 	switch net {
 	case "udp", "udp4", "udp6", "ip", "ip4", "ip6":
@@ -336,7 +332,7 @@
 		defer fd.setWriteDeadline(noDeadline)
 	}
 	if !canUseConnectEx(fd.net) {
-		return syscall.Connect(fd.sysfd, ra)
+		return connectFunc(fd.sysfd, ra)
 	}
 	// ConnectEx windows API requires an unconnected, previously bound socket.
 	if la == nil {
@@ -356,7 +352,7 @@
 	o := &fd.wop
 	o.sa = ra
 	_, err := wsrv.ExecIO(o, "ConnectEx", func(o *operation) error {
-		return syscall.ConnectEx(o.fd.sysfd, o.sa, nil, 0, nil, &o.o)
+		return connectExFunc(o.fd.sysfd, o.sa, nil, 0, nil, &o.o)
 	})
 	if err != nil {
 		return err
@@ -370,9 +366,9 @@
 		return
 	}
 	// Poller may want to unregister fd in readiness notification mechanism,
-	// so this must be executed before closesocket.
+	// so this must be executed before closeFunc.
 	fd.pd.Close()
-	closesocket(fd.sysfd)
+	closeFunc(fd.sysfd)
 	fd.sysfd = syscall.InvalidHandle
 	// no need for a finalizer anymore
 	runtime.SetFinalizer(fd, nil)
@@ -540,7 +536,7 @@
 	// Associate our new socket with IOCP.
 	netfd, err := newFD(s, fd.family, fd.sotype, fd.net)
 	if err != nil {
-		closesocket(s)
+		closeFunc(s)
 		return nil, &OpError{"accept", fd.net, fd.laddr, err}
 	}
 	if err := netfd.init(); err != nil {
diff --git a/src/net/file_test.go b/src/net/file_test.go
index 6fab06a..609efb2 100644
--- a/src/net/file_test.go
+++ b/src/net/file_test.go
@@ -27,10 +27,6 @@
 }
 
 func testFileListener(t *testing.T, net, laddr string) {
-	switch net {
-	case "tcp", "tcp4", "tcp6":
-		laddr += ":0" // any available port
-	}
 	l, err := Listen(net, laddr)
 	if err != nil {
 		t.Fatalf("Listen failed: %v", err)
@@ -59,32 +55,30 @@
 var fileListenerTests = []struct {
 	net   string
 	laddr string
-	ipv6  bool // test with underlying AF_INET6 socket
-	linux bool // test with abstract unix domain socket, a Linux-ism
 }{
-	{net: "tcp", laddr: ""},
-	{net: "tcp", laddr: "0.0.0.0"},
-	{net: "tcp", laddr: "[::ffff:0.0.0.0]"},
-	{net: "tcp", laddr: "[::]", ipv6: true},
+	{net: "tcp", laddr: ":0"},
+	{net: "tcp", laddr: "0.0.0.0:0"},
+	{net: "tcp", laddr: "[::ffff:0.0.0.0]:0"},
+	{net: "tcp", laddr: "[::]:0"},
 
-	{net: "tcp", laddr: "127.0.0.1"},
-	{net: "tcp", laddr: "[::ffff:127.0.0.1]"},
-	{net: "tcp", laddr: "[::1]", ipv6: true},
+	{net: "tcp", laddr: "127.0.0.1:0"},
+	{net: "tcp", laddr: "[::ffff:127.0.0.1]:0"},
+	{net: "tcp", laddr: "[::1]:0"},
 
-	{net: "tcp4", laddr: ""},
-	{net: "tcp4", laddr: "0.0.0.0"},
-	{net: "tcp4", laddr: "[::ffff:0.0.0.0]"},
+	{net: "tcp4", laddr: ":0"},
+	{net: "tcp4", laddr: "0.0.0.0:0"},
+	{net: "tcp4", laddr: "[::ffff:0.0.0.0]:0"},
 
-	{net: "tcp4", laddr: "127.0.0.1"},
-	{net: "tcp4", laddr: "[::ffff:127.0.0.1]"},
+	{net: "tcp4", laddr: "127.0.0.1:0"},
+	{net: "tcp4", laddr: "[::ffff:127.0.0.1]:0"},
 
-	{net: "tcp6", laddr: "", ipv6: true},
-	{net: "tcp6", laddr: "[::]", ipv6: true},
+	{net: "tcp6", laddr: ":0"},
+	{net: "tcp6", laddr: "[::]:0"},
 
-	{net: "tcp6", laddr: "[::1]", ipv6: true},
+	{net: "tcp6", laddr: "[::1]:0"},
 
-	{net: "unix", laddr: "@gotest/net", linux: true},
-	{net: "unixpacket", laddr: "@gotest/net", linux: true},
+	{net: "unix", laddr: "@gotest/net"},
+	{net: "unixpacket", laddr: "@gotest/net"},
 }
 
 func TestFileListener(t *testing.T) {
@@ -94,10 +88,8 @@
 	}
 
 	for _, tt := range fileListenerTests {
-		if skipServerTest(tt.net, "unix", tt.laddr, tt.ipv6, false, tt.linux) {
-			continue
-		}
-		if skipServerTest(tt.net, "unixpacket", tt.laddr, tt.ipv6, false, tt.linux) {
+		if !testableListenArgs(tt.net, tt.laddr, "") {
+			t.Logf("skipping %s test", tt.net+":"+tt.laddr+"->")
 			continue
 		}
 		testFileListener(t, tt.net, tt.laddr)
@@ -130,10 +122,6 @@
 }
 
 func testFilePacketConnListen(t *testing.T, net, laddr string) {
-	switch net {
-	case "udp", "udp4", "udp6":
-		laddr += ":0" // any available port
-	}
 	l, err := ListenPacket(net, laddr)
 	if err != nil {
 		t.Fatalf("ListenPacket failed: %v", err)
@@ -145,10 +133,6 @@
 }
 
 func testFilePacketConnDial(t *testing.T, net, raddr string) {
-	switch net {
-	case "udp", "udp4", "udp6":
-		raddr += ":12345"
-	}
 	c, err := Dial(net, raddr)
 	if err != nil {
 		t.Fatalf("Dial failed: %v", err)
@@ -160,23 +144,21 @@
 }
 
 var filePacketConnTests = []struct {
-	net   string
-	addr  string
-	ipv6  bool // test with underlying AF_INET6 socket
-	linux bool // test with abstract unix domain socket, a Linux-ism
+	net  string
+	addr string
 }{
-	{net: "udp", addr: "127.0.0.1"},
-	{net: "udp", addr: "[::ffff:127.0.0.1]"},
-	{net: "udp", addr: "[::1]", ipv6: true},
+	{net: "udp", addr: "127.0.0.1:0"},
+	{net: "udp", addr: "[::ffff:127.0.0.1]:0"},
+	{net: "udp", addr: "[::1]:0"},
 
-	{net: "udp4", addr: "127.0.0.1"},
-	{net: "udp4", addr: "[::ffff:127.0.0.1]"},
+	{net: "udp4", addr: "127.0.0.1:0"},
+	{net: "udp4", addr: "[::ffff:127.0.0.1]:0"},
 
-	{net: "udp6", addr: "[::1]", ipv6: true},
+	{net: "udp6", addr: "[::1]:0"},
 
 	{net: "ip4:icmp", addr: "127.0.0.1"},
 
-	{net: "unixgram", addr: "@gotest3/net", linux: true},
+	{net: "unixgram", addr: "@gotest3/net"},
 }
 
 func TestFilePacketConn(t *testing.T) {
@@ -186,7 +168,8 @@
 	}
 
 	for _, tt := range filePacketConnTests {
-		if skipServerTest(tt.net, "unixgram", tt.addr, tt.ipv6, false, tt.linux) {
+		if !testableListenArgs(tt.net, tt.addr, "") {
+			t.Logf("skipping %s test", tt.net+":"+tt.addr+"->")
 			continue
 		}
 		if os.Getuid() != 0 && tt.net == "ip4:icmp" {
@@ -194,12 +177,16 @@
 			continue
 		}
 		testFilePacketConnListen(t, tt.net, tt.addr)
-		switch tt.addr {
-		case "", "0.0.0.0", "[::ffff:0.0.0.0]", "[::]":
-		default:
-			if tt.net != "unixgram" {
-				testFilePacketConnDial(t, tt.net, tt.addr)
+		switch tt.net {
+		case "udp", "udp4", "udp6":
+			host, _, err := SplitHostPort(tt.addr)
+			if err != nil {
+				t.Error(err)
+				continue
 			}
+			testFilePacketConnDial(t, tt.net, JoinHostPort(host, "12345"))
+		case "ip4:icmp":
+			testFilePacketConnDial(t, tt.net, tt.addr)
 		}
 	}
 }
diff --git a/src/net/file_unix.go b/src/net/file_unix.go
index 214a419..8d806a1 100644
--- a/src/net/file_unix.go
+++ b/src/net/file_unix.go
@@ -18,13 +18,13 @@
 	}
 
 	if err = syscall.SetNonblock(fd, true); err != nil {
-		closesocket(fd)
+		closeFunc(fd)
 		return nil, err
 	}
 
 	sotype, err := syscall.GetsockoptInt(fd, syscall.SOL_SOCKET, syscall.SO_TYPE)
 	if err != nil {
-		closesocket(fd)
+		closeFunc(fd)
 		return nil, os.NewSyscallError("getsockopt", err)
 	}
 
@@ -33,7 +33,7 @@
 	lsa, _ := syscall.Getsockname(fd)
 	switch lsa.(type) {
 	default:
-		closesocket(fd)
+		closeFunc(fd)
 		return nil, syscall.EINVAL
 	case *syscall.SockaddrInet4:
 		family = syscall.AF_INET
@@ -64,7 +64,7 @@
 
 	netfd, err := newFD(fd, family, sotype, laddr.Network())
 	if err != nil {
-		closesocket(fd)
+		closeFunc(fd)
 		return nil, err
 	}
 	if err := netfd.init(); err != nil {
diff --git a/src/net/hook_cloexec.go b/src/net/hook_cloexec.go
new file mode 100644
index 0000000..870f0d7
--- /dev/null
+++ b/src/net/hook_cloexec.go
@@ -0,0 +1,14 @@
+// Copyright 2015 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.
+
+// +build freebsd linux
+
+package net
+
+import "syscall"
+
+var (
+	// Placeholders for socket system calls.
+	accept4Func func(int, int) (int, syscall.Sockaddr, error) = syscall.Accept4
+)
diff --git a/src/net/hook_unix.go b/src/net/hook_unix.go
new file mode 100644
index 0000000..626d07f
--- /dev/null
+++ b/src/net/hook_unix.go
@@ -0,0 +1,18 @@
+// Copyright 2015 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.
+
+// +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris
+
+package net
+
+import "syscall"
+
+var (
+	// Placeholders for socket system calls.
+	socketFunc        func(int, int, int) (int, error)         = syscall.Socket
+	closeFunc         func(int) error                          = syscall.Close
+	connectFunc       func(int, syscall.Sockaddr) error        = syscall.Connect
+	acceptFunc        func(int) (int, syscall.Sockaddr, error) = syscall.Accept
+	getsockoptIntFunc func(int, int, int) (int, error)         = syscall.GetsockoptInt
+)
diff --git a/src/net/hook_windows.go b/src/net/hook_windows.go
new file mode 100644
index 0000000..2a6e5bf
--- /dev/null
+++ b/src/net/hook_windows.go
@@ -0,0 +1,15 @@
+// Copyright 2015 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 net
+
+import "syscall"
+
+var (
+	// Placeholders for socket system calls.
+	socketFunc    func(int, int, int) (syscall.Handle, error)                                               = syscall.Socket
+	closeFunc     func(syscall.Handle) error                                                                = syscall.Closesocket
+	connectFunc   func(syscall.Handle, syscall.Sockaddr) error                                              = syscall.Connect
+	connectExFunc func(syscall.Handle, syscall.Sockaddr, *byte, uint32, *uint32, *syscall.Overlapped) error = syscall.ConnectEx
+)
diff --git a/src/net/http/fcgi/fcgi_test.go b/src/net/http/fcgi/fcgi_test.go
index 74d91bf..de0f7f8 100644
--- a/src/net/http/fcgi/fcgi_test.go
+++ b/src/net/http/fcgi/fcgi_test.go
@@ -233,7 +233,9 @@
 // isn't met. See issue 6934.
 func TestChildServeCleansUp(t *testing.T) {
 	for _, tt := range cleanUpTests {
-		rc := nopWriteCloser{bytes.NewBuffer(tt.input)}
+		input := make([]byte, len(tt.input))
+		copy(input, tt.input)
+		rc := nopWriteCloser{bytes.NewBuffer(input)}
 		done := make(chan bool)
 		c := newChild(rc, http.HandlerFunc(func(
 			w http.ResponseWriter,
diff --git a/src/net/http/fs.go b/src/net/http/fs.go
index 9a80123..4e69da8 100644
--- a/src/net/http/fs.go
+++ b/src/net/http/fs.go
@@ -102,10 +102,10 @@
 // The name is otherwise unused; in particular it can be empty and is
 // never sent in the response.
 //
-// If modtime is not the zero time, ServeContent includes it in a
-// Last-Modified header in the response.  If the request includes an
-// If-Modified-Since header, ServeContent uses modtime to decide
-// whether the content needs to be sent at all.
+// If modtime is not the zero time or Unix epoch, ServeContent
+// includes it in a Last-Modified header in the response.  If the
+// request includes an If-Modified-Since header, ServeContent uses
+// modtime to decide whether the content needs to be sent at all.
 //
 // The content's Seek method must work: ServeContent uses
 // a seek to the end of the content to determine its size.
@@ -258,10 +258,15 @@
 	}
 }
 
+var unixEpochTime = time.Unix(0, 0)
+
 // modtime is the modification time of the resource to be served, or IsZero().
 // return value is whether this request is now complete.
 func checkLastModified(w ResponseWriter, r *Request, modtime time.Time) bool {
-	if modtime.IsZero() {
+	if modtime.IsZero() || modtime.Equal(unixEpochTime) {
+		// If the file doesn't have a modtime (IsZero), or the modtime
+		// is obviously garbage (Unix time == 0), then ignore modtimes
+		// and don't process the If-Modified-Since header.
 		return false
 	}
 
diff --git a/src/net/http/fs_test.go b/src/net/http/fs_test.go
index 72f8c2c..a8cfe5f 100644
--- a/src/net/http/fs_test.go
+++ b/src/net/http/fs_test.go
@@ -751,6 +751,12 @@
 			wantContentType: "text/css; charset=utf-8",
 			wantLastMod:     "Wed, 25 Jun 2014 17:12:18 GMT",
 		},
+		"unix_zero_modtime": {
+			content:         strings.NewReader("<html>foo"),
+			modtime:         time.Unix(0, 0),
+			wantStatus:      StatusOK,
+			wantContentType: "text/html; charset=utf-8",
+		},
 	}
 	for testName, tt := range tests {
 		var content io.ReadSeeker
diff --git a/src/net/http/pprof/pprof.go b/src/net/http/pprof/pprof.go
index f5a352d..02cde50 100644
--- a/src/net/http/pprof/pprof.go
+++ b/src/net/http/pprof/pprof.go
@@ -222,17 +222,17 @@
 <head>
 <title>/debug/pprof/</title>
 </head>
+<body>
 /debug/pprof/<br>
 <br>
-<body>
 profiles:<br>
 <table>
 {{range .}}
-<tr><td align=right>{{.Count}}<td><a href="/debug/pprof/{{.Name}}?debug=1">{{.Name}}</a>
+<tr><td align=right>{{.Count}}<td><a href="{{.Name}}?debug=1">{{.Name}}</a>
 {{end}}
 </table>
 <br>
-<a href="/debug/pprof/goroutine?debug=2">full goroutine stack dump</a><br>
+<a href="goroutine?debug=2">full goroutine stack dump</a><br>
 </body>
 </html>
 `))
diff --git a/src/net/http/server.go b/src/net/http/server.go
index c68aa2c..565c87d 100644
--- a/src/net/http/server.go
+++ b/src/net/http/server.go
@@ -981,7 +981,7 @@
 	return line
 }
 
-// bodyAllowed returns true if a Write is allowed for this response type.
+// bodyAllowed reports whether a Write is allowed for this response type.
 // It's illegal to call this before the header has been flushed.
 func (w *response) bodyAllowed() bool {
 	if !w.wroteHeader {
diff --git a/src/net/http/transport.go b/src/net/http/transport.go
index afeaa8da..b18e445 100644
--- a/src/net/http/transport.go
+++ b/src/net/http/transport.go
@@ -662,7 +662,7 @@
 	return pconn, nil
 }
 
-// useProxy returns true if requests to addr should use a proxy,
+// useProxy reports whether requests to addr should use a proxy,
 // according to the NO_PROXY or no_proxy environment variable.
 // addr is always a canonicalAddr with a host and port.
 func useProxy(addr string) bool {
diff --git a/src/net/interface_test.go b/src/net/interface_test.go
index 98d6734..666f11a 100644
--- a/src/net/interface_test.go
+++ b/src/net/interface_test.go
@@ -47,15 +47,20 @@
 	return ""
 }
 
+type routeStats struct {
+	loop  int // # of active loopback interfaces
+	other int // # of active other interfaces
+
+	uni4, uni6     int // # of active connected unicast, anycast routes
+	multi4, multi6 int // # of active connected multicast route clones
+}
+
 func TestInterfaces(t *testing.T) {
-	if runtime.GOOS == "dragonfly" {
-		t.Skip("fail on dragonfly - issue 10041")
-	}
 	ift, err := Interfaces()
 	if err != nil {
 		t.Fatal(err)
 	}
-	var nifs, naf4, naf6, nmaf4, nmaf6 int
+	var stats routeStats
 	for _, ifi := range ift {
 		ifxi, err := InterfaceByIndex(ifi.Index)
 		if err != nil {
@@ -73,64 +78,86 @@
 		}
 		t.Logf("%q: flags %q, ifindex %v, mtu %v", ifi.Name, ifi.Flags.String(), ifi.Index, ifi.MTU)
 		t.Logf("hardware address %q", ifi.HardwareAddr.String())
-		if ifi.Flags&FlagUp != 0 && ifi.Flags&FlagLoopback == 0 {
-			nifs++ // active interfaces except loopback interfaces
+		if ifi.Flags&FlagUp != 0 {
+			if ifi.Flags&FlagLoopback != 0 {
+				stats.loop++
+			} else {
+				stats.other++
+			}
 		}
 		n4, n6 := testInterfaceAddrs(t, &ifi)
-		naf4 += n4
-		naf6 += n6
+		stats.uni4 += n4
+		stats.uni6 += n6
 		n4, n6 = testInterfaceMulticastAddrs(t, &ifi)
-		nmaf4 += n4
-		nmaf6 += n6
+		stats.multi4 += n4
+		stats.multi6 += n6
 	}
 	switch runtime.GOOS {
 	case "nacl", "plan9", "solaris":
 	default:
-		if supportsIPv4 && nifs > 0 && naf4 == 0 {
-			t.Errorf("got %v; want more than or equal to one", naf4)
+		// Test the existence of connected unicast routes for
+		// IPv4.
+		if supportsIPv4 && stats.loop+stats.other > 0 && stats.uni4 == 0 {
+			t.Errorf("num IPv4 unicast routes = 0; want >0; summary: %+v", stats)
 		}
-		if supportsIPv6 && nifs > 0 && naf6 == 0 {
-			t.Errorf("got %v; want more than or equal to one", naf6)
+		// Test the existence of connected unicast routes for
+		// IPv6. We can assume the existence of ::1/128 when
+		// at least one looopback interface is installed.
+		if supportsIPv6 && stats.loop > 0 && stats.uni6 == 0 {
+			t.Errorf("num IPv6 unicast routes = 0; want >0; summary: %+v", stats)
 		}
 	}
 	switch runtime.GOOS {
 	case "dragonfly", "nacl", "netbsd", "openbsd", "plan9", "solaris":
 	default:
-		// Unlike IPv6, IPv4 multicast capability is not a
-		// mandatory feature.
-		//if supportsIPv4 && nactvifs > 0 && nmaf4 == 0 {
-		//	t.Errorf("got %v; want more than or equal to one", nmaf4)
+		// Test the existence of connected multicast route
+		// clones for IPv4. Unlike IPv6, IPv4 multicast
+		// capability is not a mandatory feature, and so this
+		// test is disabled.
+		//if supportsIPv4 && stats.loop > 0 && stats.uni4 > 1 && stats.multi4 == 0 {
+		//	t.Errorf("num IPv4 multicast route clones = 0; want >0; summary: %+v", stats)
 		//}
-		if supportsIPv6 && nifs > 0 && nmaf6 == 0 {
-			t.Errorf("got %v; want more than or equal to one", nmaf6)
+		// Test the existence of connected multicast route
+		// clones for IPv6. Some platform never uses loopback
+		// interface as the nexthop for multicast routing.
+		// We can assume the existence of connected multicast
+		// route clones when at least two connected unicast
+		// routes, ::1/128 and other, are installed.
+		if supportsIPv6 && stats.loop > 0 && stats.uni6 > 1 && stats.multi6 == 0 {
+			t.Errorf("num IPv6 multicast route clones = 0; want >0; summary: %+v", stats)
 		}
 	}
 }
 
 func TestInterfaceAddrs(t *testing.T) {
-	if runtime.GOOS == "dragonfly" {
-		t.Skip("fail on dragonfly - issue 10041")
-	}
 	ift, err := Interfaces()
 	if err != nil {
 		t.Fatal(err)
 	}
-	var nifs int
+	var stats routeStats
 	for _, ifi := range ift {
-		if ifi.Flags&FlagUp != 0 && ifi.Flags&FlagLoopback == 0 {
-			nifs++ // active interfaces except loopback interfaces
+		if ifi.Flags&FlagUp != 0 {
+			if ifi.Flags&FlagLoopback != 0 {
+				stats.loop++
+			} else {
+				stats.other++
+			}
 		}
 	}
 	ifat, err := InterfaceAddrs()
 	if err != nil {
 		t.Fatal(err)
 	}
-	naf4, naf6 := testAddrs(t, ifat)
-	if supportsIPv4 && nifs > 0 && naf4 == 0 {
-		t.Errorf("got %v; want more than or equal to one", naf4)
+	stats.uni4, stats.uni6 = testAddrs(t, ifat)
+	// Test the existence of connected unicast routes for IPv4.
+	if supportsIPv4 && stats.loop+stats.other > 0 && stats.uni4 == 0 {
+		t.Errorf("num IPv4 unicast routes = 0; want >0; summary: %+v", stats)
 	}
-	if supportsIPv6 && nifs > 0 && naf6 == 0 {
-		t.Errorf("got %v; want more than or equal to one", naf6)
+	// Test the existence of connected unicast routes for IPv6.
+	// We can assume the existence of ::1/128 when at least one
+	// looopback interface is installed.
+	if supportsIPv6 && stats.loop > 0 && stats.uni6 == 0 {
+		t.Errorf("num IPv6 unicast routes = 0; want >0; summary: %+v", stats)
 	}
 }
 
@@ -202,6 +229,9 @@
 }
 
 func BenchmarkInterfaces(b *testing.B) {
+	uninstallTestHooks()
+	defer installTestHooks()
+
 	for i := 0; i < b.N; i++ {
 		if _, err := Interfaces(); err != nil {
 			b.Fatal(err)
@@ -210,6 +240,9 @@
 }
 
 func BenchmarkInterfaceByIndex(b *testing.B) {
+	uninstallTestHooks()
+	defer installTestHooks()
+
 	ifi := loopbackInterface()
 	if ifi == nil {
 		b.Skip("loopback interface not found")
@@ -222,6 +255,9 @@
 }
 
 func BenchmarkInterfaceByName(b *testing.B) {
+	uninstallTestHooks()
+	defer installTestHooks()
+
 	ifi := loopbackInterface()
 	if ifi == nil {
 		b.Skip("loopback interface not found")
@@ -234,6 +270,9 @@
 }
 
 func BenchmarkInterfaceAddrs(b *testing.B) {
+	uninstallTestHooks()
+	defer installTestHooks()
+
 	for i := 0; i < b.N; i++ {
 		if _, err := InterfaceAddrs(); err != nil {
 			b.Fatal(err)
@@ -242,6 +281,9 @@
 }
 
 func BenchmarkInterfacesAndAddrs(b *testing.B) {
+	uninstallTestHooks()
+	defer installTestHooks()
+
 	ifi := loopbackInterface()
 	if ifi == nil {
 		b.Skip("loopback interface not found")
@@ -254,6 +296,9 @@
 }
 
 func BenchmarkInterfacesAndMulticastAddrs(b *testing.B) {
+	uninstallTestHooks()
+	defer installTestHooks()
+
 	ifi := loopbackInterface()
 	if ifi == nil {
 		b.Skip("loopback interface not found")
diff --git a/src/net/internal/socktest/main_test.go b/src/net/internal/socktest/main_test.go
new file mode 100644
index 0000000..3ae1c6b
--- /dev/null
+++ b/src/net/internal/socktest/main_test.go
@@ -0,0 +1,40 @@
+// Copyright 2015 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.
+
+// +build !plan9
+
+package socktest_test
+
+import (
+	"net/internal/socktest"
+	"os"
+	"syscall"
+	"testing"
+)
+
+var sw socktest.Switch
+
+func TestMain(m *testing.M) {
+	installTestHooks()
+
+	st := m.Run()
+
+	for s := range sw.Sockets() {
+		closeFunc(s)
+	}
+	uninstallTestHooks()
+	os.Exit(st)
+}
+
+func TestSocket(t *testing.T) {
+	for _, f := range []socktest.Filter{
+		func(st *socktest.Status) (socktest.AfterFilter, error) { return nil, nil },
+		nil,
+	} {
+		sw.Set(socktest.FilterSocket, f)
+		for _, family := range []int{syscall.AF_INET, syscall.AF_INET6} {
+			socketFunc(family, syscall.SOCK_STREAM, syscall.IPPROTO_TCP)
+		}
+	}
+}
diff --git a/src/net/internal/socktest/main_unix_test.go b/src/net/internal/socktest/main_unix_test.go
new file mode 100644
index 0000000..b8eebc2
--- /dev/null
+++ b/src/net/internal/socktest/main_unix_test.go
@@ -0,0 +1,24 @@
+// Copyright 2015 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.
+
+// +build !plan9,!windows
+
+package socktest_test
+
+import "syscall"
+
+var (
+	socketFunc func(int, int, int) (int, error)
+	closeFunc  func(int) error
+)
+
+func installTestHooks() {
+	socketFunc = sw.Socket
+	closeFunc = sw.Close
+}
+
+func uninstallTestHooks() {
+	socketFunc = syscall.Socket
+	closeFunc = syscall.Close
+}
diff --git a/src/net/internal/socktest/main_windows_test.go b/src/net/internal/socktest/main_windows_test.go
new file mode 100644
index 0000000..df1cb97
--- /dev/null
+++ b/src/net/internal/socktest/main_windows_test.go
@@ -0,0 +1,22 @@
+// Copyright 2015 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 socktest_test
+
+import "syscall"
+
+var (
+	socketFunc func(int, int, int) (syscall.Handle, error)
+	closeFunc  func(syscall.Handle) error
+)
+
+func installTestHooks() {
+	socketFunc = sw.Socket
+	closeFunc = sw.Closesocket
+}
+
+func uninstallTestHooks() {
+	socketFunc = syscall.Socket
+	closeFunc = syscall.Closesocket
+}
diff --git a/src/net/internal/socktest/switch.go b/src/net/internal/socktest/switch.go
new file mode 100644
index 0000000..5398191
--- /dev/null
+++ b/src/net/internal/socktest/switch.go
@@ -0,0 +1,150 @@
+// Copyright 2015 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 socktest provides utilities for socket testing.
+package socktest
+
+import "sync"
+
+func switchInit(sw *Switch) {
+	sw.fltab = make(map[FilterType]Filter)
+	sw.sotab = make(Sockets)
+	sw.stats = make(stats)
+}
+
+// A Switch represents a callpath point switch for socket system
+// calls.
+type Switch struct {
+	once sync.Once
+
+	fmu   sync.RWMutex
+	fltab map[FilterType]Filter
+
+	smu   sync.RWMutex
+	sotab Sockets
+	stats stats
+}
+
+// Stats returns a list of per-cookie socket statistics.
+func (sw *Switch) Stats() []Stat {
+	var st []Stat
+	sw.smu.RLock()
+	for _, s := range sw.stats {
+		ns := *s
+		st = append(st, ns)
+	}
+	sw.smu.RUnlock()
+	return st
+}
+
+// Sockets returns mappings of socket descriptor to socket status.
+func (sw *Switch) Sockets() Sockets {
+	sw.smu.RLock()
+	tab := make(Sockets, len(sw.sotab))
+	for i, s := range sw.sotab {
+		tab[i] = s
+	}
+	sw.smu.RUnlock()
+	return tab
+}
+
+// A Cookie represents a 3-tuple of a socket; address family, socket
+// type and protocol number.
+type Cookie uint64
+
+// Family returns an address family.
+func (c Cookie) Family() int { return int(c >> 48) }
+
+// Type returns a socket type.
+func (c Cookie) Type() int { return int(c << 16 >> 32) }
+
+// Protocol returns a protocol number.
+func (c Cookie) Protocol() int { return int(c & 0xff) }
+
+func cookie(family, sotype, proto int) Cookie {
+	return Cookie(family)<<48 | Cookie(sotype)&0xffffffff<<16 | Cookie(proto)&0xff
+}
+
+// A Status represents the status of a socket.
+type Status struct {
+	Cookie    Cookie
+	Err       error // error status of socket system call
+	SocketErr int   // error status of socket by SO_ERROR
+}
+
+// A Stat represents a per-cookie socket statistics.
+type Stat struct {
+	Family   int // address family
+	Type     int // socket type
+	Protocol int // protocol number
+
+	Opened    uint64 // number of sockets opened
+	Accepted  uint64 // number of sockets accepted
+	Connected uint64 // number of sockets connected
+	Closed    uint64 // number of sockets closed
+}
+
+type stats map[Cookie]*Stat
+
+func (st stats) getLocked(c Cookie) *Stat {
+	s, ok := st[c]
+	if !ok {
+		s = &Stat{Family: c.Family(), Type: c.Type(), Protocol: c.Protocol()}
+		st[c] = s
+	}
+	return s
+}
+
+// A FilterType represents a filter type.
+type FilterType int
+
+const (
+	FilterSocket        FilterType = iota // for Socket
+	FilterAccept                          // for Accept or Accept4
+	FilterConnect                         // for Connect or ConnectEx
+	FilterGetsockoptInt                   // for GetsockoptInt
+	FilterClose                           // for Close or Closesocket
+)
+
+// A Filter represents a socket system call filter.
+//
+// It will only be executed before a system call for a socket that has
+// an entry in internal table.
+// If the filter returns a non-nil error, the execution of system call
+// will be canceled and the system call function returns the non-nil
+// error.
+// It can return a non-nil AfterFilter for filtering after the
+// execution of the system call.
+type Filter func(*Status) (AfterFilter, error)
+
+func (f Filter) apply(st *Status) (AfterFilter, error) {
+	if f == nil {
+		return nil, nil
+	}
+	return f(st)
+}
+
+// An AfterFilter represents a socket system call filter after an
+// execution of a system call.
+//
+// It will only be executed after a system call for a socket that has
+// an entry in internal table.
+// If the filter returns a non-nil error, the system call function
+// returns the non-nil error.
+type AfterFilter func(*Status) error
+
+func (f AfterFilter) apply(st *Status) error {
+	if f == nil {
+		return nil
+	}
+	return f(st)
+}
+
+// Set deploys the socket system call filter f for the filter type t.
+func (sw *Switch) Set(t FilterType, f Filter) {
+	sw.once.Do(func() { switchInit(sw) })
+	sw.fmu.Lock()
+	sw.fltab[t] = f
+	sw.fmu.Unlock()
+}
diff --git a/src/net/internal/socktest/switch_stub.go b/src/net/internal/socktest/switch_stub.go
new file mode 100644
index 0000000..be97628
--- /dev/null
+++ b/src/net/internal/socktest/switch_stub.go
@@ -0,0 +1,10 @@
+// Copyright 2015 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.
+
+// +build plan9
+
+package socktest
+
+// Sockets maps a socket descriptor to the status of socket.
+type Sockets map[int]Status
diff --git a/src/net/internal/socktest/switch_unix.go b/src/net/internal/socktest/switch_unix.go
new file mode 100644
index 0000000..2b89276
--- /dev/null
+++ b/src/net/internal/socktest/switch_unix.go
@@ -0,0 +1,29 @@
+// Copyright 2015 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.
+
+// +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris
+
+package socktest
+
+// Sockets maps a socket descriptor to the status of socket.
+type Sockets map[int]Status
+
+func (sw *Switch) sockso(s int) *Status {
+	sw.smu.RLock()
+	defer sw.smu.RUnlock()
+	so, ok := sw.sotab[s]
+	if !ok {
+		return nil
+	}
+	return &so
+}
+
+// addLocked returns a new Status without locking.
+// sw.smu must be held before call.
+func (sw *Switch) addLocked(s, family, sotype, proto int) *Status {
+	sw.once.Do(func() { switchInit(sw) })
+	so := Status{Cookie: cookie(family, sotype, proto)}
+	sw.sotab[s] = so
+	return &so
+}
diff --git a/src/net/internal/socktest/switch_windows.go b/src/net/internal/socktest/switch_windows.go
new file mode 100644
index 0000000..3cee49b
--- /dev/null
+++ b/src/net/internal/socktest/switch_windows.go
@@ -0,0 +1,29 @@
+// Copyright 2015 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 socktest
+
+import "syscall"
+
+// Sockets maps a socket descriptor to the status of socket.
+type Sockets map[syscall.Handle]Status
+
+func (sw *Switch) sockso(s syscall.Handle) *Status {
+	sw.smu.RLock()
+	defer sw.smu.RUnlock()
+	so, ok := sw.sotab[s]
+	if !ok {
+		return nil
+	}
+	return &so
+}
+
+// addLocked returns a new Status without locking.
+// sw.smu must be held before call.
+func (sw *Switch) addLocked(s syscall.Handle, family, sotype, proto int) *Status {
+	sw.once.Do(func() { switchInit(sw) })
+	so := Status{Cookie: cookie(family, sotype, proto)}
+	sw.sotab[s] = so
+	return &so
+}
diff --git a/src/net/internal/socktest/sys_cloexec.go b/src/net/internal/socktest/sys_cloexec.go
new file mode 100644
index 0000000..61cb6ae
--- /dev/null
+++ b/src/net/internal/socktest/sys_cloexec.go
@@ -0,0 +1,41 @@
+// Copyright 2015 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.
+
+// +build freebsd linux
+
+package socktest
+
+import "syscall"
+
+// Accept4 wraps syscall.Accept4.
+func (sw *Switch) Accept4(s, flags int) (ns int, sa syscall.Sockaddr, err error) {
+	so := sw.sockso(s)
+	if so == nil {
+		return syscall.Accept4(s, flags)
+	}
+	sw.fmu.RLock()
+	f, _ := sw.fltab[FilterAccept]
+	sw.fmu.RUnlock()
+
+	af, err := f.apply(so)
+	if err != nil {
+		return -1, nil, err
+	}
+	ns, sa, so.Err = syscall.Accept4(s, flags)
+	if err = af.apply(so); err != nil {
+		if so.Err == nil {
+			syscall.Close(ns)
+		}
+		return -1, nil, err
+	}
+
+	if so.Err != nil {
+		return -1, nil, so.Err
+	}
+	sw.smu.Lock()
+	nso := sw.addLocked(ns, so.Cookie.Family(), so.Cookie.Type(), so.Cookie.Protocol())
+	sw.stats.getLocked(nso.Cookie).Accepted++
+	sw.smu.Unlock()
+	return ns, sa, nil
+}
diff --git a/src/net/internal/socktest/sys_unix.go b/src/net/internal/socktest/sys_unix.go
new file mode 100644
index 0000000..b128c01
--- /dev/null
+++ b/src/net/internal/socktest/sys_unix.go
@@ -0,0 +1,157 @@
+// Copyright 2015 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.
+
+// +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris
+
+package socktest
+
+import "syscall"
+
+// Socket wraps syscall.Socket.
+func (sw *Switch) Socket(family, sotype, proto int) (s int, err error) {
+	so := &Status{Cookie: cookie(family, sotype, proto)}
+	sw.fmu.RLock()
+	f, _ := sw.fltab[FilterSocket]
+	sw.fmu.RUnlock()
+
+	af, err := f.apply(so)
+	if err != nil {
+		return -1, err
+	}
+	s, so.Err = syscall.Socket(family, sotype, proto)
+	if err = af.apply(so); err != nil {
+		if so.Err == nil {
+			syscall.Close(s)
+		}
+		return -1, err
+	}
+
+	if so.Err != nil {
+		return -1, so.Err
+	}
+	sw.smu.Lock()
+	nso := sw.addLocked(s, family, sotype, proto)
+	sw.stats.getLocked(nso.Cookie).Opened++
+	sw.smu.Unlock()
+	return s, nil
+}
+
+// Close wraps syscall.Close.
+func (sw *Switch) Close(s int) (err error) {
+	so := sw.sockso(s)
+	if so == nil {
+		return syscall.Close(s)
+	}
+	sw.fmu.RLock()
+	f, _ := sw.fltab[FilterClose]
+	sw.fmu.RUnlock()
+
+	af, err := f.apply(so)
+	if err != nil {
+		return err
+	}
+	so.Err = syscall.Close(s)
+	if err = af.apply(so); err != nil {
+		return err
+	}
+
+	if so.Err != nil {
+		return so.Err
+	}
+	sw.smu.Lock()
+	delete(sw.sotab, s)
+	sw.stats.getLocked(so.Cookie).Closed++
+	sw.smu.Unlock()
+	return nil
+}
+
+// Connect wraps syscall.Connect.
+func (sw *Switch) Connect(s int, sa syscall.Sockaddr) (err error) {
+	so := sw.sockso(s)
+	if so == nil {
+		return syscall.Connect(s, sa)
+	}
+	sw.fmu.RLock()
+	f, _ := sw.fltab[FilterConnect]
+	sw.fmu.RUnlock()
+
+	af, err := f.apply(so)
+	if err != nil {
+		return err
+	}
+	so.Err = syscall.Connect(s, sa)
+	if err = af.apply(so); err != nil {
+		return err
+	}
+
+	if so.Err != nil {
+		return so.Err
+	}
+	sw.smu.Lock()
+	sw.stats.getLocked(so.Cookie).Connected++
+	sw.smu.Unlock()
+	return nil
+}
+
+// Accept wraps syscall.Accept.
+func (sw *Switch) Accept(s int) (ns int, sa syscall.Sockaddr, err error) {
+	so := sw.sockso(s)
+	if so == nil {
+		return syscall.Accept(s)
+	}
+	sw.fmu.RLock()
+	f, _ := sw.fltab[FilterAccept]
+	sw.fmu.RUnlock()
+
+	af, err := f.apply(so)
+	if err != nil {
+		return -1, nil, err
+	}
+	ns, sa, so.Err = syscall.Accept(s)
+	if err = af.apply(so); err != nil {
+		if so.Err == nil {
+			syscall.Close(ns)
+		}
+		return -1, nil, err
+	}
+
+	if so.Err != nil {
+		return -1, nil, so.Err
+	}
+	sw.smu.Lock()
+	nso := sw.addLocked(ns, so.Cookie.Family(), so.Cookie.Type(), so.Cookie.Protocol())
+	sw.stats.getLocked(nso.Cookie).Accepted++
+	sw.smu.Unlock()
+	return ns, sa, nil
+}
+
+// GetsockoptInt wraps syscall.GetsockoptInt.
+func (sw *Switch) GetsockoptInt(s, level, opt int) (soerr int, err error) {
+	so := sw.sockso(s)
+	if so == nil {
+		return syscall.GetsockoptInt(s, level, opt)
+	}
+	sw.fmu.RLock()
+	f, _ := sw.fltab[FilterGetsockoptInt]
+	sw.fmu.RUnlock()
+
+	af, err := f.apply(so)
+	if err != nil {
+		return -1, err
+	}
+	so.SocketErr, so.Err = syscall.GetsockoptInt(s, level, opt)
+	if err = af.apply(so); err != nil {
+		return -1, err
+	}
+
+	if so.Err != nil {
+		return -1, so.Err
+	}
+	if opt == syscall.SO_ERROR && (so.SocketErr == 0 || syscall.Errno(so.SocketErr) == syscall.EISCONN) {
+		sw.smu.Lock()
+		sw.stats.getLocked(so.Cookie).Connected++
+		sw.smu.Unlock()
+	}
+	return so.SocketErr, nil
+}
diff --git a/src/net/internal/socktest/sys_windows.go b/src/net/internal/socktest/sys_windows.go
new file mode 100644
index 0000000..30bac45
--- /dev/null
+++ b/src/net/internal/socktest/sys_windows.go
@@ -0,0 +1,121 @@
+// Copyright 2015 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 socktest
+
+import "syscall"
+
+// Socket wraps syscall.Socket.
+func (sw *Switch) Socket(family, sotype, proto int) (s syscall.Handle, err error) {
+	so := &Status{Cookie: cookie(family, sotype, proto)}
+	sw.fmu.RLock()
+	f, _ := sw.fltab[FilterSocket]
+	sw.fmu.RUnlock()
+
+	af, err := f.apply(so)
+	if err != nil {
+		return syscall.InvalidHandle, err
+	}
+	s, so.Err = syscall.Socket(family, sotype, proto)
+	if err = af.apply(so); err != nil {
+		if so.Err == nil {
+			syscall.Closesocket(s)
+		}
+		return syscall.InvalidHandle, err
+	}
+
+	if so.Err != nil {
+		return syscall.InvalidHandle, so.Err
+	}
+	sw.smu.Lock()
+	nso := sw.addLocked(s, family, sotype, proto)
+	sw.stats.getLocked(nso.Cookie).Opened++
+	sw.smu.Unlock()
+	return s, nil
+}
+
+// Closesocket wraps syscall.Closesocket.
+func (sw *Switch) Closesocket(s syscall.Handle) (err error) {
+	so := sw.sockso(s)
+	if so == nil {
+		return syscall.Closesocket(s)
+	}
+	sw.fmu.RLock()
+	f, _ := sw.fltab[FilterClose]
+	sw.fmu.RUnlock()
+
+	af, err := f.apply(so)
+	if err != nil {
+		return err
+	}
+	so.Err = syscall.Closesocket(s)
+	if err = af.apply(so); err != nil {
+		return err
+	}
+
+	if so.Err != nil {
+		return so.Err
+	}
+	sw.smu.Lock()
+	delete(sw.sotab, s)
+	sw.stats.getLocked(so.Cookie).Closed++
+	sw.smu.Unlock()
+	return nil
+}
+
+// Conenct wraps syscall.Connect.
+func (sw *Switch) Connect(s syscall.Handle, sa syscall.Sockaddr) (err error) {
+	so := sw.sockso(s)
+	if so == nil {
+		return syscall.Connect(s, sa)
+	}
+	sw.fmu.RLock()
+	f, _ := sw.fltab[FilterConnect]
+	sw.fmu.RUnlock()
+
+	af, err := f.apply(so)
+	if err != nil {
+		return err
+	}
+	so.Err = syscall.Connect(s, sa)
+	if err = af.apply(so); err != nil {
+		return err
+	}
+
+	if so.Err != nil {
+		return so.Err
+	}
+	sw.smu.Lock()
+	sw.stats.getLocked(so.Cookie).Connected++
+	sw.smu.Unlock()
+	return nil
+}
+
+// ConenctEx wraps syscall.ConnectEx.
+func (sw *Switch) ConnectEx(s syscall.Handle, sa syscall.Sockaddr, b *byte, n uint32, nwr *uint32, o *syscall.Overlapped) (err error) {
+	so := sw.sockso(s)
+	if so == nil {
+		return syscall.ConnectEx(s, sa, b, n, nwr, o)
+	}
+	sw.fmu.RLock()
+	f, _ := sw.fltab[FilterConnect]
+	sw.fmu.RUnlock()
+
+	af, err := f.apply(so)
+	if err != nil {
+		return err
+	}
+	so.Err = syscall.ConnectEx(s, sa, b, n, nwr, o)
+	if err = af.apply(so); err != nil {
+		return err
+	}
+
+	if so.Err != nil {
+		return so.Err
+	}
+	sw.smu.Lock()
+	sw.stats.getLocked(so.Cookie).Connected++
+	sw.smu.Unlock()
+	return nil
+}
diff --git a/src/net/ip.go b/src/net/ip.go
index f83658c..a554165 100644
--- a/src/net/ip.go
+++ b/src/net/ip.go
@@ -108,7 +108,7 @@
 	IPv6linklocalallrouters    = IP{0xff, 0x02, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x02}
 )
 
-// IsUnspecified returns true if ip is an unspecified address.
+// IsUnspecified reports whether ip is an unspecified address.
 func (ip IP) IsUnspecified() bool {
 	if ip.Equal(IPv4zero) || ip.Equal(IPv6unspecified) {
 		return true
@@ -116,7 +116,7 @@
 	return false
 }
 
-// IsLoopback returns true if ip is a loopback address.
+// IsLoopback reports whether ip is a loopback address.
 func (ip IP) IsLoopback() bool {
 	if ip4 := ip.To4(); ip4 != nil && ip4[0] == 127 {
 		return true
@@ -124,7 +124,7 @@
 	return ip.Equal(IPv6loopback)
 }
 
-// IsMulticast returns true if ip is a multicast address.
+// IsMulticast reports whether ip is a multicast address.
 func (ip IP) IsMulticast() bool {
 	if ip4 := ip.To4(); ip4 != nil && ip4[0]&0xf0 == 0xe0 {
 		return true
@@ -132,13 +132,13 @@
 	return ip[0] == 0xff
 }
 
-// IsInterfaceLocalMulticast returns true if ip is
+// IsInterfaceLocalMulticast reports whether ip is
 // an interface-local multicast address.
 func (ip IP) IsInterfaceLocalMulticast() bool {
 	return len(ip) == IPv6len && ip[0] == 0xff && ip[1]&0x0f == 0x01
 }
 
-// IsLinkLocalMulticast returns true if ip is a link-local
+// IsLinkLocalMulticast reports whether ip is a link-local
 // multicast address.
 func (ip IP) IsLinkLocalMulticast() bool {
 	if ip4 := ip.To4(); ip4 != nil && ip4[0] == 224 && ip4[1] == 0 && ip4[2] == 0 {
@@ -147,7 +147,7 @@
 	return ip[0] == 0xff && ip[1]&0x0f == 0x02
 }
 
-// IsLinkLocalUnicast returns true if ip is a link-local
+// IsLinkLocalUnicast reports whether ip is a link-local
 // unicast address.
 func (ip IP) IsLinkLocalUnicast() bool {
 	if ip4 := ip.To4(); ip4 != nil && ip4[0] == 169 && ip4[1] == 254 {
@@ -156,7 +156,7 @@
 	return ip[0] == 0xfe && ip[1]&0xc0 == 0x80
 }
 
-// IsGlobalUnicast returns true if ip is a global unicast
+// IsGlobalUnicast reports whether ip is a global unicast
 // address.
 func (ip IP) IsGlobalUnicast() bool {
 	return !ip.IsUnspecified() &&
@@ -352,7 +352,7 @@
 	return nil
 }
 
-// Equal returns true if ip and x are the same IP address.
+// Equal reports whether ip and x are the same IP address.
 // An IPv4 address and that same address in IPv6 form are
 // considered to be equal.
 func (ip IP) Equal(x IP) bool {
diff --git a/src/net/ip_test.go b/src/net/ip_test.go
index 604da39..e6f4e65 100644
--- a/src/net/ip_test.go
+++ b/src/net/ip_test.go
@@ -53,6 +53,9 @@
 }
 
 func BenchmarkParseIP(b *testing.B) {
+	uninstallTestHooks()
+	defer installTestHooks()
+
 	for i := 0; i < b.N; i++ {
 		for _, tt := range parseIPTests {
 			ParseIP(tt.in)
@@ -108,6 +111,9 @@
 }
 
 func BenchmarkIPString(b *testing.B) {
+	uninstallTestHooks()
+	defer installTestHooks()
+
 	for i := 0; i < b.N; i++ {
 		for _, tt := range ipStringTests {
 			if tt.in != nil {
@@ -158,6 +164,9 @@
 }
 
 func BenchmarkIPMaskString(b *testing.B) {
+	uninstallTestHooks()
+	defer installTestHooks()
+
 	for i := 0; i < b.N; i++ {
 		for _, tt := range ipMaskStringTests {
 			tt.in.String()
diff --git a/src/net/ipraw_test.go b/src/net/ipraw_test.go
index 7bf95e1..f93b9ef 100644
--- a/src/net/ipraw_test.go
+++ b/src/net/ipraw_test.go
@@ -6,9 +6,7 @@
 
 import (
 	"fmt"
-	"os"
 	"reflect"
-	"runtime"
 	"testing"
 )
 
@@ -64,9 +62,8 @@
 }
 
 func TestResolveIPAddr(t *testing.T) {
-	switch runtime.GOOS {
-	case "nacl":
-		t.Skipf("skipping test on %q", runtime.GOOS)
+	if !testableNetwork("ip+nopriv") {
+		t.Skip("ip+nopriv test")
 	}
 
 	for _, tt := range resolveIPAddrTests {
@@ -89,16 +86,11 @@
 }
 
 func TestIPConnLocalName(t *testing.T) {
-	switch runtime.GOOS {
-	case "nacl", "plan9", "windows":
-		t.Skipf("skipping test on %q", runtime.GOOS)
-	default:
-		if os.Getuid() != 0 {
-			t.Skip("skipping test; must be root")
-		}
-	}
-
 	for _, tt := range ipConnLocalNameTests {
+		if !testableNetwork(tt.net) {
+			t.Logf("skipping %s test", tt.net)
+			continue
+		}
 		c, err := ListenIP(tt.net, tt.laddr)
 		if err != nil {
 			t.Fatalf("ListenIP failed: %v", err)
@@ -111,13 +103,8 @@
 }
 
 func TestIPConnRemoteName(t *testing.T) {
-	switch runtime.GOOS {
-	case "plan9", "windows":
-		t.Skipf("skipping test on %q", runtime.GOOS)
-	default:
-		if os.Getuid() != 0 {
-			t.Skip("skipping test; must be root")
-		}
+	if !testableNetwork("ip:tcp") {
+		t.Skip("ip:tcp test")
 	}
 
 	raddr := &IPAddr{IP: IPv4(127, 0, 0, 1).To4()}
diff --git a/src/net/iprawsock.go b/src/net/iprawsock.go
index 5cc3613..1e53ab2 100644
--- a/src/net/iprawsock.go
+++ b/src/net/iprawsock.go
@@ -23,6 +23,13 @@
 	return a.IP.String()
 }
 
+func (a *IPAddr) isWildcard() bool {
+	if a == nil || a.IP == nil {
+		return true
+	}
+	return a.IP.IsUnspecified()
+}
+
 func (a *IPAddr) toAddr() Addr {
 	if a == nil {
 		return nil
diff --git a/src/net/iprawsock_posix.go b/src/net/iprawsock_posix.go
index e11eace..94db068 100644
--- a/src/net/iprawsock_posix.go
+++ b/src/net/iprawsock_posix.go
@@ -43,13 +43,6 @@
 	return syscall.AF_INET6
 }
 
-func (a *IPAddr) isWildcard() bool {
-	if a == nil || a.IP == nil {
-		return true
-	}
-	return a.IP.IsUnspecified()
-}
-
 func (a *IPAddr) sockaddr(family int) (syscall.Sockaddr, error) {
 	if a == nil {
 		return nil, nil
diff --git a/src/net/ipsock.go b/src/net/ipsock.go
index 858c6ef..98d2dbf 100644
--- a/src/net/ipsock.go
+++ b/src/net/ipsock.go
@@ -64,7 +64,7 @@
 // implement the netaddr interface. Known filters are nil, ipv4only
 // and ipv6only. It returns any address when filter is nil. The result
 // contains at least one address when error is nil.
-func firstFavoriteAddr(filter func(IP) IP, ips []IP, inetaddr func(IP) netaddr) (netaddr, error) {
+func firstFavoriteAddr(filter func(IPAddr) bool, ips []IPAddr, inetaddr func(IPAddr) netaddr) (netaddr, error) {
 	if filter != nil {
 		return firstSupportedAddr(filter, ips, inetaddr)
 	}
@@ -79,14 +79,14 @@
 		// possible. This is especially relevant if localhost
 		// resolves to [ipv6-localhost, ipv4-localhost]. Too
 		// much code assumes localhost == ipv4-localhost.
-		if ip4 := ipv4only(ip); ip4 != nil && !ipv4 {
-			list = append(list, inetaddr(ip4))
+		if ipv4only(ip) && !ipv4 {
+			list = append(list, inetaddr(ip))
 			ipv4 = true
 			if ipv6 {
 				swap = true
 			}
-		} else if ip6 := ipv6only(ip); ip6 != nil && !ipv6 {
-			list = append(list, inetaddr(ip6))
+		} else if ipv6only(ip) && !ipv6 {
+			list = append(list, inetaddr(ip))
 			ipv6 = true
 		}
 		if ipv4 && ipv6 {
@@ -106,33 +106,25 @@
 	}
 }
 
-func firstSupportedAddr(filter func(IP) IP, ips []IP, inetaddr func(IP) netaddr) (netaddr, error) {
+func firstSupportedAddr(filter func(IPAddr) bool, ips []IPAddr, inetaddr func(IPAddr) netaddr) (netaddr, error) {
 	for _, ip := range ips {
-		if ip := filter(ip); ip != nil {
+		if filter(ip) {
 			return inetaddr(ip), nil
 		}
 	}
 	return nil, errNoSuitableAddress
 }
 
-// ipv4only returns IPv4 addresses that we can use with the kernel's
-// IPv4 addressing modes. If ip is an IPv4 address, ipv4only returns ip.
-// Otherwise it returns nil.
-func ipv4only(ip IP) IP {
-	if supportsIPv4 && ip.To4() != nil {
-		return ip
-	}
-	return nil
+// ipv4only reports whether the kernel supports IPv4 addressing mode
+// and addr is an IPv4 address.
+func ipv4only(addr IPAddr) bool {
+	return supportsIPv4 && addr.IP.To4() != nil
 }
 
-// ipv6only returns IPv6 addresses that we can use with the kernel's
-// IPv6 addressing modes.  It returns IPv4-mapped IPv6 addresses as
-// nils and returns other IPv6 address types as IPv6 addresses.
-func ipv6only(ip IP) IP {
-	if supportsIPv6 && len(ip) == IPv6len && ip.To4() == nil {
-		return ip
-	}
-	return nil
+// ipv6only reports whether the kernel supports IPv6 addressing mode
+// and addr is an IPv6 address except IPv4-mapped IPv6 address.
+func ipv6only(addr IPAddr) bool {
+	return supportsIPv6 && len(addr.IP) == IPv6len && addr.IP.To4() == nil
 }
 
 // SplitHostPort splits a network address of the form "host:port",
@@ -236,9 +228,9 @@
 // address when error is nil.
 func resolveInternetAddr(net, addr string, deadline time.Time) (netaddr, error) {
 	var (
-		err              error
-		host, port, zone string
-		portnum          int
+		err        error
+		host, port string
+		portnum    int
 	)
 	switch net {
 	case "tcp", "tcp4", "tcp6", "udp", "udp4", "udp6":
@@ -257,40 +249,40 @@
 	default:
 		return nil, UnknownNetworkError(net)
 	}
-	inetaddr := func(ip IP) netaddr {
+	inetaddr := func(ip IPAddr) netaddr {
 		switch net {
 		case "tcp", "tcp4", "tcp6":
-			return &TCPAddr{IP: ip, Port: portnum, Zone: zone}
+			return &TCPAddr{IP: ip.IP, Port: portnum, Zone: ip.Zone}
 		case "udp", "udp4", "udp6":
-			return &UDPAddr{IP: ip, Port: portnum, Zone: zone}
+			return &UDPAddr{IP: ip.IP, Port: portnum, Zone: ip.Zone}
 		case "ip", "ip4", "ip6":
-			return &IPAddr{IP: ip, Zone: zone}
+			return &IPAddr{IP: ip.IP, Zone: ip.Zone}
 		default:
 			panic("unexpected network: " + net)
 		}
 	}
 	if host == "" {
-		return inetaddr(nil), nil
+		return inetaddr(IPAddr{}), nil
 	}
 	// Try as a literal IP address.
 	var ip IP
 	if ip = parseIPv4(host); ip != nil {
-		return inetaddr(ip), nil
+		return inetaddr(IPAddr{IP: ip}), nil
 	}
+	var zone string
 	if ip, zone = parseIPv6(host, true); ip != nil {
-		return inetaddr(ip), nil
+		return inetaddr(IPAddr{IP: ip, Zone: zone}), nil
 	}
 	// Try as a DNS name.
-	host, zone = splitHostZone(host)
 	ips, err := lookupIPDeadline(host, deadline)
 	if err != nil {
 		return nil, err
 	}
-	var filter func(IP) IP
+	var filter func(IPAddr) bool
 	if net != "" && net[len(net)-1] == '4' {
 		filter = ipv4only
 	}
-	if net != "" && net[len(net)-1] == '6' || zone != "" {
+	if net != "" && net[len(net)-1] == '6' {
 		filter = ipv6only
 	}
 	return firstFavoriteAddr(filter, ips, inetaddr)
diff --git a/src/net/ipsock_posix.go b/src/net/ipsock_posix.go
index f9ebe40..7597a92 100644
--- a/src/net/ipsock_posix.go
+++ b/src/net/ipsock_posix.go
@@ -14,12 +14,12 @@
 )
 
 func probeIPv4Stack() bool {
-	s, err := syscall.Socket(syscall.AF_INET, syscall.SOCK_STREAM, syscall.IPPROTO_TCP)
+	s, err := socketFunc(syscall.AF_INET, syscall.SOCK_STREAM, syscall.IPPROTO_TCP)
 	switch err {
 	case syscall.EAFNOSUPPORT, syscall.EPROTONOSUPPORT:
 		return false
 	case nil:
-		closesocket(s)
+		closeFunc(s)
 	}
 	return true
 }
@@ -50,11 +50,11 @@
 	}
 
 	for i := range probes {
-		s, err := syscall.Socket(syscall.AF_INET6, syscall.SOCK_STREAM, syscall.IPPROTO_TCP)
+		s, err := socketFunc(syscall.AF_INET6, syscall.SOCK_STREAM, syscall.IPPROTO_TCP)
 		if err != nil {
 			continue
 		}
-		defer closesocket(s)
+		defer closeFunc(s)
 		syscall.SetsockoptInt(s, syscall.IPPROTO_IPV6, syscall.IPV6_V6ONLY, probes[i].value)
 		sa, err := probes[i].laddr.sockaddr(syscall.AF_INET6)
 		if err != nil {
diff --git a/src/net/ipsock_test.go b/src/net/ipsock_test.go
index 9ecaaec..754ccbb 100644
--- a/src/net/ipsock_test.go
+++ b/src/net/ipsock_test.go
@@ -9,20 +9,20 @@
 	"testing"
 )
 
-var testInetaddr = func(ip IP) netaddr { return &TCPAddr{IP: ip, Port: 5682} }
+var testInetaddr = func(ip IPAddr) netaddr { return &TCPAddr{IP: ip.IP, Port: 5682, Zone: ip.Zone} }
 
 var firstFavoriteAddrTests = []struct {
-	filter   func(IP) IP
-	ips      []IP
-	inetaddr func(IP) netaddr
+	filter   func(IPAddr) bool
+	ips      []IPAddr
+	inetaddr func(IPAddr) netaddr
 	addr     netaddr
 	err      error
 }{
 	{
 		nil,
-		[]IP{
-			IPv4(127, 0, 0, 1),
-			IPv6loopback,
+		[]IPAddr{
+			{IP: IPv4(127, 0, 0, 1)},
+			{IP: IPv6loopback},
 		},
 		testInetaddr,
 		addrList{
@@ -33,9 +33,9 @@
 	},
 	{
 		nil,
-		[]IP{
-			IPv6loopback,
-			IPv4(127, 0, 0, 1),
+		[]IPAddr{
+			{IP: IPv6loopback},
+			{IP: IPv4(127, 0, 0, 1)},
 		},
 		testInetaddr,
 		addrList{
@@ -46,9 +46,9 @@
 	},
 	{
 		nil,
-		[]IP{
-			IPv4(127, 0, 0, 1),
-			IPv4(192, 168, 0, 1),
+		[]IPAddr{
+			{IP: IPv4(127, 0, 0, 1)},
+			{IP: IPv4(192, 168, 0, 1)},
 		},
 		testInetaddr,
 		&TCPAddr{IP: IPv4(127, 0, 0, 1), Port: 5682},
@@ -56,9 +56,9 @@
 	},
 	{
 		nil,
-		[]IP{
-			IPv6loopback,
-			ParseIP("fe80::1"),
+		[]IPAddr{
+			{IP: IPv6loopback},
+			{IP: ParseIP("fe80::1"), Zone: "eth0"},
 		},
 		testInetaddr,
 		&TCPAddr{IP: IPv6loopback, Port: 5682},
@@ -66,11 +66,11 @@
 	},
 	{
 		nil,
-		[]IP{
-			IPv4(127, 0, 0, 1),
-			IPv4(192, 168, 0, 1),
-			IPv6loopback,
-			ParseIP("fe80::1"),
+		[]IPAddr{
+			{IP: IPv4(127, 0, 0, 1)},
+			{IP: IPv4(192, 168, 0, 1)},
+			{IP: IPv6loopback},
+			{IP: ParseIP("fe80::1"), Zone: "eth0"},
 		},
 		testInetaddr,
 		addrList{
@@ -81,11 +81,11 @@
 	},
 	{
 		nil,
-		[]IP{
-			IPv6loopback,
-			ParseIP("fe80::1"),
-			IPv4(127, 0, 0, 1),
-			IPv4(192, 168, 0, 1),
+		[]IPAddr{
+			{IP: IPv6loopback},
+			{IP: ParseIP("fe80::1"), Zone: "eth0"},
+			{IP: IPv4(127, 0, 0, 1)},
+			{IP: IPv4(192, 168, 0, 1)},
 		},
 		testInetaddr,
 		addrList{
@@ -96,11 +96,11 @@
 	},
 	{
 		nil,
-		[]IP{
-			IPv4(127, 0, 0, 1),
-			IPv6loopback,
-			IPv4(192, 168, 0, 1),
-			ParseIP("fe80::1"),
+		[]IPAddr{
+			{IP: IPv4(127, 0, 0, 1)},
+			{IP: IPv6loopback},
+			{IP: IPv4(192, 168, 0, 1)},
+			{IP: ParseIP("fe80::1"), Zone: "eth0"},
 		},
 		testInetaddr,
 		addrList{
@@ -111,11 +111,11 @@
 	},
 	{
 		nil,
-		[]IP{
-			IPv6loopback,
-			IPv4(127, 0, 0, 1),
-			ParseIP("fe80::1"),
-			IPv4(192, 168, 0, 1),
+		[]IPAddr{
+			{IP: IPv6loopback},
+			{IP: IPv4(127, 0, 0, 1)},
+			{IP: ParseIP("fe80::1"), Zone: "eth0"},
+			{IP: IPv4(192, 168, 0, 1)},
 		},
 		testInetaddr,
 		addrList{
@@ -127,9 +127,9 @@
 
 	{
 		ipv4only,
-		[]IP{
-			IPv4(127, 0, 0, 1),
-			IPv6loopback,
+		[]IPAddr{
+			{IP: IPv4(127, 0, 0, 1)},
+			{IP: IPv6loopback},
 		},
 		testInetaddr,
 		&TCPAddr{IP: IPv4(127, 0, 0, 1), Port: 5682},
@@ -137,9 +137,9 @@
 	},
 	{
 		ipv4only,
-		[]IP{
-			IPv6loopback,
-			IPv4(127, 0, 0, 1),
+		[]IPAddr{
+			{IP: IPv6loopback},
+			{IP: IPv4(127, 0, 0, 1)},
 		},
 		testInetaddr,
 		&TCPAddr{IP: IPv4(127, 0, 0, 1), Port: 5682},
@@ -148,9 +148,9 @@
 
 	{
 		ipv6only,
-		[]IP{
-			IPv4(127, 0, 0, 1),
-			IPv6loopback,
+		[]IPAddr{
+			{IP: IPv4(127, 0, 0, 1)},
+			{IP: IPv6loopback},
 		},
 		testInetaddr,
 		&TCPAddr{IP: IPv6loopback, Port: 5682},
@@ -158,9 +158,9 @@
 	},
 	{
 		ipv6only,
-		[]IP{
-			IPv6loopback,
-			IPv4(127, 0, 0, 1),
+		[]IPAddr{
+			{IP: IPv6loopback},
+			{IP: IPv4(127, 0, 0, 1)},
 		},
 		testInetaddr,
 		&TCPAddr{IP: IPv6loopback, Port: 5682},
@@ -170,10 +170,10 @@
 	{nil, nil, testInetaddr, nil, errNoSuitableAddress},
 
 	{ipv4only, nil, testInetaddr, nil, errNoSuitableAddress},
-	{ipv4only, []IP{IPv6loopback}, testInetaddr, nil, errNoSuitableAddress},
+	{ipv4only, []IPAddr{{IP: IPv6loopback}}, testInetaddr, nil, errNoSuitableAddress},
 
 	{ipv6only, nil, testInetaddr, nil, errNoSuitableAddress},
-	{ipv6only, []IP{IPv4(127, 0, 0, 1)}, testInetaddr, nil, errNoSuitableAddress},
+	{ipv6only, []IPAddr{{IP: IPv4(127, 0, 0, 1)}}, testInetaddr, nil, errNoSuitableAddress},
 }
 
 func TestFirstFavoriteAddr(t *testing.T) {
diff --git a/src/net/lookup.go b/src/net/lookup.go
index aeffe6c..65abc81 100644
--- a/src/net/lookup.go
+++ b/src/net/lookup.go
@@ -27,8 +27,16 @@
 
 // LookupIP looks up host using the local resolver.
 // It returns an array of that host's IPv4 and IPv6 addresses.
-func LookupIP(host string) (addrs []IP, err error) {
-	return lookupIPMerge(host)
+func LookupIP(host string) (ips []IP, err error) {
+	addrs, err := lookupIPMerge(host)
+	if err != nil {
+		return
+	}
+	ips = make([]IP, len(addrs))
+	for i, addr := range addrs {
+		ips[i] = addr.IP
+	}
+	return
 }
 
 var lookupGroup singleflight
@@ -36,7 +44,7 @@
 // lookupIPMerge wraps lookupIP, but makes sure that for any given
 // host, only one lookup is in-flight at a time. The returned memory
 // is always owned by the caller.
-func lookupIPMerge(host string) (addrs []IP, err error) {
+func lookupIPMerge(host string) (addrs []IPAddr, err error) {
 	addrsi, err, shared := lookupGroup.Do(host, func() (interface{}, error) {
 		return lookupIP(host)
 	})
@@ -45,13 +53,13 @@
 
 // lookupIPReturn turns the return values from singleflight.Do into
 // the return values from LookupIP.
-func lookupIPReturn(addrsi interface{}, err error, shared bool) ([]IP, error) {
+func lookupIPReturn(addrsi interface{}, err error, shared bool) ([]IPAddr, error) {
 	if err != nil {
 		return nil, err
 	}
-	addrs := addrsi.([]IP)
+	addrs := addrsi.([]IPAddr)
 	if shared {
-		clone := make([]IP, len(addrs))
+		clone := make([]IPAddr, len(addrs))
 		copy(clone, addrs)
 		addrs = clone
 	}
@@ -59,7 +67,7 @@
 }
 
 // lookupIPDeadline looks up a hostname with a deadline.
-func lookupIPDeadline(host string, deadline time.Time) (addrs []IP, err error) {
+func lookupIPDeadline(host string, deadline time.Time) (addrs []IPAddr, err error) {
 	if deadline.IsZero() {
 		return lookupIPMerge(host)
 	}
diff --git a/src/net/lookup_plan9.go b/src/net/lookup_plan9.go
index b80ac10..73abbad 100644
--- a/src/net/lookup_plan9.go
+++ b/src/net/lookup_plan9.go
@@ -147,14 +147,16 @@
 	return
 }
 
-func lookupIP(host string) (ips []IP, err error) {
-	addrs, err := LookupHost(host)
+func lookupIP(host string) (addrs []IPAddr, err error) {
+	lits, err := LookupHost(host)
 	if err != nil {
 		return
 	}
-	for _, addr := range addrs {
-		if ip := ParseIP(addr); ip != nil {
-			ips = append(ips, ip)
+	for _, lit := range lits {
+		host, zone := splitHostZone(lit)
+		if ip := ParseIP(host); ip != nil {
+			addr := IPAddr{IP: ip, Zone: zone}
+			addrs = append(addrs, addr)
 		}
 	}
 	return
diff --git a/src/net/lookup_stub.go b/src/net/lookup_stub.go
index 502aafb..5636198 100644
--- a/src/net/lookup_stub.go
+++ b/src/net/lookup_stub.go
@@ -16,7 +16,7 @@
 	return nil, syscall.ENOPROTOOPT
 }
 
-func lookupIP(host string) (ips []IP, err error) {
+func lookupIP(host string) (addrs []IPAddr, err error) {
 	return nil, syscall.ENOPROTOOPT
 }
 
diff --git a/src/net/lookup_unix.go b/src/net/lookup_unix.go
index a545784..473adf8 100644
--- a/src/net/lookup_unix.go
+++ b/src/net/lookup_unix.go
@@ -60,7 +60,7 @@
 	return
 }
 
-func lookupIP(host string) (addrs []IP, err error) {
+func lookupIP(host string) (addrs []IPAddr, err error) {
 	addrs, err, ok := cgoLookupIP(host)
 	if !ok {
 		addrs, err = goLookupIP(host)
diff --git a/src/net/lookup_windows.go b/src/net/lookup_windows.go
index 6a925b0..6a8d918 100644
--- a/src/net/lookup_windows.go
+++ b/src/net/lookup_windows.go
@@ -62,7 +62,7 @@
 	return
 }
 
-func gethostbyname(name string) (addrs []IP, err error) {
+func gethostbyname(name string) (addrs []IPAddr, err error) {
 	// caller already acquired thread
 	h, err := syscall.GetHostByName(name)
 	if err != nil {
@@ -71,9 +71,9 @@
 	switch h.AddrType {
 	case syscall.AF_INET:
 		i := 0
-		addrs = make([]IP, 100) // plenty of room to grow
+		addrs = make([]IPAddr, 100) // plenty of room to grow
 		for p := (*[100](*[4]byte))(unsafe.Pointer(h.AddrList)); i < cap(addrs) && p[i] != nil; i++ {
-			addrs[i] = IPv4(p[i][0], p[i][1], p[i][2], p[i][3])
+			addrs[i] = IPAddr{IP: IPv4(p[i][0], p[i][1], p[i][2], p[i][3])}
 		}
 		addrs = addrs[0:i]
 	default: // TODO(vcc): Implement non IPv4 address lookups.
@@ -82,11 +82,11 @@
 	return addrs, nil
 }
 
-func oldLookupIP(name string) (addrs []IP, err error) {
+func oldLookupIP(name string) (addrs []IPAddr, err error) {
 	// GetHostByName return value is stored in thread local storage.
 	// Start new os thread before the call to prevent races.
 	type result struct {
-		addrs []IP
+		addrs []IPAddr
 		err   error
 	}
 	ch := make(chan result)
@@ -99,10 +99,10 @@
 		ch <- result{addrs: addrs, err: err}
 	}()
 	r := <-ch
-	return r.addrs, r.err
+	return addrs, r.err
 }
 
-func newLookupIP(name string) (addrs []IP, err error) {
+func newLookupIP(name string) (addrs []IPAddr, err error) {
 	acquireThread()
 	defer releaseThread()
 	hints := syscall.AddrinfoW{
@@ -116,16 +116,17 @@
 		return nil, os.NewSyscallError("GetAddrInfoW", e)
 	}
 	defer syscall.FreeAddrInfoW(result)
-	addrs = make([]IP, 0, 5)
+	addrs = make([]IPAddr, 0, 5)
 	for ; result != nil; result = result.Next {
 		addr := unsafe.Pointer(result.Addr)
 		switch result.Family {
 		case syscall.AF_INET:
 			a := (*syscall.RawSockaddrInet4)(addr).Addr
-			addrs = append(addrs, IPv4(a[0], a[1], a[2], a[3]))
+			addrs = append(addrs, IPAddr{IP: IPv4(a[0], a[1], a[2], a[3])})
 		case syscall.AF_INET6:
 			a := (*syscall.RawSockaddrInet6)(addr).Addr
-			addrs = append(addrs, IP{a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8], a[9], a[10], a[11], a[12], a[13], a[14], a[15]})
+			zone := zoneToString(int((*syscall.RawSockaddrInet6)(addr).Scope_id))
+			addrs = append(addrs, IPAddr{IP: IP{a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8], a[9], a[10], a[11], a[12], a[13], a[14], a[15]}, Zone: zone})
 		default:
 			return nil, os.NewSyscallError("LookupIP", syscall.EWINDOWS)
 		}
diff --git a/src/net/mail/message.go b/src/net/mail/message.go
index 71fe74b..f3f698c 100644
--- a/src/net/mail/message.go
+++ b/src/net/mail/message.go
@@ -428,7 +428,7 @@
 	"0123456789" +
 	"!#$%&'*+-/=?^_`{|}~")
 
-// isAtext returns true if c is an RFC 5322 atext character.
+// isAtext reports whether c is an RFC 5322 atext character.
 // If dot is true, period is included.
 func isAtext(c byte, dot bool) bool {
 	if dot && c == '.' {
@@ -437,7 +437,7 @@
 	return bytes.IndexByte(atextChars, c) >= 0
 }
 
-// isQtext returns true if c is an RFC 5322 qtext character.
+// isQtext reports whether c is an RFC 5322 qtext character.
 func isQtext(c byte) bool {
 	// Printable US-ASCII, excluding backslash or quote.
 	if c == '\\' || c == '"' {
@@ -446,13 +446,13 @@
 	return '!' <= c && c <= '~'
 }
 
-// isVchar returns true if c is an RFC 5322 VCHAR character.
+// isVchar reports whether c is an RFC 5322 VCHAR character.
 func isVchar(c byte) bool {
 	// Visible (printing) characters.
 	return '!' <= c && c <= '~'
 }
 
-// isWSP returns true if c is a WSP (white space).
+// isWSP reports whether c is a WSP (white space).
 // WSP is a space or horizontal tab (RFC5234 Appendix B).
 func isWSP(c byte) bool {
 	return c == ' ' || c == '\t'
diff --git a/src/net/main_cloexec_test.go b/src/net/main_cloexec_test.go
new file mode 100644
index 0000000..7903819
--- /dev/null
+++ b/src/net/main_cloexec_test.go
@@ -0,0 +1,25 @@
+// Copyright 2015 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.
+
+// +build freebsd linux
+
+package net
+
+func init() {
+	extraTestHookInstallers = append(extraTestHookInstallers, installAccept4TestHook)
+	extraTestHookUninstallers = append(extraTestHookUninstallers, uninstallAccept4TestHook)
+}
+
+var (
+	// Placeholders for saving original socket system calls.
+	origAccept4 = accept4Func
+)
+
+func installAccept4TestHook() {
+	accept4Func = sw.Accept4
+}
+
+func uninstallAccept4TestHook() {
+	accept4Func = origAccept4
+}
diff --git a/src/net/main_plan9_test.go b/src/net/main_plan9_test.go
new file mode 100644
index 0000000..bbd47aa
--- /dev/null
+++ b/src/net/main_plan9_test.go
@@ -0,0 +1,11 @@
+// Copyright 2015 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 net
+
+func installTestHooks() {}
+
+func uninstallTestHooks() {}
+
+func forceCloseSockets() {}
diff --git a/src/net/main_test.go b/src/net/main_test.go
new file mode 100644
index 0000000..bc0f92e
--- /dev/null
+++ b/src/net/main_test.go
@@ -0,0 +1,89 @@
+// Copyright 2015 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 net
+
+import (
+	"fmt"
+	"net/internal/socktest"
+	"os"
+	"runtime"
+	"sort"
+	"strings"
+	"testing"
+)
+
+var sw socktest.Switch
+
+func TestMain(m *testing.M) {
+	installTestHooks()
+
+	st := m.Run()
+
+	if !testing.Short() {
+		printLeakedGoroutines()
+		printLeakedSockets()
+		printSocketStats()
+	}
+	forceCloseSockets()
+	uninstallTestHooks()
+	os.Exit(st)
+}
+
+func printLeakedGoroutines() {
+	gss := leakedGoroutines()
+	if len(gss) == 0 {
+		return
+	}
+	fmt.Fprintf(os.Stderr, "Leaked goroutines:\n")
+	for _, gs := range gss {
+		fmt.Fprintf(os.Stderr, "%v\n", gs)
+	}
+	fmt.Fprintf(os.Stderr, "\n")
+}
+
+// leakedGoroutines returns a list of remaining goroutins used in test
+// cases.
+func leakedGoroutines() []string {
+	var gss []string
+	b := make([]byte, 2<<20)
+	b = b[:runtime.Stack(b, true)]
+	for _, s := range strings.Split(string(b), "\n\n") {
+		ss := strings.SplitN(s, "\n", 2)
+		if len(ss) != 2 {
+			continue
+		}
+		stack := strings.TrimSpace(ss[1])
+		if !strings.Contains(stack, "created by net") {
+			continue
+		}
+		gss = append(gss, stack)
+	}
+	sort.Strings(gss)
+	return gss
+}
+
+func printLeakedSockets() {
+	sos := sw.Sockets()
+	if len(sos) == 0 {
+		return
+	}
+	fmt.Fprintf(os.Stderr, "Leaked sockets:\n")
+	for s, so := range sos {
+		fmt.Fprintf(os.Stderr, "%v: %+v\n", s, so)
+	}
+	fmt.Fprintf(os.Stderr, "\n")
+}
+
+func printSocketStats() {
+	sts := sw.Stats()
+	if len(sts) == 0 {
+		return
+	}
+	fmt.Fprintf(os.Stderr, "Socket statistical information:\n")
+	for _, st := range sts {
+		fmt.Fprintf(os.Stderr, "%+v\n", st)
+	}
+	fmt.Fprintf(os.Stderr, "\n")
+}
diff --git a/src/net/main_unix_test.go b/src/net/main_unix_test.go
new file mode 100644
index 0000000..637ac3d
--- /dev/null
+++ b/src/net/main_unix_test.go
@@ -0,0 +1,49 @@
+// Copyright 2015 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.
+
+// +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris
+
+package net
+
+var (
+	// Placeholders for saving original socket system calls.
+	origSocket        = socketFunc
+	origClose         = closeFunc
+	origConnect       = connectFunc
+	origAccept        = acceptFunc
+	origGetsockoptInt = getsockoptIntFunc
+
+	extraTestHookInstallers   []func()
+	extraTestHookUninstallers []func()
+)
+
+func installTestHooks() {
+	socketFunc = sw.Socket
+	closeFunc = sw.Close
+	connectFunc = sw.Connect
+	acceptFunc = sw.Accept
+	getsockoptIntFunc = sw.GetsockoptInt
+
+	for _, fn := range extraTestHookInstallers {
+		fn()
+	}
+}
+
+func uninstallTestHooks() {
+	socketFunc = origSocket
+	closeFunc = origClose
+	connectFunc = origConnect
+	acceptFunc = origAccept
+	getsockoptIntFunc = origGetsockoptInt
+
+	for _, fn := range extraTestHookUninstallers {
+		fn()
+	}
+}
+
+func forceCloseSockets() {
+	for s := range sw.Sockets() {
+		closeFunc(s)
+	}
+}
diff --git a/src/net/main_windows_test.go b/src/net/main_windows_test.go
new file mode 100644
index 0000000..03c3796
--- /dev/null
+++ b/src/net/main_windows_test.go
@@ -0,0 +1,33 @@
+// Copyright 2015 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 net
+
+var (
+	// Placeholders for saving original socket system calls.
+	origSocket      = socketFunc
+	origClosesocket = closeFunc
+	origConnect     = connectFunc
+	origConnectEx   = connectExFunc
+)
+
+func installTestHooks() {
+	socketFunc = sw.Socket
+	closeFunc = sw.Closesocket
+	connectFunc = sw.Connect
+	connectExFunc = sw.ConnectEx
+}
+
+func uninstallTestHooks() {
+	socketFunc = origSocket
+	closeFunc = origClosesocket
+	connectFunc = origConnect
+	connectExFunc = origConnectEx
+}
+
+func forceCloseSockets() {
+	for s := range sw.Sockets() {
+		closeFunc(s)
+	}
+}
diff --git a/src/net/net_test.go b/src/net/net_test.go
index bfed4d6..5a88363 100644
--- a/src/net/net_test.go
+++ b/src/net/net_test.go
@@ -63,10 +63,10 @@
 }
 
 func TestShutdownUnix(t *testing.T) {
-	switch runtime.GOOS {
-	case "nacl", "plan9", "windows":
-		t.Skipf("skipping test on %q", runtime.GOOS)
+	if !testableNetwork("unix") {
+		t.Skip("unix test")
 	}
+
 	f, err := ioutil.TempFile("", "go_net_unixtest")
 	if err != nil {
 		t.Fatalf("TempFile: %s", err)
diff --git a/src/net/packetconn_test.go b/src/net/packetconn_test.go
index 5bbfc0f..31e050f 100644
--- a/src/net/packetconn_test.go
+++ b/src/net/packetconn_test.go
@@ -9,8 +9,6 @@
 
 import (
 	"os"
-	"runtime"
-	"strings"
 	"testing"
 	"time"
 )
@@ -21,24 +19,11 @@
 //	golang.org/x/net/ipv6
 //	golang.org/x/net/icmp
 
-func packetConnTestData(t *testing.T, net string, i int) ([]byte, func()) {
-	switch net {
-	case "udp":
-		return []byte("UDP PACKETCONN TEST"), nil
-	case "unixgram":
-		switch runtime.GOOS {
-		case "nacl", "plan9", "windows":
-			return nil, func() {
-				t.Logf("skipping %q test on %q", net, runtime.GOOS)
-			}
-		default:
-			return []byte("UNIXGRAM PACKETCONN TEST"), nil
-		}
-	default:
-		return nil, func() {
-			t.Logf("skipping %q test", net)
-		}
+func packetConnTestData(t *testing.T, network string) ([]byte, func()) {
+	if !testableNetwork(network) {
+		return nil, func() { t.Logf("skipping %s test", network) }
 	}
+	return []byte("PACKETCONN TEST"), nil
 }
 
 var packetConnTests = []struct {
@@ -60,9 +45,8 @@
 		}
 	}
 
-	for i, tt := range packetConnTests {
-		netstr := strings.Split(tt.net, ":")
-		wb, skipOrFatalFn := packetConnTestData(t, netstr[0], i)
+	for _, tt := range packetConnTests {
+		wb, skipOrFatalFn := packetConnTestData(t, tt.net)
 		if skipOrFatalFn != nil {
 			skipOrFatalFn()
 			continue
@@ -72,7 +56,7 @@
 		if err != nil {
 			t.Fatalf("ListenPacket failed: %v", err)
 		}
-		defer closer(c1, netstr[0], tt.addr1, tt.addr2)
+		defer closer(c1, tt.net, tt.addr1, tt.addr2)
 		c1.LocalAddr()
 		c1.SetDeadline(time.Now().Add(500 * time.Millisecond))
 		c1.SetReadDeadline(time.Now().Add(500 * time.Millisecond))
@@ -82,7 +66,7 @@
 		if err != nil {
 			t.Fatalf("ListenPacket failed: %v", err)
 		}
-		defer closer(c2, netstr[0], tt.addr1, tt.addr2)
+		defer closer(c2, tt.net, tt.addr1, tt.addr2)
 		c2.LocalAddr()
 		c2.SetDeadline(time.Now().Add(500 * time.Millisecond))
 		c2.SetReadDeadline(time.Now().Add(500 * time.Millisecond))
@@ -115,10 +99,9 @@
 		}
 	}
 
-	for i, tt := range packetConnTests {
+	for _, tt := range packetConnTests {
 		var wb []byte
-		netstr := strings.Split(tt.net, ":")
-		wb, skipOrFatalFn := packetConnTestData(t, netstr[0], i)
+		wb, skipOrFatalFn := packetConnTestData(t, tt.net)
 		if skipOrFatalFn != nil {
 			skipOrFatalFn()
 			continue
@@ -128,7 +111,7 @@
 		if err != nil {
 			t.Fatalf("ListenPacket failed: %v", err)
 		}
-		defer closer(c1, netstr[0], tt.addr1, tt.addr2)
+		defer closer(c1, tt.net, tt.addr1, tt.addr2)
 		c1.LocalAddr()
 		c1.SetDeadline(time.Now().Add(500 * time.Millisecond))
 		c1.SetReadDeadline(time.Now().Add(500 * time.Millisecond))
@@ -153,9 +136,7 @@
 			t.Fatalf("PacketConn.ReadFrom failed: %v", err)
 		}
 		var dst Addr
-		switch netstr[0] {
-		case "ip":
-			dst = &IPAddr{IP: IPv4(127, 0, 0, 1)}
+		switch tt.net {
 		case "unixgram":
 			continue
 		default:
diff --git a/src/net/platform_test.go b/src/net/platform_test.go
new file mode 100644
index 0000000..a1e766d
--- /dev/null
+++ b/src/net/platform_test.go
@@ -0,0 +1,137 @@
+// Copyright 2015 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 net
+
+import (
+	"os"
+	"runtime"
+	"strings"
+	"testing"
+)
+
+// testableNetwork reports whether network is testable on the current
+// platform configuration.
+func testableNetwork(network string) bool {
+	switch ss := strings.Split(network, ":"); ss[0] {
+	case "ip+nopriv":
+		switch runtime.GOOS {
+		case "nacl":
+			return false
+		}
+	case "ip", "ip4", "ip6":
+		switch runtime.GOOS {
+		case "nacl", "plan9":
+			return false
+		default:
+			if os.Getuid() != 0 {
+				return false
+			}
+		}
+	case "unix", "unixgram":
+		switch runtime.GOOS {
+		case "nacl", "plan9", "windows":
+			return false
+		}
+		// iOS does not support unix, unixgram.
+		if runtime.GOOS == "darwin" && (runtime.GOARCH == "arm" || runtime.GOARCH == "arm64") {
+			return false
+		}
+	case "unixpacket":
+		switch runtime.GOOS {
+		case "android", "darwin", "nacl", "openbsd", "plan9", "windows":
+			fallthrough
+		case "freebsd": // FreeBSD 8 and below don't support unixpacket
+			return false
+		}
+	}
+	return true
+}
+
+// testableAddress reports whether address of network is testable on
+// the current platform configuration.
+func testableAddress(network, address string) bool {
+	switch ss := strings.Split(network, ":"); ss[0] {
+	case "unix", "unixgram", "unixpacket":
+		// Abstract unix domain sockets, a Linux-ism.
+		if address[0] == '@' && runtime.GOOS != "linux" {
+			return false
+		}
+	}
+	return true
+}
+
+// testableListenArgs reports whether arguments are testable on the
+// current platform configuration.
+func testableListenArgs(network, address, client string) bool {
+	if !testableNetwork(network) || !testableAddress(network, address) {
+		return false
+	}
+
+	var err error
+	var addr Addr
+	switch ss := strings.Split(network, ":"); ss[0] {
+	case "tcp", "tcp4", "tcp6":
+		addr, err = ResolveTCPAddr("tcp", address)
+	case "udp", "udp4", "udp6":
+		addr, err = ResolveUDPAddr("udp", address)
+	case "ip", "ip4", "ip6":
+		addr, err = ResolveIPAddr("ip", address)
+	default:
+		return true
+	}
+	if err != nil {
+		return false
+	}
+	var ip IP
+	var wildcard bool
+	switch addr := addr.(type) {
+	case *TCPAddr:
+		ip = addr.IP
+		wildcard = addr.isWildcard()
+	case *UDPAddr:
+		ip = addr.IP
+		wildcard = addr.isWildcard()
+	case *IPAddr:
+		ip = addr.IP
+		wildcard = addr.isWildcard()
+	}
+
+	// Test wildcard IP addresses.
+	if wildcard && (testing.Short() || !*testExternal) {
+		return false
+	}
+
+	// Test functionality of IPv6 communication using AF_INET6
+	// sockets.
+	if !supportsIPv6 && ip.To16() != nil && ip.To4() == nil {
+		return false
+	}
+
+	// Test functionality of IPv4 communication using AF_INET6
+	// sockets.
+	cip := ParseIP(client)
+	if !supportsIPv4map && (network == "tcp" || network == "udp" || network == "ip") && wildcard {
+		// At this point, we prefer IPv4 when ip is nil.
+		// See favoriteAddrFamily for further information.
+		if ip.To16() != nil && ip.To4() == nil && cip.To4() != nil { // a pair of IPv6 server and IPv4 client
+			return false
+		}
+		if (ip.To4() != nil || ip == nil) && cip.To16() != nil && cip.To4() == nil { // a pair of IPv4 server and IPv6 client
+			return false
+		}
+	}
+
+	return true
+}
+
+var condFatalf = func() func(*testing.T, string, ...interface{}) {
+	// A few APIs, File, Read/WriteMsg{UDP,IP}, are not
+	// implemented yet on both Plan 9 and Windows.
+	switch runtime.GOOS {
+	case "plan9", "windows":
+		return (*testing.T).Logf
+	}
+	return (*testing.T).Fatalf
+}()
diff --git a/src/net/protoconn_test.go b/src/net/protoconn_test.go
index 61c35df..3a16ec5 100644
--- a/src/net/protoconn_test.go
+++ b/src/net/protoconn_test.go
@@ -35,15 +35,6 @@
 	return addr
 }
 
-var condFatalf = func() func(*testing.T, string, ...interface{}) {
-	// A few APIs are not implemented yet on both Plan 9 and Windows.
-	switch runtime.GOOS {
-	case "plan9", "windows":
-		return (*testing.T).Logf
-	}
-	return (*testing.T).Fatalf
-}()
-
 func TestTCPListenerSpecificMethods(t *testing.T) {
 	switch runtime.GOOS {
 	case "plan9":
@@ -218,9 +209,8 @@
 }
 
 func TestUnixListenerSpecificMethods(t *testing.T) {
-	switch runtime.GOOS {
-	case "nacl", "plan9", "windows":
-		t.Skipf("skipping test on %q", runtime.GOOS)
+	if !testableNetwork("unix") {
+		t.Skip("unix test")
 	}
 
 	addr := testUnixAddr()
@@ -260,9 +250,8 @@
 }
 
 func TestUnixConnSpecificMethods(t *testing.T) {
-	switch runtime.GOOS {
-	case "nacl", "plan9", "windows":
-		t.Skipf("skipping test on %q", runtime.GOOS)
+	if !testableNetwork("unixgram") {
+		t.Skip("unixgram test")
 	}
 
 	addr1, addr2, addr3 := testUnixAddr(), testUnixAddr(), testUnixAddr()
diff --git a/src/net/server_test.go b/src/net/server_test.go
index bf7feab..479c181 100644
--- a/src/net/server_test.go
+++ b/src/net/server_test.go
@@ -8,99 +8,66 @@
 	"flag"
 	"io"
 	"os"
-	"runtime"
 	"testing"
 	"time"
 )
 
-func skipServerTest(net, unixsotype, addr string, ipv6, ipv4map, linuxOnly bool) bool {
-	switch runtime.GOOS {
-	case "linux":
-	case "nacl", "plan9", "windows":
-		// "unix" sockets are not supported on Windows and Plan 9.
-		if net == unixsotype {
-			return true
-		}
-	default:
-		if net == unixsotype && linuxOnly {
-			return true
-		}
-	}
-	switch addr {
-	case "", "0.0.0.0", "[::ffff:0.0.0.0]", "[::]":
-		if testing.Short() || !*testExternal {
-			return true
-		}
-	}
-	if ipv6 && !supportsIPv6 {
-		return true
-	}
-	if ipv4map && !supportsIPv4map {
-		return true
-	}
-	return false
-}
-
 var streamConnServerTests = []struct {
-	snet      string // server side
-	saddr     string
-	cnet      string // client side
-	caddr     string
-	ipv6      bool // test with underlying AF_INET6 socket
-	ipv4map   bool // test with IPv6 IPv4-mapping functionality
-	empty     bool // test with empty data
-	linuxOnly bool // test with abstract unix domain socket, a Linux-ism
+	snet  string // server side
+	saddr string
+	cnet  string // client side
+	caddr string
+	empty bool // test with empty data
 }{
-	{snet: "tcp", saddr: "", cnet: "tcp", caddr: "127.0.0.1"},
-	{snet: "tcp", saddr: "0.0.0.0", cnet: "tcp", caddr: "127.0.0.1"},
-	{snet: "tcp", saddr: "[::ffff:0.0.0.0]", cnet: "tcp", caddr: "127.0.0.1"},
-	{snet: "tcp", saddr: "[::]", cnet: "tcp", caddr: "[::1]", ipv6: true},
+	{snet: "tcp", saddr: ":0", cnet: "tcp", caddr: "127.0.0.1"},
+	{snet: "tcp", saddr: "0.0.0.0:0", cnet: "tcp", caddr: "127.0.0.1"},
+	{snet: "tcp", saddr: "[::ffff:0.0.0.0]:0", cnet: "tcp", caddr: "127.0.0.1"},
+	{snet: "tcp", saddr: "[::]:0", cnet: "tcp", caddr: "::1"},
 
-	{snet: "tcp", saddr: "", cnet: "tcp", caddr: "[::1]", ipv4map: true},
-	{snet: "tcp", saddr: "0.0.0.0", cnet: "tcp", caddr: "[::1]", ipv4map: true},
-	{snet: "tcp", saddr: "[::ffff:0.0.0.0]", cnet: "tcp", caddr: "[::1]", ipv4map: true},
-	{snet: "tcp", saddr: "[::]", cnet: "tcp", caddr: "127.0.0.1", ipv4map: true},
+	{snet: "tcp", saddr: ":0", cnet: "tcp", caddr: "::1"},
+	{snet: "tcp", saddr: "0.0.0.0:0", cnet: "tcp", caddr: "::1"},
+	{snet: "tcp", saddr: "[::ffff:0.0.0.0]:0", cnet: "tcp", caddr: "::1"},
+	{snet: "tcp", saddr: "[::]:0", cnet: "tcp", caddr: "127.0.0.1"},
 
-	{snet: "tcp", saddr: "", cnet: "tcp4", caddr: "127.0.0.1"},
-	{snet: "tcp", saddr: "0.0.0.0", cnet: "tcp4", caddr: "127.0.0.1"},
-	{snet: "tcp", saddr: "[::ffff:0.0.0.0]", cnet: "tcp4", caddr: "127.0.0.1"},
-	{snet: "tcp", saddr: "[::]", cnet: "tcp6", caddr: "[::1]", ipv6: true},
+	{snet: "tcp", saddr: ":0", cnet: "tcp4", caddr: "127.0.0.1"},
+	{snet: "tcp", saddr: "0.0.0.0:0", cnet: "tcp4", caddr: "127.0.0.1"},
+	{snet: "tcp", saddr: "[::ffff:0.0.0.0]:0", cnet: "tcp4", caddr: "127.0.0.1"},
+	{snet: "tcp", saddr: "[::]:0", cnet: "tcp6", caddr: "::1"},
 
-	{snet: "tcp", saddr: "", cnet: "tcp6", caddr: "[::1]", ipv4map: true},
-	{snet: "tcp", saddr: "0.0.0.0", cnet: "tcp6", caddr: "[::1]", ipv4map: true},
-	{snet: "tcp", saddr: "[::ffff:0.0.0.0]", cnet: "tcp6", caddr: "[::1]", ipv4map: true},
-	{snet: "tcp", saddr: "[::]", cnet: "tcp4", caddr: "127.0.0.1", ipv4map: true},
+	{snet: "tcp", saddr: ":0", cnet: "tcp6", caddr: "::1"},
+	{snet: "tcp", saddr: "0.0.0.0:0", cnet: "tcp6", caddr: "::1"},
+	{snet: "tcp", saddr: "[::ffff:0.0.0.0]:0", cnet: "tcp6", caddr: "::1"},
+	{snet: "tcp", saddr: "[::]:0", cnet: "tcp4", caddr: "127.0.0.1"},
 
-	{snet: "tcp", saddr: "127.0.0.1", cnet: "tcp", caddr: "127.0.0.1"},
-	{snet: "tcp", saddr: "[::ffff:127.0.0.1]", cnet: "tcp", caddr: "127.0.0.1"},
-	{snet: "tcp", saddr: "[::1]", cnet: "tcp", caddr: "[::1]", ipv6: true},
+	{snet: "tcp", saddr: "127.0.0.1:0", cnet: "tcp", caddr: "127.0.0.1"},
+	{snet: "tcp", saddr: "[::ffff:127.0.0.1]:0", cnet: "tcp", caddr: "127.0.0.1"},
+	{snet: "tcp", saddr: "[::1]:0", cnet: "tcp", caddr: "::1"},
 
-	{snet: "tcp4", saddr: "", cnet: "tcp4", caddr: "127.0.0.1"},
-	{snet: "tcp4", saddr: "0.0.0.0", cnet: "tcp4", caddr: "127.0.0.1"},
-	{snet: "tcp4", saddr: "[::ffff:0.0.0.0]", cnet: "tcp4", caddr: "127.0.0.1"},
+	{snet: "tcp4", saddr: ":0", cnet: "tcp4", caddr: "127.0.0.1"},
+	{snet: "tcp4", saddr: "0.0.0.0:0", cnet: "tcp4", caddr: "127.0.0.1"},
+	{snet: "tcp4", saddr: "[::ffff:0.0.0.0]:0", cnet: "tcp4", caddr: "127.0.0.1"},
 
-	{snet: "tcp4", saddr: "127.0.0.1", cnet: "tcp4", caddr: "127.0.0.1"},
+	{snet: "tcp4", saddr: "127.0.0.1:0", cnet: "tcp4", caddr: "127.0.0.1"},
 
-	{snet: "tcp6", saddr: "", cnet: "tcp6", caddr: "[::1]", ipv6: true},
-	{snet: "tcp6", saddr: "[::]", cnet: "tcp6", caddr: "[::1]", ipv6: true},
+	{snet: "tcp6", saddr: ":0", cnet: "tcp6", caddr: "::1"},
+	{snet: "tcp6", saddr: "[::]:0", cnet: "tcp6", caddr: "::1"},
 
-	{snet: "tcp6", saddr: "[::1]", cnet: "tcp6", caddr: "[::1]", ipv6: true},
+	{snet: "tcp6", saddr: "[::1]:0", cnet: "tcp6", caddr: "::1"},
 
 	{snet: "unix", saddr: testUnixAddr(), cnet: "unix", caddr: testUnixAddr()},
-	{snet: "unix", saddr: "@gotest2/net", cnet: "unix", caddr: "@gotest2/net.local", linuxOnly: true},
+	{snet: "unix", saddr: "@gotest2/net", cnet: "unix", caddr: "@gotest2/net.local"},
 }
 
 func TestStreamConnServer(t *testing.T) {
 	for _, tt := range streamConnServerTests {
-		if skipServerTest(tt.snet, "unix", tt.saddr, tt.ipv6, tt.ipv4map, tt.linuxOnly) {
+		if !testableListenArgs(tt.snet, tt.saddr, tt.caddr) {
+			t.Logf("skipping %s test", tt.snet+":"+tt.saddr+"->"+tt.caddr)
 			continue
 		}
 
 		listening := make(chan string)
 		done := make(chan int)
 		switch tt.snet {
-		case "tcp", "tcp4", "tcp6":
-			tt.saddr += ":0"
 		case "unix":
 			os.Remove(tt.saddr)
 			os.Remove(tt.caddr)
@@ -115,7 +82,7 @@
 			if err != nil {
 				t.Fatalf("SplitHostPort(%q) failed: %v", taddr, err)
 			}
-			taddr = tt.caddr + ":" + port
+			taddr = JoinHostPort(tt.caddr, port)
 		}
 
 		runStreamConnClient(t, tt.cnet, taddr, tt.empty)
@@ -130,26 +97,19 @@
 }
 
 var seqpacketConnServerTests = []struct {
-	net       string
-	saddr     string // server address
-	caddr     string // client address
-	empty     bool   // test with empty data
-	linuxOnly bool   // test with abstract unix domain socket, a Linux-ism
+	net   string
+	saddr string // server address
+	caddr string // client address
+	empty bool   // test with empty data
 }{
 	{net: "unixpacket", saddr: testUnixAddr(), caddr: testUnixAddr()},
-	{net: "unixpacket", saddr: "@gotest4/net", caddr: "@gotest4/net.local", linuxOnly: true},
+	{net: "unixpacket", saddr: "@gotest4/net", caddr: "@gotest4/net.local"},
 }
 
 func TestSeqpacketConnServer(t *testing.T) {
-	switch runtime.GOOS {
-	case "darwin", "nacl", "openbsd", "plan9", "windows":
-		fallthrough
-	case "freebsd": // FreeBSD 8 doesn't support unixpacket
-		t.Skipf("skipping test on %q", runtime.GOOS)
-	}
-
 	for _, tt := range seqpacketConnServerTests {
-		if runtime.GOOS != "linux" && tt.linuxOnly {
+		if !testableListenArgs(tt.net, tt.saddr, tt.caddr) {
+			t.Logf("skipping %s test", tt.net+":"+tt.saddr+"->"+tt.caddr)
 			continue
 		}
 		listening := make(chan string)
@@ -248,65 +208,62 @@
 var testDatagram = flag.Bool("datagram", false, "whether to test udp and unixgram")
 
 var datagramPacketConnServerTests = []struct {
-	snet      string // server side
-	saddr     string
-	cnet      string // client side
-	caddr     string
-	ipv6      bool // test with underlying AF_INET6 socket
-	ipv4map   bool // test with IPv6 IPv4-mapping functionality
-	dial      bool // test with Dial or DialUnix
-	empty     bool // test with empty data
-	linuxOnly bool // test with abstract unix domain socket, a Linux-ism
+	snet  string // server side
+	saddr string
+	cnet  string // client side
+	caddr string
+	dial  bool // test with Dial or DialUnix
+	empty bool // test with empty data
 }{
-	{snet: "udp", saddr: "", cnet: "udp", caddr: "127.0.0.1"},
-	{snet: "udp", saddr: "0.0.0.0", cnet: "udp", caddr: "127.0.0.1"},
-	{snet: "udp", saddr: "[::ffff:0.0.0.0]", cnet: "udp", caddr: "127.0.0.1"},
-	{snet: "udp", saddr: "[::]", cnet: "udp", caddr: "[::1]", ipv6: true},
+	{snet: "udp", saddr: ":0", cnet: "udp", caddr: "127.0.0.1"},
+	{snet: "udp", saddr: "0.0.0.0:0", cnet: "udp", caddr: "127.0.0.1"},
+	{snet: "udp", saddr: "[::ffff:0.0.0.0]:0", cnet: "udp", caddr: "127.0.0.1"},
+	{snet: "udp", saddr: "[::]:0", cnet: "udp", caddr: "::1"},
 
-	{snet: "udp", saddr: "", cnet: "udp", caddr: "[::1]", ipv4map: true},
-	{snet: "udp", saddr: "0.0.0.0", cnet: "udp", caddr: "[::1]", ipv4map: true},
-	{snet: "udp", saddr: "[::ffff:0.0.0.0]", cnet: "udp", caddr: "[::1]", ipv4map: true},
-	{snet: "udp", saddr: "[::]", cnet: "udp", caddr: "127.0.0.1", ipv4map: true},
+	{snet: "udp", saddr: ":0", cnet: "udp", caddr: "::1"},
+	{snet: "udp", saddr: "0.0.0.0:0", cnet: "udp", caddr: "::1"},
+	{snet: "udp", saddr: "[::ffff:0.0.0.0]:0", cnet: "udp", caddr: "::1"},
+	{snet: "udp", saddr: "[::]:0", cnet: "udp", caddr: "127.0.0.1"},
 
-	{snet: "udp", saddr: "", cnet: "udp4", caddr: "127.0.0.1"},
-	{snet: "udp", saddr: "0.0.0.0", cnet: "udp4", caddr: "127.0.0.1"},
-	{snet: "udp", saddr: "[::ffff:0.0.0.0]", cnet: "udp4", caddr: "127.0.0.1"},
-	{snet: "udp", saddr: "[::]", cnet: "udp6", caddr: "[::1]", ipv6: true},
+	{snet: "udp", saddr: ":0", cnet: "udp4", caddr: "127.0.0.1"},
+	{snet: "udp", saddr: "0.0.0.0:0", cnet: "udp4", caddr: "127.0.0.1"},
+	{snet: "udp", saddr: "[::ffff:0.0.0.0]:0", cnet: "udp4", caddr: "127.0.0.1"},
+	{snet: "udp", saddr: "[::]:0", cnet: "udp6", caddr: "::1"},
 
-	{snet: "udp", saddr: "", cnet: "udp6", caddr: "[::1]", ipv4map: true},
-	{snet: "udp", saddr: "0.0.0.0", cnet: "udp6", caddr: "[::1]", ipv4map: true},
-	{snet: "udp", saddr: "[::ffff:0.0.0.0]", cnet: "udp6", caddr: "[::1]", ipv4map: true},
-	{snet: "udp", saddr: "[::]", cnet: "udp4", caddr: "127.0.0.1", ipv4map: true},
+	{snet: "udp", saddr: ":0", cnet: "udp6", caddr: "::1"},
+	{snet: "udp", saddr: "0.0.0.0:0", cnet: "udp6", caddr: "::1"},
+	{snet: "udp", saddr: "[::ffff:0.0.0.0]:0", cnet: "udp6", caddr: "::1"},
+	{snet: "udp", saddr: "[::]:0", cnet: "udp4", caddr: "127.0.0.1"},
 
-	{snet: "udp", saddr: "127.0.0.1", cnet: "udp", caddr: "127.0.0.1"},
-	{snet: "udp", saddr: "[::ffff:127.0.0.1]", cnet: "udp", caddr: "127.0.0.1"},
-	{snet: "udp", saddr: "[::1]", cnet: "udp", caddr: "[::1]", ipv6: true},
+	{snet: "udp", saddr: "127.0.0.1:0", cnet: "udp", caddr: "127.0.0.1"},
+	{snet: "udp", saddr: "[::ffff:127.0.0.1]:0", cnet: "udp", caddr: "127.0.0.1"},
+	{snet: "udp", saddr: "[::1]:0", cnet: "udp", caddr: "::1"},
 
-	{snet: "udp4", saddr: "", cnet: "udp4", caddr: "127.0.0.1"},
-	{snet: "udp4", saddr: "0.0.0.0", cnet: "udp4", caddr: "127.0.0.1"},
-	{snet: "udp4", saddr: "[::ffff:0.0.0.0]", cnet: "udp4", caddr: "127.0.0.1"},
+	{snet: "udp4", saddr: ":0", cnet: "udp4", caddr: "127.0.0.1"},
+	{snet: "udp4", saddr: "0.0.0.0:0", cnet: "udp4", caddr: "127.0.0.1"},
+	{snet: "udp4", saddr: "[::ffff:0.0.0.0]:0", cnet: "udp4", caddr: "127.0.0.1"},
 
-	{snet: "udp4", saddr: "127.0.0.1", cnet: "udp4", caddr: "127.0.0.1"},
+	{snet: "udp4", saddr: "127.0.0.1:0", cnet: "udp4", caddr: "127.0.0.1"},
 
-	{snet: "udp6", saddr: "", cnet: "udp6", caddr: "[::1]", ipv6: true},
-	{snet: "udp6", saddr: "[::]", cnet: "udp6", caddr: "[::1]", ipv6: true},
+	{snet: "udp6", saddr: ":0", cnet: "udp6", caddr: "::1"},
+	{snet: "udp6", saddr: "[::]:0", cnet: "udp6", caddr: "::1"},
 
-	{snet: "udp6", saddr: "[::1]", cnet: "udp6", caddr: "[::1]", ipv6: true},
+	{snet: "udp6", saddr: "[::1]:0", cnet: "udp6", caddr: "::1"},
 
-	{snet: "udp", saddr: "127.0.0.1", cnet: "udp", caddr: "127.0.0.1", dial: true},
-	{snet: "udp", saddr: "127.0.0.1", cnet: "udp", caddr: "127.0.0.1", empty: true},
-	{snet: "udp", saddr: "127.0.0.1", cnet: "udp", caddr: "127.0.0.1", dial: true, empty: true},
+	{snet: "udp", saddr: "127.0.0.1:0", cnet: "udp", caddr: "127.0.0.1", dial: true},
+	{snet: "udp", saddr: "127.0.0.1:0", cnet: "udp", caddr: "127.0.0.1", empty: true},
+	{snet: "udp", saddr: "127.0.0.1:0", cnet: "udp", caddr: "127.0.0.1", dial: true, empty: true},
 
-	{snet: "udp", saddr: "[::1]", cnet: "udp", caddr: "[::1]", ipv6: true, dial: true},
-	{snet: "udp", saddr: "[::1]", cnet: "udp", caddr: "[::1]", ipv6: true, empty: true},
-	{snet: "udp", saddr: "[::1]", cnet: "udp", caddr: "[::1]", ipv6: true, dial: true, empty: true},
+	{snet: "udp", saddr: "[::1]:0", cnet: "udp", caddr: "::1", dial: true},
+	{snet: "udp", saddr: "[::1]:0", cnet: "udp", caddr: "::1", empty: true},
+	{snet: "udp", saddr: "[::1]:0", cnet: "udp", caddr: "::1", dial: true, empty: true},
 
 	{snet: "unixgram", saddr: testUnixAddr(), cnet: "unixgram", caddr: testUnixAddr()},
 	{snet: "unixgram", saddr: testUnixAddr(), cnet: "unixgram", caddr: testUnixAddr(), dial: true},
 	{snet: "unixgram", saddr: testUnixAddr(), cnet: "unixgram", caddr: testUnixAddr(), empty: true},
 	{snet: "unixgram", saddr: testUnixAddr(), cnet: "unixgram", caddr: testUnixAddr(), dial: true, empty: true},
 
-	{snet: "unixgram", saddr: "@gotest6/net", cnet: "unixgram", caddr: "@gotest6/net.local", linuxOnly: true},
+	{snet: "unixgram", saddr: "@gotest6/net", cnet: "unixgram", caddr: "@gotest6/net.local"},
 }
 
 func TestDatagramPacketConnServer(t *testing.T) {
@@ -315,15 +272,14 @@
 	}
 
 	for _, tt := range datagramPacketConnServerTests {
-		if skipServerTest(tt.snet, "unixgram", tt.saddr, tt.ipv6, tt.ipv4map, tt.linuxOnly) {
+		if !testableListenArgs(tt.snet, tt.saddr, tt.caddr) {
+			t.Logf("skipping %s test", tt.snet+":"+tt.saddr+"->"+tt.caddr)
 			continue
 		}
 
 		listening := make(chan string)
 		done := make(chan int)
 		switch tt.snet {
-		case "udp", "udp4", "udp6":
-			tt.saddr += ":0"
 		case "unixgram":
 			os.Remove(tt.saddr)
 			os.Remove(tt.caddr)
@@ -338,8 +294,8 @@
 			if err != nil {
 				t.Fatalf("SplitHostPort(%q) failed: %v", taddr, err)
 			}
-			taddr = tt.caddr + ":" + port
-			tt.caddr += ":0"
+			taddr = JoinHostPort(tt.caddr, port)
+			tt.caddr = JoinHostPort(tt.caddr, "0")
 		}
 		if tt.dial {
 			runDatagramConnClient(t, tt.cnet, tt.caddr, taddr, tt.empty)
diff --git a/src/net/sock_cloexec.go b/src/net/sock_cloexec.go
index dec8185..842d7d5 100644
--- a/src/net/sock_cloexec.go
+++ b/src/net/sock_cloexec.go
@@ -14,7 +14,7 @@
 // Wrapper around the socket system call that marks the returned file
 // descriptor as nonblocking and close-on-exec.
 func sysSocket(family, sotype, proto int) (int, error) {
-	s, err := syscall.Socket(family, sotype|syscall.SOCK_NONBLOCK|syscall.SOCK_CLOEXEC, proto)
+	s, err := socketFunc(family, sotype|syscall.SOCK_NONBLOCK|syscall.SOCK_CLOEXEC, proto)
 	// On Linux the SOCK_NONBLOCK and SOCK_CLOEXEC flags were
 	// introduced in 2.6.27 kernel and on FreeBSD both flags were
 	// introduced in 10 kernel. If we get an EINVAL error on Linux
@@ -26,7 +26,7 @@
 
 	// See ../syscall/exec_unix.go for description of ForkLock.
 	syscall.ForkLock.RLock()
-	s, err = syscall.Socket(family, sotype, proto)
+	s, err = socketFunc(family, sotype, proto)
 	if err == nil {
 		syscall.CloseOnExec(s)
 	}
@@ -35,7 +35,7 @@
 		return -1, err
 	}
 	if err = syscall.SetNonblock(s, true); err != nil {
-		syscall.Close(s)
+		closeFunc(s)
 		return -1, err
 	}
 	return s, nil
@@ -44,7 +44,7 @@
 // Wrapper around the accept system call that marks the returned file
 // descriptor as nonblocking and close-on-exec.
 func accept(s int) (int, syscall.Sockaddr, error) {
-	ns, sa, err := syscall.Accept4(s, syscall.SOCK_NONBLOCK|syscall.SOCK_CLOEXEC)
+	ns, sa, err := accept4Func(s, syscall.SOCK_NONBLOCK|syscall.SOCK_CLOEXEC)
 	// On Linux the accept4 system call was introduced in 2.6.28
 	// kernel and on FreeBSD it was introduced in 10 kernel. If we
 	// get an ENOSYS error on both Linux and FreeBSD, or EINVAL
@@ -63,7 +63,7 @@
 	// because we have put fd.sysfd into non-blocking mode.
 	// However, a call to the File method will put it back into
 	// blocking mode. We can't take that risk, so no use of ForkLock here.
-	ns, sa, err = syscall.Accept(s)
+	ns, sa, err = acceptFunc(s)
 	if err == nil {
 		syscall.CloseOnExec(ns)
 	}
@@ -71,7 +71,7 @@
 		return -1, nil, err
 	}
 	if err = syscall.SetNonblock(ns, true); err != nil {
-		syscall.Close(ns)
+		closeFunc(ns)
 		return -1, nil, err
 	}
 	return ns, sa, nil
diff --git a/src/net/sock_posix.go b/src/net/sock_posix.go
index 3f956df..013944e 100644
--- a/src/net/sock_posix.go
+++ b/src/net/sock_posix.go
@@ -42,11 +42,11 @@
 		return nil, err
 	}
 	if err = setDefaultSockopts(s, family, sotype, ipv6only); err != nil {
-		closesocket(s)
+		closeFunc(s)
 		return nil, err
 	}
 	if fd, err = newFD(s, family, sotype, net); err != nil {
-		closesocket(s)
+		closeFunc(s)
 		return nil, err
 	}
 
diff --git a/src/net/sock_windows.go b/src/net/sock_windows.go
index 6ccde3a..591861f 100644
--- a/src/net/sock_windows.go
+++ b/src/net/sock_windows.go
@@ -12,10 +12,10 @@
 	return syscall.SOMAXCONN
 }
 
-func sysSocket(f, t, p int) (syscall.Handle, error) {
+func sysSocket(family, sotype, proto int) (syscall.Handle, error) {
 	// See ../syscall/exec_unix.go for description of ForkLock.
 	syscall.ForkLock.RLock()
-	s, err := syscall.Socket(f, t, p)
+	s, err := socketFunc(family, sotype, proto)
 	if err == nil {
 		syscall.CloseOnExec(s)
 	}
diff --git a/src/net/sys_cloexec.go b/src/net/sys_cloexec.go
index 898fb7c..5a631aa 100644
--- a/src/net/sys_cloexec.go
+++ b/src/net/sys_cloexec.go
@@ -16,7 +16,7 @@
 func sysSocket(family, sotype, proto int) (int, error) {
 	// See ../syscall/exec_unix.go for description of ForkLock.
 	syscall.ForkLock.RLock()
-	s, err := syscall.Socket(family, sotype, proto)
+	s, err := socketFunc(family, sotype, proto)
 	if err == nil {
 		syscall.CloseOnExec(s)
 	}
@@ -25,7 +25,7 @@
 		return -1, err
 	}
 	if err = syscall.SetNonblock(s, true); err != nil {
-		syscall.Close(s)
+		closeFunc(s)
 		return -1, err
 	}
 	return s, nil
@@ -39,7 +39,7 @@
 	// because we have put fd.sysfd into non-blocking mode.
 	// However, a call to the File method will put it back into
 	// blocking mode. We can't take that risk, so no use of ForkLock here.
-	ns, sa, err := syscall.Accept(s)
+	ns, sa, err := acceptFunc(s)
 	if err == nil {
 		syscall.CloseOnExec(ns)
 	}
@@ -47,7 +47,7 @@
 		return -1, nil, err
 	}
 	if err = syscall.SetNonblock(ns, true); err != nil {
-		syscall.Close(ns)
+		closeFunc(ns)
 		return -1, nil, err
 	}
 	return ns, sa, nil
diff --git a/src/net/tcp_test.go b/src/net/tcp_test.go
index 36d4445..434c9c6 100644
--- a/src/net/tcp_test.go
+++ b/src/net/tcp_test.go
@@ -59,6 +59,9 @@
 }
 
 func benchmarkTCP(b *testing.B, persistent, timeout bool, laddr string) {
+	uninstallTestHooks()
+	defer installTestHooks()
+
 	const msgLen = 512
 	conns := b.N
 	numConcurrent := runtime.GOMAXPROCS(-1) * 2
@@ -172,6 +175,8 @@
 	// The benchmark stresses concurrent reading and writing to the same connection.
 	// Such pattern is used in net/http and net/rpc.
 
+	uninstallTestHooks()
+	defer installTestHooks()
 	b.StopTimer()
 
 	P := runtime.GOMAXPROCS(0)
@@ -494,13 +499,11 @@
 
 func TestTCPReadWriteAllocs(t *testing.T) {
 	switch runtime.GOOS {
-	case "nacl", "windows", "darwin", "dragonfly":
+	case "nacl", "windows":
 		// NaCl needs to allocate pseudo file descriptor
 		// stuff. See syscall/fd_nacl.go.
 		// Windows uses closures and channels for IO
 		// completion port-based netpoll. See fd_windows.go.
-		// Darwin is unreliable for unknown reasons (issue 8859).
-		// Dragonfly also unreliable (lumped into issue 8859).
 		t.Skipf("not supported on %s", runtime.GOOS)
 	}
 
diff --git a/src/net/tcpsock.go b/src/net/tcpsock.go
index f3dfbd2..fbadad6 100644
--- a/src/net/tcpsock.go
+++ b/src/net/tcpsock.go
@@ -25,6 +25,13 @@
 	return JoinHostPort(ip, itoa(a.Port))
 }
 
+func (a *TCPAddr) isWildcard() bool {
+	if a == nil || a.IP == nil {
+		return true
+	}
+	return a.IP.IsUnspecified()
+}
+
 func (a *TCPAddr) toAddr() Addr {
 	if a == nil {
 		return nil
diff --git a/src/net/tcpsock_posix.go b/src/net/tcpsock_posix.go
index aaff0ac..024dcd4 100644
--- a/src/net/tcpsock_posix.go
+++ b/src/net/tcpsock_posix.go
@@ -38,13 +38,6 @@
 	return syscall.AF_INET6
 }
 
-func (a *TCPAddr) isWildcard() bool {
-	if a == nil || a.IP == nil {
-		return true
-	}
-	return a.IP.IsUnspecified()
-}
-
 func (a *TCPAddr) sockaddr(family int) (syscall.Sockaddr, error) {
 	if a == nil {
 		return nil, nil
diff --git a/src/net/udpsock.go b/src/net/udpsock.go
index 4c99ae4..532f7d5 100644
--- a/src/net/udpsock.go
+++ b/src/net/udpsock.go
@@ -25,6 +25,13 @@
 	return JoinHostPort(ip, itoa(a.Port))
 }
 
+func (a *UDPAddr) isWildcard() bool {
+	if a == nil || a.IP == nil {
+		return true
+	}
+	return a.IP.IsUnspecified()
+}
+
 func (a *UDPAddr) toAddr() Addr {
 	if a == nil {
 		return nil
diff --git a/src/net/udpsock_posix.go b/src/net/udpsock_posix.go
index 0770b7c..9733e7b 100644
--- a/src/net/udpsock_posix.go
+++ b/src/net/udpsock_posix.go
@@ -31,13 +31,6 @@
 	return syscall.AF_INET6
 }
 
-func (a *UDPAddr) isWildcard() bool {
-	if a == nil || a.IP == nil {
-		return true
-	}
-	return a.IP.IsUnspecified()
-}
-
 func (a *UDPAddr) sockaddr(family int) (syscall.Sockaddr, error) {
 	if a == nil {
 		return nil, nil
diff --git a/src/net/unix_test.go b/src/net/unix_test.go
index 1cdff39..85d1ff4 100644
--- a/src/net/unix_test.go
+++ b/src/net/unix_test.go
@@ -17,6 +17,10 @@
 )
 
 func TestReadUnixgramWithUnnamedSocket(t *testing.T) {
+	if !testableNetwork("unixgram") {
+		t.Skip("unixgram test")
+	}
+
 	addr := testUnixAddr()
 	la, err := ResolveUnixAddr("unixgram", addr)
 	if err != nil {
@@ -64,6 +68,9 @@
 }
 
 func TestReadUnixgramWithZeroBytesBuffer(t *testing.T) {
+	if !testableNetwork("unixgram") {
+		t.Skip("unixgram test")
+	}
 	// issue 4352: Recvfrom failed with "address family not
 	// supported by protocol family" if zero-length buffer provided
 
@@ -143,6 +150,7 @@
 	if runtime.GOOS != "linux" {
 		t.Skip("skipping: autobind is linux only")
 	}
+
 	laddr := &UnixAddr{Name: "", Net: "unix"}
 	ln, err := ListenUnix("unix", laddr)
 	if err != nil {
@@ -152,6 +160,10 @@
 }
 
 func TestUnixgramWrite(t *testing.T) {
+	if !testableNetwork("unixgram") {
+		t.Skip("unixgram test")
+	}
+
 	addr := testUnixAddr()
 	laddr, err := ResolveUnixAddr("unixgram", addr)
 	if err != nil {
@@ -219,6 +231,10 @@
 }
 
 func TestUnixConnLocalAndRemoteNames(t *testing.T) {
+	if !testableNetwork("unix") {
+		t.Skip("unix test")
+	}
+
 	for _, laddr := range []string{"", testUnixAddr()} {
 		laddr := laddr
 		taddr := testUnixAddr()
@@ -278,6 +294,10 @@
 }
 
 func TestUnixgramConnLocalAndRemoteNames(t *testing.T) {
+	if !testableNetwork("unixgram") {
+		t.Skip("unixgram test")
+	}
+
 	for _, laddr := range []string{"", testUnixAddr()} {
 		laddr := laddr
 		taddr := testUnixAddr()
diff --git a/src/net/url/url.go b/src/net/url/url.go
index f167408..0ad68cc 100644
--- a/src/net/url/url.go
+++ b/src/net/url/url.go
@@ -443,7 +443,7 @@
 // String reassembles the URL into a valid URL string.
 // The general form of the result is one of:
 //
-//	scheme:opaque
+//	scheme:opaque?query#fragment
 //	scheme://userinfo@host/path?query#fragment
 //
 // If u.Opaque is non-empty, String uses the first form;
@@ -639,7 +639,7 @@
 	return "/" + strings.TrimLeft(strings.Join(dst, "/"), "/")
 }
 
-// IsAbs returns true if the URL is absolute.
+// IsAbs reports whether the URL is absolute.
 func (u *URL) IsAbs() bool {
 	return u.Scheme != ""
 }
diff --git a/src/os/exec/exec.go b/src/os/exec/exec.go
index 72b4905..bb0c3ac 100644
--- a/src/os/exec/exec.go
+++ b/src/os/exec/exec.go
@@ -80,7 +80,7 @@
 	// new process. It does not include standard input, standard output, or
 	// standard error. If non-nil, entry i becomes file descriptor 3+i.
 	//
-	// BUG: on OS X 10.6, child processes may sometimes inherit unwanted fds.
+	// BUG(rsc): On OS X 10.6, child processes may sometimes inherit unwanted fds.
 	// http://golang.org/issue/2603
 	ExtraFiles []*os.File
 
diff --git a/src/os/exec/exec_test.go b/src/os/exec/exec_test.go
index ebaef99..d3dec57 100644
--- a/src/os/exec/exec_test.go
+++ b/src/os/exec/exec_test.go
@@ -251,6 +251,12 @@
 }
 
 func numOpenFDS(t *testing.T) (n int, lsof []byte) {
+	if runtime.GOOS == "android" {
+		// Android's stock lsof does not obey the -p option,
+		// so extra filtering is needed. (golang.org/issue/10206)
+		return numOpenFDsAndroid(t)
+	}
+
 	lsof, err := exec.Command("lsof", "-b", "-n", "-p", strconv.Itoa(os.Getpid())).Output()
 	if err != nil {
 		t.Skip("skipping test; error finding or running lsof")
@@ -258,6 +264,45 @@
 	return bytes.Count(lsof, []byte("\n")), lsof
 }
 
+func numOpenFDsAndroid(t *testing.T) (n int, lsof []byte) {
+	raw, err := exec.Command("lsof").Output()
+	if err != nil {
+		t.Skip("skipping test; error finding or running lsof")
+	}
+
+	// First find the PID column index by parsing the first line, and
+	// select lines containing pid in the column.
+	pid := []byte(strconv.Itoa(os.Getpid()))
+	pidCol := -1
+
+	s := bufio.NewScanner(bytes.NewReader(raw))
+	for s.Scan() {
+		line := s.Bytes()
+		fields := bytes.Fields(line)
+		if pidCol < 0 {
+			for i, v := range fields {
+				if bytes.Equal(v, []byte("PID")) {
+					pidCol = i
+					break
+				}
+			}
+			lsof = append(lsof, line...)
+			continue
+		}
+		if bytes.Equal(fields[pidCol], pid) {
+			lsof = append(lsof, '\n')
+			lsof = append(lsof, line...)
+		}
+	}
+	if pidCol < 0 {
+		t.Fatal("error processing lsof output: unexpected header format")
+	}
+	if err := s.Err(); err != nil {
+		t.Fatalf("error processing lsof output: %v", err)
+	}
+	return bytes.Count(lsof, []byte("\n")), lsof
+}
+
 var testedAlreadyLeaked = false
 
 // basefds returns the number of expected file descriptors
diff --git a/src/os/file.go b/src/os/file.go
index 79e8fc3..f332bc8 100644
--- a/src/os/file.go
+++ b/src/os/file.go
@@ -204,14 +204,15 @@
 func Mkdir(name string, perm FileMode) error {
 	e := syscall.Mkdir(name, syscallMode(perm))
 
-	// mkdir(2) itself won't handle the sticky bit on *BSD and Solaris
-	if !supportsCreateWithStickyBit && e == nil && perm&ModeSticky != 0 {
-		e = Chmod(name, perm)
-	}
-
 	if e != nil {
 		return &PathError{"mkdir", name, e}
 	}
+
+	// mkdir(2) itself won't handle the sticky bit on *BSD and Solaris
+	if !supportsCreateWithStickyBit && perm&ModeSticky != 0 {
+		Chmod(name, perm)
+	}
+
 	return nil
 }
 
diff --git a/src/os/file_darwin.go b/src/os/file_darwin.go
new file mode 100644
index 0000000..ee3a954
--- /dev/null
+++ b/src/os/file_darwin.go
@@ -0,0 +1,40 @@
+// Copyright 2015 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.
+
+// +build arm arm64
+
+package os
+
+/*
+#cgo CFLAGS: -x objective-c
+#cgo LDFLAGS: -framework CoreFoundation -framework Foundation
+
+#include <sys/param.h>
+#include <CoreFoundation/CFString.h>
+#include <Foundation/NSPathUtilities.h>
+
+char tmpdir[MAXPATHLEN];
+
+char* loadtmpdir() {
+	tmpdir[0] = 0;
+	CFStringRef path = (CFStringRef)NSTemporaryDirectory();
+	CFStringGetCString(path, tmpdir, sizeof(tmpdir), kCFStringEncodingUTF8);
+	return tmpdir;
+}
+*/
+import "C"
+
+func init() {
+	if Getenv("TMPDIR") != "" {
+		return
+	}
+	dir := C.GoString(C.loadtmpdir())
+	if len(dir) == 0 {
+		return
+	}
+	if dir[len(dir)-1] == '/' {
+		dir = dir[:len(dir)-1]
+	}
+	Setenv("TMPDIR", dir)
+}
diff --git a/src/os/file_unix.go b/src/os/file_unix.go
index fbe05c6..3fb70d6 100644
--- a/src/os/file_unix.go
+++ b/src/os/file_unix.go
@@ -88,8 +88,8 @@
 	}
 
 	// open(2) itself won't handle the sticky bit on *BSD and Solaris
-	if chmod && e == nil {
-		e = Chmod(name, perm)
+	if chmod {
+		Chmod(name, perm)
 	}
 
 	// There's a race here with fork/exec, which we are
diff --git a/src/os/os_test.go b/src/os/os_test.go
index 380e2b8..4ce6b7e 100644
--- a/src/os/os_test.go
+++ b/src/os/os_test.go
@@ -584,18 +584,18 @@
 func chtmpdir(t *testing.T) func() {
 	oldwd, err := Getwd()
 	if err != nil {
-		t.Fatal("chtmpdir: %v", err)
+		t.Fatalf("chtmpdir: %v", err)
 	}
 	d, err := ioutil.TempDir("", "test")
 	if err != nil {
-		t.Fatal("chtmpdir: %v", err)
+		t.Fatalf("chtmpdir: %v", err)
 	}
 	if err := Chdir(d); err != nil {
-		t.Fatal("chtmpdir: %v", err)
+		t.Fatalf("chtmpdir: %v", err)
 	}
 	return func() {
 		if err := Chdir(oldwd); err != nil {
-			t.Fatal("chtmpdir: %v", err)
+			t.Fatalf("chtmpdir: %v", err)
 		}
 		RemoveAll(d)
 	}
diff --git a/src/os/path_plan9.go b/src/os/path_plan9.go
index 64bad50..b09b53a 100644
--- a/src/os/path_plan9.go
+++ b/src/os/path_plan9.go
@@ -9,7 +9,7 @@
 	PathListSeparator = '\000' // OS-specific path list separator
 )
 
-// IsPathSeparator returns true if c is a directory separator character.
+// IsPathSeparator reports whether c is a directory separator character.
 func IsPathSeparator(c uint8) bool {
 	return PathSeparator == c
 }
diff --git a/src/os/path_test.go b/src/os/path_test.go
index 0aa327f..50d2c36 100644
--- a/src/os/path_test.go
+++ b/src/os/path_test.go
@@ -213,7 +213,7 @@
 		}
 	}
 	RemoveAll("/_go_os_test")
-	const dir = "/go_os_test/dir"
+	const dir = "/_go_os_test/dir"
 	err := MkdirAll(dir, 0777)
 	if err != nil {
 		pathErr, ok := err.(*PathError)
@@ -221,7 +221,7 @@
 		if ok && (pathErr.Err == syscall.EACCES || isReadonlyError(pathErr.Err)) {
 			t.Skipf("could not create %v: %v", dir, err)
 		}
-		t.Fatalf(`MkdirAll "/_go_os_test/dir": %v, %s, %d`, err, pathErr.Err, pathErr.Err)
+		t.Fatalf(`MkdirAll "/_go_os_test/dir": %v, %s`, err, pathErr.Err)
 	}
 	RemoveAll("/_go_os_test")
 }
diff --git a/src/os/path_unix.go b/src/os/path_unix.go
index 0211107..36f8e61 100644
--- a/src/os/path_unix.go
+++ b/src/os/path_unix.go
@@ -11,7 +11,7 @@
 	PathListSeparator = ':' // OS-specific path list separator
 )
 
-// IsPathSeparator returns true if c is a directory separator character.
+// IsPathSeparator reports whether c is a directory separator character.
 func IsPathSeparator(c uint8) bool {
 	return PathSeparator == c
 }
diff --git a/src/os/path_windows.go b/src/os/path_windows.go
index 61f2ca5..c96f137 100644
--- a/src/os/path_windows.go
+++ b/src/os/path_windows.go
@@ -9,7 +9,7 @@
 	PathListSeparator = ';'  // OS-specific path list separator
 )
 
-// IsPathSeparator returns true if c is a directory separator character.
+// IsPathSeparator reports whether c is a directory separator character.
 func IsPathSeparator(c uint8) bool {
 	// NOTE: Windows accept / as path separator.
 	return c == '\\' || c == '/'
diff --git a/src/os/proc.go b/src/os/proc.go
index 774f099..33a8b26 100644
--- a/src/os/proc.go
+++ b/src/os/proc.go
@@ -44,6 +44,14 @@
 
 // Exit causes the current program to exit with the given status code.
 // Conventionally, code zero indicates success, non-zero an error.
-// The program terminates immediately; deferred functions are
-// not run.
-func Exit(code int) { syscall.Exit(code) }
+// The program terminates immediately; deferred functions are not run.
+func Exit(code int) {
+	if code == 0 {
+		// Give race detector a chance to fail the program.
+		// Racy programs do not have the right to finish successfully.
+		runtime_beforeExit()
+	}
+	syscall.Exit(code)
+}
+
+func runtime_beforeExit() // implemented in runtime
diff --git a/src/os/signal/sig.s b/src/os/signal/sig.s
index f54e6ff..7fa6c92 100644
--- a/src/os/signal/sig.s
+++ b/src/os/signal/sig.s
@@ -4,7 +4,7 @@
 
 // Assembly to get into package runtime without using exported symbols.
 
-// +build amd64 amd64p32 arm 386 ppc64 ppc64le
+// +build amd64 amd64p32 arm arm64 386 ppc64 ppc64le
 
 #include "textflag.h"
 
diff --git a/src/os/signal/signal_windows_test.go b/src/os/signal/signal_windows_test.go
index f3e6706..45c86f0 100644
--- a/src/os/signal/signal_windows_test.go
+++ b/src/os/signal/signal_windows_test.go
@@ -10,6 +10,7 @@
 	"os"
 	"os/exec"
 	"path/filepath"
+	"runtime"
 	"syscall"
 	"testing"
 	"time"
@@ -31,6 +32,9 @@
 }
 
 func TestCtrlBreak(t *testing.T) {
+	if runtime.GOARCH == "386" {
+		t.Skip("known failing test on windows/386, see https://golang.org/issue/10215")
+	}
 	// create source file
 	const source = `
 package main
diff --git a/src/path/filepath/match.go b/src/path/filepath/match.go
index ecc07aa..89f16de 100644
--- a/src/path/filepath/match.go
+++ b/src/path/filepath/match.go
@@ -16,7 +16,7 @@
 // ErrBadPattern indicates a globbing pattern was malformed.
 var ErrBadPattern = errors.New("syntax error in pattern")
 
-// Match returns true if name matches the shell file name pattern.
+// Match reports whether name matches the shell file name pattern.
 // The pattern syntax is:
 //
 //	pattern:
@@ -301,7 +301,7 @@
 	return
 }
 
-// hasMeta returns true if path contains any of the magic characters
+// hasMeta reports whether path contains any of the magic characters
 // recognized by Match.
 func hasMeta(path string) bool {
 	// TODO(niemeyer): Should other magic characters be added here?
diff --git a/src/path/filepath/path.go b/src/path/filepath/path.go
index ebdd9f5..f9b041b 100644
--- a/src/path/filepath/path.go
+++ b/src/path/filepath/path.go
@@ -4,6 +4,9 @@
 
 // Package filepath implements utility routines for manipulating filename paths
 // in a way compatible with the target operating system-defined file paths.
+//
+// Functions in this package replace any occurrences of the slash ('/') character
+// with os.PathSeparator when returning paths unless otherwise specified.
 package filepath
 
 import (
@@ -174,7 +177,8 @@
 
 // SplitList splits a list of paths joined by the OS-specific ListSeparator,
 // usually found in PATH or GOPATH environment variables.
-// Unlike strings.Split, SplitList returns an empty slice when passed an empty string.
+// Unlike strings.Split, SplitList returns an empty slice when passed an empty
+// string. SplitList does not replace slash characters in the returned paths.
 func SplitList(path string) []string {
 	return splitList(path)
 }
diff --git a/src/path/filepath/path_plan9.go b/src/path/filepath/path_plan9.go
index da5f5fd..962774e 100644
--- a/src/path/filepath/path_plan9.go
+++ b/src/path/filepath/path_plan9.go
@@ -6,7 +6,7 @@
 
 import "strings"
 
-// IsAbs returns true if the path is absolute.
+// IsAbs reports whether the path is absolute.
 func IsAbs(path string) bool {
 	return strings.HasPrefix(path, "/") || strings.HasPrefix(path, "#")
 }
diff --git a/src/path/filepath/path_unix.go b/src/path/filepath/path_unix.go
index 008b76e..d241d78 100644
--- a/src/path/filepath/path_unix.go
+++ b/src/path/filepath/path_unix.go
@@ -8,7 +8,7 @@
 
 import "strings"
 
-// IsAbs returns true if the path is absolute.
+// IsAbs reports whether the path is absolute.
 func IsAbs(path string) bool {
 	return strings.HasPrefix(path, "/")
 }
diff --git a/src/path/filepath/path_windows.go b/src/path/filepath/path_windows.go
index d6ed3d1..bcfe0a3 100644
--- a/src/path/filepath/path_windows.go
+++ b/src/path/filepath/path_windows.go
@@ -13,7 +13,7 @@
 	return c == '\\' || c == '/'
 }
 
-// IsAbs returns true if the path is absolute.
+// IsAbs reports whether the path is absolute.
 func IsAbs(path string) (b bool) {
 	l := volumeNameLen(path)
 	if l == 0 {
@@ -141,7 +141,7 @@
 	return head + string(Separator) + tail
 }
 
-// isUNC returns true if path is a UNC path.
+// isUNC reports whether path is a UNC path.
 func isUNC(path string) bool {
 	return volumeNameLen(path) > 2
 }
diff --git a/src/path/match.go b/src/path/match.go
index 8154bf6..75dd3b3 100644
--- a/src/path/match.go
+++ b/src/path/match.go
@@ -13,7 +13,7 @@
 // ErrBadPattern indicates a globbing pattern was malformed.
 var ErrBadPattern = errors.New("syntax error in pattern")
 
-// Match returns true if name matches the shell file name pattern.
+// Match reports whether name matches the shell file name pattern.
 // The pattern syntax is:
 //
 //	pattern:
diff --git a/src/path/path.go b/src/path/path.go
index 98a6d52..3f0828c 100644
--- a/src/path/path.go
+++ b/src/path/path.go
@@ -192,7 +192,7 @@
 	return path
 }
 
-// IsAbs returns true if the path is absolute.
+// IsAbs reports whether the path is absolute.
 func IsAbs(path string) bool {
 	return len(path) > 0 && path[0] == '/'
 }
diff --git a/src/reflect/asm_arm64.s b/src/reflect/asm_arm64.s
new file mode 100644
index 0000000..a5a8b91
--- /dev/null
+++ b/src/reflect/asm_arm64.s
@@ -0,0 +1,30 @@
+// Copyright 2012 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.
+
+#include "textflag.h"
+#include "funcdata.h"
+
+// makeFuncStub is the code half of the function returned by MakeFunc.
+// See the comment on the declaration of makeFuncStub in makefunc.go
+// for more details.
+// No arg size here, runtime pulls arg map out of the func value.
+TEXT ·makeFuncStub(SB),(NOSPLIT|WRAPPER),$16
+	NO_LOCAL_POINTERS
+	MOVD	R26, 8(RSP)
+	MOVD	$argframe+0(FP), R3
+	MOVD	R3, 16(RSP)
+	BL	·callReflect(SB)
+	RET
+
+// methodValueCall is the code half of the function returned by makeMethodValue.
+// See the comment on the declaration of methodValueCall in makefunc.go
+// for more details.
+// No arg size here; runtime pulls arg map out of the func value.
+TEXT ·methodValueCall(SB),(NOSPLIT|WRAPPER),$16
+	NO_LOCAL_POINTERS
+	MOVD	R26, 8(RSP)
+	MOVD	$argframe+0(FP), R3
+	MOVD	R3, 16(RSP)
+	BL	·callMethod(SB)
+	RET
diff --git a/src/reflect/type.go b/src/reflect/type.go
index 1752ddd..ccd1454 100644
--- a/src/reflect/type.go
+++ b/src/reflect/type.go
@@ -87,16 +87,16 @@
 	// Kind returns the specific kind of this type.
 	Kind() Kind
 
-	// Implements returns true if the type implements the interface type u.
+	// Implements reports whether the type implements the interface type u.
 	Implements(u Type) bool
 
-	// AssignableTo returns true if a value of the type is assignable to type u.
+	// AssignableTo reports whether a value of the type is assignable to type u.
 	AssignableTo(u Type) bool
 
-	// ConvertibleTo returns true if a value of the type is convertible to type u.
+	// ConvertibleTo reports whether a value of the type is convertible to type u.
 	ConvertibleTo(u Type) bool
 
-	// Comparable returns true if values of this type are comparable.
+	// Comparable reports whether values of this type are comparable.
 	Comparable() bool
 
 	// Methods applicable only to some types, depending on Kind.
@@ -120,7 +120,7 @@
 	// It panics if the type's Kind is not Chan.
 	ChanDir() ChanDir
 
-	// IsVariadic returns true if a function type's final input parameter
+	// IsVariadic reports whether a function type's final input parameter
 	// is a "..." parameter.  If so, t.In(t.NumIn() - 1) returns the parameter's
 	// implicit actual type []T.
 	//
@@ -201,9 +201,9 @@
 // See golang.org/issue/4876 for more details.
 
 /*
- * These data structures are known to the compiler (../../cmd/gc/reflect.c).
+ * These data structures are known to the compiler (../../cmd/internal/gc/reflect.go).
  * A few are known to ../runtime/type.go to convey to debuggers.
- * They are also known to ../runtime/type.h.
+ * They are also known to ../runtime/type.go.
  */
 
 // A Kind represents the specific kind of type that a Type represents.
@@ -1122,7 +1122,7 @@
 	return t.alg != nil && t.alg.equal != nil
 }
 
-// implements returns true if the type V implements the interface type T.
+// implements reports whether the type V implements the interface type T.
 func implements(T, V *rtype) bool {
 	if T.Kind() != Interface {
 		return false
@@ -1143,7 +1143,7 @@
 	// methods along the way, or else V does not implement T.
 	// This lets us run the scan in overall linear time instead of
 	// the quadratic time  a naive search would require.
-	// See also ../runtime/iface.c.
+	// See also ../runtime/iface.go.
 	if V.Kind() == Interface {
 		v := (*interfaceType)(unsafe.Pointer(V))
 		i := 0
@@ -1176,7 +1176,7 @@
 	return false
 }
 
-// directlyAssignable returns true if a value x of type V can be directly
+// directlyAssignable reports whether a value x of type V can be directly
 // assigned (using memmove) to a value of type T.
 // http://golang.org/doc/go_spec.html#Assignability
 // Ignoring the interface rules (implemented elsewhere)
@@ -1637,13 +1637,10 @@
 	gc.size = align(gc.size, a)
 }
 
-// These constants must stay in sync with ../runtime/mgc0.h.
+// These constants must stay in sync with ../runtime/mbitmap.go.
 const (
 	bitsScalar  = 1
 	bitsPointer = 2
-
-	bitsIface = 2
-	bitsEface = 3
 )
 
 // Make sure these routines stay in sync with ../../runtime/hashmap.go!
diff --git a/src/reflect/value.go b/src/reflect/value.go
index ad48152..27f9c2d 100644
--- a/src/reflect/value.go
+++ b/src/reflect/value.go
@@ -176,7 +176,7 @@
 
 // nonEmptyInterface is the header for a interface value with methods.
 type nonEmptyInterface struct {
-	// see ../runtime/iface.c:/Itab
+	// see ../runtime/iface.go:/Itab
 	itab *struct {
 		ityp   *rtype // static interface type
 		typ    *rtype // dynamic concrete type
@@ -268,7 +268,7 @@
 	return *(*[]rune)(v.ptr)
 }
 
-// CanAddr returns true if the value's address can be obtained with Addr.
+// CanAddr reports whether the value's address can be obtained with Addr.
 // Such values are called addressable.  A value is addressable if it is
 // an element of a slice, an element of an addressable array,
 // a field of an addressable struct, or the result of dereferencing a pointer.
@@ -277,7 +277,7 @@
 	return v.flag&flagAddr != 0
 }
 
-// CanSet returns true if the value of v can be changed.
+// CanSet reports whether the value of v can be changed.
 // A Value can be changed only if it is addressable and was not
 // obtained by the use of unexported struct fields.
 // If CanSet returns false, calling Set or any type-specific
@@ -884,7 +884,7 @@
 	panic(&ValueError{"reflect.Value.Int", v.kind()})
 }
 
-// CanInterface returns true if Interface can be used without panicking.
+// CanInterface reports whether Interface can be used without panicking.
 func (v Value) CanInterface() bool {
 	if v.flag == 0 {
 		panic(&ValueError{"reflect.Value.CanInterface", Invalid})
@@ -971,7 +971,7 @@
 	panic(&ValueError{"reflect.Value.IsNil", v.kind()})
 }
 
-// IsValid returns true if v represents a value.
+// IsValid reports whether v represents a value.
 // It returns false if v is the zero Value.
 // If IsValid returns false, all other methods except String panic.
 // Most functions and methods never return an invalid value.
@@ -1148,7 +1148,7 @@
 	return len(tt.fields)
 }
 
-// OverflowComplex returns true if the complex128 x cannot be represented by v's type.
+// OverflowComplex reports whether the complex128 x cannot be represented by v's type.
 // It panics if v's Kind is not Complex64 or Complex128.
 func (v Value) OverflowComplex(x complex128) bool {
 	k := v.kind()
@@ -1161,7 +1161,7 @@
 	panic(&ValueError{"reflect.Value.OverflowComplex", v.kind()})
 }
 
-// OverflowFloat returns true if the float64 x cannot be represented by v's type.
+// OverflowFloat reports whether the float64 x cannot be represented by v's type.
 // It panics if v's Kind is not Float32 or Float64.
 func (v Value) OverflowFloat(x float64) bool {
 	k := v.kind()
@@ -1181,7 +1181,7 @@
 	return math.MaxFloat32 < x && x <= math.MaxFloat64
 }
 
-// OverflowInt returns true if the int64 x cannot be represented by v's type.
+// OverflowInt reports whether the int64 x cannot be represented by v's type.
 // It panics if v's Kind is not Int, Int8, int16, Int32, or Int64.
 func (v Value) OverflowInt(x int64) bool {
 	k := v.kind()
@@ -1194,7 +1194,7 @@
 	panic(&ValueError{"reflect.Value.OverflowInt", v.kind()})
 }
 
-// OverflowUint returns true if the uint64 x cannot be represented by v's type.
+// OverflowUint reports whether the uint64 x cannot be represented by v's type.
 // It panics if v's Kind is not Uint, Uintptr, Uint8, Uint16, Uint32, or Uint64.
 func (v Value) OverflowUint(x uint64) bool {
 	k := v.kind()
@@ -1647,7 +1647,7 @@
 
 // TrySend attempts to send x on the channel v but will not block.
 // It panics if v's Kind is not Chan.
-// It returns true if the value was sent, false otherwise.
+// It reports whether the value was sent.
 // As in Go, x's value must be assignable to the channel's element type.
 func (v Value) TrySend(x Value) bool {
 	v.mustBe(Chan)
diff --git a/src/regexp/backtrack.go b/src/regexp/backtrack.go
new file mode 100644
index 0000000..824014b
--- /dev/null
+++ b/src/regexp/backtrack.go
@@ -0,0 +1,351 @@
+// Copyright 2015 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.
+
+// backtrack is a regular expression search with submatch
+// tracking for small regular expressions and texts. It allocates
+// a bit vector with (length of input) * (length of prog) bits,
+// to make sure it never explores the same (character position, instruction)
+// state multiple times. This limits the search to run in time linear in
+// the length of the test.
+//
+// backtrack is a fast replacement for the NFA code on small
+// regexps when onepass cannot be used.
+
+package regexp
+
+import "regexp/syntax"
+
+// A job is an entry on the backtracker's job stack. It holds
+// the instruction pc and the position in the input.
+type job struct {
+	pc  uint32
+	arg int
+	pos int
+}
+
+const (
+	visitedBits        = 32
+	maxBacktrackProg   = 500        // len(prog.Inst) <= max
+	maxBacktrackVector = 256 * 1024 // bit vector size <= max (bits)
+)
+
+// bitState holds state for the backtracker.
+type bitState struct {
+	prog *syntax.Prog
+
+	end     int
+	cap     []int
+	reqcap  bool // whether any captures are requested
+	input   input
+	jobs    []job
+	visited []uint32
+}
+
+var notBacktrack *bitState = nil
+
+// maxBitStateLen returns the maximum length of a string to search with
+// the backtracker using prog.
+func maxBitStateLen(prog *syntax.Prog) int {
+	return maxBacktrackVector / len(prog.Inst)
+}
+
+// newBitState returns a new bitState for the given prog,
+// or notBacktrack if the size of the prog exceeds the maximum size that
+// the backtracker will be run for.
+func newBitState(prog *syntax.Prog) *bitState {
+	if len(prog.Inst) > maxBacktrackProg {
+		return notBacktrack
+	}
+	return &bitState{
+		prog: prog,
+	}
+}
+
+// reset resets the state of the backtracker.
+// end is the end position in the input. ncap and reqcap are the number
+// of the machine's capture registers and the number of user-requested
+// captures respectively.
+func (b *bitState) reset(end int, ncap int, reqcap int) {
+	b.end = end
+	b.reqcap = reqcap > 0
+
+	if cap(b.jobs) == 0 {
+		b.jobs = make([]job, 0, 256)
+	} else {
+		b.jobs = b.jobs[:0]
+	}
+
+	visitedSize := (len(b.prog.Inst)*(end+1) + visitedBits - 1) / visitedBits
+	if cap(b.visited) < visitedSize {
+		b.visited = make([]uint32, visitedSize, maxBacktrackVector/visitedBits)
+	} else {
+		b.visited = b.visited[:visitedSize]
+		for i := range b.visited {
+			b.visited[i] = 0
+		}
+	}
+
+	if len(b.cap) < ncap {
+		b.cap = make([]int, ncap)
+	}
+	for i := range b.cap {
+		b.cap[i] = -1
+	}
+}
+
+// shouldVisit reports whether the combination of (pc, pos) has not
+// been visited yet.
+func (b *bitState) shouldVisit(pc uint32, pos int) bool {
+	n := uint(int(pc)*(b.end+1) + pos)
+	if b.visited[n/visitedBits]&(1<<(n&(visitedBits-1))) != 0 {
+		return false
+	}
+	b.visited[n/visitedBits] |= 1 << (n & (visitedBits - 1))
+	return true
+}
+
+// push pushes (pc, pos, arg) onto the job stack if it should be
+// visited.
+func (b *bitState) push(pc uint32, pos int, arg int) {
+	if b.prog.Inst[pc].Op == syntax.InstFail {
+		return
+	}
+
+	// Only check shouldVisit when arg == 0.
+	// When arg > 0, we are continuing a previous visit.
+	if arg == 0 && !b.shouldVisit(pc, pos) {
+		return
+	}
+
+	b.jobs = append(b.jobs, job{pc: pc, arg: arg, pos: pos})
+}
+
+// tryBacktrack runs a backtracking search starting at pos.
+func (m *machine) tryBacktrack(b *bitState, i input, pc uint32, pos int) bool {
+	longest := m.re.longest
+	m.matched = false
+
+	b.push(pc, pos, 0)
+	for len(b.jobs) > 0 {
+		l := len(b.jobs) - 1
+		// Pop job off the stack.
+		pc := b.jobs[l].pc
+		pos := b.jobs[l].pos
+		arg := b.jobs[l].arg
+		b.jobs = b.jobs[:l]
+
+		// Optimization: rather than push and pop,
+		// code that is going to Push and continue
+		// the loop simply updates ip, p, and arg
+		// and jumps to CheckAndLoop.  We have to
+		// do the ShouldVisit check that Push
+		// would have, but we avoid the stack
+		// manipulation.
+		goto Skip
+	CheckAndLoop:
+		if !b.shouldVisit(pc, pos) {
+			continue
+		}
+	Skip:
+
+		inst := b.prog.Inst[pc]
+
+		switch inst.Op {
+		default:
+			panic("bad inst")
+		case syntax.InstFail:
+			panic("unexpected InstFail")
+		case syntax.InstAlt:
+			// Cannot just
+			//   b.push(inst.Out, pos, 0)
+			//   b.push(inst.Arg, pos, 0)
+			// If during the processing of inst.Out, we encounter
+			// inst.Arg via another path, we want to process it then.
+			// Pushing it here will inhibit that. Instead, re-push
+			// inst with arg==1 as a reminder to push inst.Arg out
+			// later.
+			switch arg {
+			case 0:
+				b.push(pc, pos, 1)
+				pc = inst.Out
+				goto CheckAndLoop
+			case 1:
+				// Finished inst.Out; try inst.Arg.
+				arg = 0
+				pc = inst.Arg
+				goto CheckAndLoop
+			}
+			panic("bad arg in InstAlt")
+
+		case syntax.InstAltMatch:
+			// One opcode consumes runes; the other leads to match.
+			switch b.prog.Inst[inst.Out].Op {
+			case syntax.InstRune, syntax.InstRune1, syntax.InstRuneAny, syntax.InstRuneAnyNotNL:
+				// inst.Arg is the match.
+				b.push(inst.Arg, pos, 0)
+				pc = inst.Arg
+				pos = b.end
+				goto CheckAndLoop
+			}
+			// inst.Out is the match - non-greedy
+			b.push(inst.Out, b.end, 0)
+			pc = inst.Out
+			goto CheckAndLoop
+
+		case syntax.InstRune:
+			r, width := i.step(pos)
+			if !inst.MatchRune(r) {
+				continue
+			}
+			pos += width
+			pc = inst.Out
+			goto CheckAndLoop
+
+		case syntax.InstRune1:
+			r, width := i.step(pos)
+			if r != inst.Rune[0] {
+				continue
+			}
+			pos += width
+			pc = inst.Out
+			goto CheckAndLoop
+
+		case syntax.InstRuneAnyNotNL:
+			r, width := i.step(pos)
+			if r == '\n' || r == endOfText {
+				continue
+			}
+			pos += width
+			pc = inst.Out
+			goto CheckAndLoop
+
+		case syntax.InstRuneAny:
+			r, width := i.step(pos)
+			if r == endOfText {
+				continue
+			}
+			pos += width
+			pc = inst.Out
+			goto CheckAndLoop
+
+		case syntax.InstCapture:
+			switch arg {
+			case 0:
+				if 0 <= inst.Arg && inst.Arg < uint32(len(b.cap)) {
+					// Capture pos to register, but save old value.
+					b.push(pc, b.cap[inst.Arg], 1) // come back when we're done.
+					b.cap[inst.Arg] = pos
+				}
+				pc = inst.Out
+				goto CheckAndLoop
+			case 1:
+				// Finished inst.Out; restore the old value.
+				b.cap[inst.Arg] = pos
+				continue
+
+			}
+			panic("bad arg in InstCapture")
+			continue
+
+		case syntax.InstEmptyWidth:
+			if syntax.EmptyOp(inst.Arg)&^i.context(pos) != 0 {
+				continue
+			}
+			pc = inst.Out
+			goto CheckAndLoop
+
+		case syntax.InstNop:
+			pc = inst.Out
+			goto CheckAndLoop
+
+		case syntax.InstMatch:
+			// We found a match. If the caller doesn't care
+			// where the match is, no point going further.
+			if !b.reqcap {
+				m.matched = true
+				return m.matched
+			}
+
+			// Record best match so far.
+			// Only need to check end point, because this entire
+			// call is only considering one start position.
+			b.cap[1] = pos
+			if !m.matched || (longest && pos > 0 && pos > m.matchcap[1]) {
+				copy(m.matchcap, b.cap)
+			}
+			m.matched = true
+
+			// If going for first match, we're done.
+			if !longest {
+				return m.matched
+			}
+
+			// If we used the entire text, no longer match is possible.
+			if pos == b.end {
+				return m.matched
+			}
+
+			// Otherwise, continue on in hope of a longer match.
+			continue
+		}
+		panic("unreachable")
+	}
+
+	return m.matched
+}
+
+// backtrack runs a backtracking search of prog on the input starting at pos.
+func (m *machine) backtrack(i input, pos int, end int, reqcap int) bool {
+	if !i.canCheckPrefix() {
+		panic("backtrack called for a RuneReader")
+	}
+
+	startCond := m.re.cond
+	if startCond == ^syntax.EmptyOp(0) { // impossible
+		return false
+	}
+	if startCond&syntax.EmptyBeginText != 0 && pos != 0 {
+		// Anchored match, past beginning of text.
+		return false
+	}
+
+	b := m.b
+	b.reset(end, len(m.matchcap), reqcap)
+
+	for i := range m.matchcap {
+		m.matchcap[i] = -1
+	}
+
+	// Anchored search must start at the beginning of the input
+	if startCond&syntax.EmptyBeginText != 0 {
+		b.cap[0] = pos
+		return m.tryBacktrack(b, i, uint32(m.p.Start), pos)
+	}
+
+	// Unanchored search, starting from each possible text position.
+	// Notice that we have to try the empty string at the end of
+	// the text, so the loop condition is pos <= end, not pos < end.
+	// This looks like it's quadratic in the size of the text,
+	// but we are not clearing visited between calls to TrySearch,
+	// so no work is duplicated and it ends up still being linear.
+	width := -1
+	for ; pos <= end && width != 0; pos += width {
+		if len(m.re.prefix) > 0 {
+			// Match requires literal prefix; fast search for it.
+			advance := i.index(m.re, pos)
+			if advance < 0 {
+				return false
+			}
+			pos += advance
+		}
+
+		b.cap[0] = pos
+		if m.tryBacktrack(b, i, uint32(m.p.Start), pos) {
+			// Match must be leftmost; done.
+			return true
+		}
+		_, width = i.step(pos)
+	}
+	return false
+}
diff --git a/src/regexp/exec.go b/src/regexp/exec.go
index c4cb201..5182720 100644
--- a/src/regexp/exec.go
+++ b/src/regexp/exec.go
@@ -35,13 +35,15 @@
 
 // A machine holds all the state during an NFA simulation for p.
 type machine struct {
-	re       *Regexp      // corresponding Regexp
-	p        *syntax.Prog // compiled program
-	op       *onePassProg // compiled onepass program, or notOnePass
-	q0, q1   queue        // two queues for runq, nextq
-	pool     []*thread    // pool of available threads
-	matched  bool         // whether a match was found
-	matchcap []int        // capture information for the match
+	re             *Regexp      // corresponding Regexp
+	p              *syntax.Prog // compiled program
+	op             *onePassProg // compiled onepass program, or notOnePass
+	maxBitStateLen int          // max length of string to search with bitstate
+	b              *bitState    // state for backtracker, allocated lazily
+	q0, q1         queue        // two queues for runq, nextq
+	pool           []*thread    // pool of available threads
+	matched        bool         // whether a match was found
+	matchcap       []int        // capture information for the match
 
 	// cached inputs, to avoid allocation
 	inputBytes  inputBytes
@@ -76,6 +78,9 @@
 	if ncap < 2 {
 		ncap = 2
 	}
+	if op == notOnePass {
+		m.maxBitStateLen = maxBitStateLen(p)
+	}
 	m.matchcap = make([]int, ncap)
 	return m
 }
@@ -422,18 +427,29 @@
 func (re *Regexp) doExecute(r io.RuneReader, b []byte, s string, pos int, ncap int) []int {
 	m := re.get()
 	var i input
+	var size int
 	if r != nil {
 		i = m.newInputReader(r)
 	} else if b != nil {
 		i = m.newInputBytes(b)
+		size = len(b)
 	} else {
 		i = m.newInputString(s)
+		size = len(s)
 	}
 	if m.op != notOnePass {
 		if !m.onepass(i, pos) {
 			re.put(m)
 			return nil
 		}
+	} else if size < m.maxBitStateLen && r == nil {
+		if m.b == nil {
+			m.b = newBitState(m.p)
+		}
+		if !m.backtrack(i, pos, size, ncap) {
+			re.put(m)
+			return nil
+		}
 	} else {
 		m.init(ncap)
 		if !m.match(i, pos) {
diff --git a/src/regexp/regexp.go b/src/regexp/regexp.go
index f20d109..70ba9d0 100644
--- a/src/regexp/regexp.go
+++ b/src/regexp/regexp.go
@@ -7,7 +7,7 @@
 // The syntax of the regular expressions accepted is the same
 // general syntax used by Perl, Python, and other languages.
 // More precisely, it is the syntax accepted by RE2 and described at
-// http://code.google.com/p/re2/wiki/Syntax, except for \C.
+// https://golang.org/s/re2syntax, except for \C.
 // For an overview of the syntax, run
 //   godoc regexp/syntax
 //
diff --git a/src/regexp/syntax/prog.go b/src/regexp/syntax/prog.go
index 29bd282..ae6db31 100644
--- a/src/regexp/syntax/prog.go
+++ b/src/regexp/syntax/prog.go
@@ -189,7 +189,7 @@
 
 const noMatch = -1
 
-// MatchRune returns true if the instruction matches (and consumes) r.
+// MatchRune reports whether the instruction matches (and consumes) r.
 // It should only be called when i.Op == InstRune.
 func (i *Inst) MatchRune(r rune) bool {
 	return i.MatchRunePos(r) != noMatch
@@ -256,7 +256,7 @@
 		('0' <= r && r <= '9')
 }
 
-// MatchEmptyWidth returns true if the instruction matches
+// MatchEmptyWidth reports whether the instruction matches
 // an empty string between the runes before and after.
 // It should only be called when i.Op == InstEmptyWidth.
 func (i *Inst) MatchEmptyWidth(before rune, after rune) bool {
diff --git a/src/run.bash b/src/run.bash
index 4177124..6fc864d 100755
--- a/src/run.bash
+++ b/src/run.bash
@@ -12,6 +12,9 @@
 unset GOPATH    # we disallow local import for non-local packages, if $GOROOT happens
                 # to be under $GOPATH, then some tests below will fail
 
+export GOHOSTOS
+export CC
+
 # no core files, please
 ulimit -c 0
 
@@ -32,225 +35,4 @@
 	[ "$(ulimit -H -T)" == "unlimited" ] || ulimit -S -T $(ulimit -H -T)
 fi
 
-# allow all.bash to avoid double-build of everything
-rebuild=true
-if [ "$1" == "--no-rebuild" ]; then
-	shift
-else
-	echo '##### Building packages and commands.'
-	time go install -a -v std cmd
-	echo
-fi
-
-# we must unset GOROOT_FINAL before tests, because runtime/debug requires
-# correct access to source code, so if we have GOROOT_FINAL in effect,
-# at least runtime/debug test will fail.
-unset GOROOT_FINAL
-
-# TODO(adg): create an environment variable and to permit the builders to
-# specify the timeout scale.
-timeout_scale=1
-# the freebsd-* builders are slow, and there's no easy way to make them faster.
-[ "$GOOS" == "freebsd" ] && timeout_scale=2
-# increase timeout for ARM up to 3 times the normal value
-[ "$GOARCH" == "arm" ] && timeout_scale=3
-
-echo '##### Testing packages.'
-time go test std cmd -short -timeout=$(expr 120 \* $timeout_scale)s -gcflags "$GO_GCFLAGS"
-echo
-
-# We set GOMAXPROCS=2 in addition to -cpu=1,2,4 in order to test runtime bootstrap code,
-# creation of first goroutines and first garbage collections in the parallel setting.
-echo '##### GOMAXPROCS=2 runtime -cpu=1,2,4'
-GOMAXPROCS=2 go test runtime -short -timeout=$(expr 300 \* $timeout_scale)s -cpu=1,2,4
-echo
-
-echo '##### sync -cpu=10'
-go test sync -short -timeout=$(expr 120 \* $timeout_scale)s -cpu=10
-
-xcd() {
-	echo
-	echo '#####' $1
-	builtin cd "$GOROOT"/src/$1 || exit 1
-}
-
-# NOTE: "set -e" cannot help us in subshells. It works until you test it with ||.
-#
-#	$ bash --version
-#	GNU bash, version 3.2.48(1)-release (x86_64-apple-darwin12)
-#	Copyright (C) 2007 Free Software Foundation, Inc.
-#
-#	$ set -e; (set -e; false; echo still here); echo subshell exit status $?
-#	subshell exit status 1
-#	# subshell stopped early, set exit status, but outer set -e didn't stop.
-#
-#	$ set -e; (set -e; false; echo still here) || echo stopped
-#	still here
-#	# somehow the '|| echo stopped' broke the inner set -e.
-#	
-# To avoid this bug, every command in a subshell should have '|| exit 1' on it.
-# Strictly speaking, the test may be unnecessary on the final command of
-# the subshell, but it aids later editing and may avoid future bash bugs.
-
-if [ "$GOOS" == "android" ]; then
-	# Disable cgo tests on android.
-	# They are not designed to run off the host.
-	# golang.org/issue/8345
-	CGO_ENABLED=0
-fi
-
-[ "$CGO_ENABLED" != 1 ] ||
-[ "$GOHOSTOS" == windows ] ||
-(xcd ../misc/cgo/stdio
-go run $GOROOT/test/run.go - . || exit 1
-) || exit $?
-
-[ "$CGO_ENABLED" != 1 ] ||
-(xcd ../misc/cgo/life
-go run $GOROOT/test/run.go - . || exit 1
-) || exit $?
-
-[ "$CGO_ENABLED" != 1 ] ||
-(xcd ../misc/cgo/test
-# cgo tests inspect the traceback for runtime functions
-extlink=0
-export GOTRACEBACK=2
-go test -ldflags '-linkmode=auto' || exit 1
-# linkmode=internal fails on dragonfly since errno is a TLS relocation.
-[ "$GOHOSTOS" == dragonfly ] || go test -ldflags '-linkmode=internal' || exit 1
-# TODO(austin): Add linux-ppc64(le) once external linking works (issue #8912)
-case "$GOHOSTOS-$GOARCH" in
-openbsd-386 | openbsd-amd64)
-	# test linkmode=external, but __thread not supported, so skip testtls.
-	go test -ldflags '-linkmode=external' || exit 1
-	extlink=1
-	;;
-darwin-386 | darwin-amd64)
-	# linkmode=external fails on OS X 10.6 and earlier == Darwin
-	# 10.8 and earlier.
-	case $(uname -r) in
-	[0-9].* | 10.*) ;;
-	*)
-		go test -ldflags '-linkmode=external'  || exit 1
-		extlink=1
-		;;
-	esac
-	;;
-android-arm | dragonfly-386 | dragonfly-amd64 | freebsd-386 | freebsd-amd64 | freebsd-arm | linux-386 | linux-amd64 | linux-arm | netbsd-386 | netbsd-amd64)
-	go test -ldflags '-linkmode=external' || exit 1
-	go test -ldflags '-linkmode=auto' ../testtls || exit 1
-	go test -ldflags '-linkmode=external' ../testtls || exit 1
-	extlink=1
-	
-	case "$GOHOSTOS-$GOARCH" in
-	netbsd-386 | netbsd-amd64) ;; # no static linking
-	freebsd-arm) ;; # -fPIC compiled tls code will use __tls_get_addr instead
-	                # of __aeabi_read_tp, however, on FreeBSD/ARM, __tls_get_addr
-	                # is implemented in rtld-elf, so -fPIC isn't compatible with
-	                # static linking on FreeBSD/ARM with clang. (cgo depends on
-			# -fPIC fundamentally.)
-	*)
-		if ! $CC -xc -o /dev/null -static - 2>/dev/null <<<'int main() {}' ; then
-			echo "No support for static linking found (lacks libc.a?), skip cgo static linking test."
-		else
-			go test -ldflags '-linkmode=external -extldflags "-static -pthread"' ../testtls || exit 1
-			go test ../nocgo || exit 1
-			go test -ldflags '-linkmode=external' ../nocgo || exit 1
-			go test -ldflags '-linkmode=external -extldflags "-static -pthread"' ../nocgo || exit 1
-		fi
-		;;
-	esac
-	;;
-esac
-) || exit $?
-
-# Race detector only supported on Linux, FreeBSD and OS X,
-# and only on amd64, and only when cgo is enabled.
-# Delayed until here so we know whether to try external linking.
-case "$GOHOSTOS-$GOOS-$GOARCH-$CGO_ENABLED" in
-linux-linux-amd64-1 | freebsd-freebsd-amd64-1 | darwin-darwin-amd64-1)
-	echo
-	echo '##### Testing race detector.'
-	go test -race -i runtime/race flag os/exec
-	go test -race -run=Output runtime/race
-	go test -race -short flag os/exec
-	
-	# Test with external linking; see issue 9133.
-	if [ "$extlink" = 1 ]; then
-		go test -race -short -ldflags=-linkmode=external flag os/exec
-	fi
-esac
-
-[ "$CGO_ENABLED" != 1 ] || [ "$GOOS" == darwin ] ||
-(xcd ../misc/cgo/testgodefs
-./test.bash || exit 1
-) || exit $?
-
-[ "$CGO_ENABLED" != 1 ] ||
-[ "$GOHOSTOS" == windows ] ||
-(xcd ../misc/cgo/testso
-./test.bash || exit 1
-) || exit $?
-
-[ "$CGO_ENABLED" != 1 ] ||
-[ "$GOHOSTOS-$GOARCH" != linux-amd64 ] ||
-(xcd ../misc/cgo/testasan
-go run main.go || exit 1
-) || exit $?
-
-[ "$CGO_ENABLED" != 1 ] ||
-[ "$GOHOSTOS" == windows ] ||
-(xcd ../misc/cgo/errors
-./test.bash || exit 1
-) || exit $?
-
-[ "$GOOS" == nacl ] ||
-[ "$GOOS" == android ] ||
-(xcd ../doc/progs
-time ./run || exit 1
-) || exit $?
-
-[ "$GOOS" == android ] ||
-[ "$GOOS" == nacl ] ||
-[ "$GOARCH" == arm ] ||  # uses network, fails under QEMU
-(xcd ../doc/articles/wiki
-./test.bash || exit 1
-) || exit $?
-
-[ "$GOOS" == android ] ||
-[ "$GOOS" == nacl ] ||
-(xcd ../doc/codewalk
-time ./run || exit 1
-) || exit $?
-
-[ "$GOOS" == nacl ] ||
-[ "$GOARCH" == arm ] ||
-(xcd ../test/bench/shootout
-time ./timing.sh -test || exit 1
-) || exit $?
-
-[ "$GOOS" == android ] || # TODO(crawshaw): get this working
-[ "$GOOS" == openbsd ] || # golang.org/issue/5057
-(
-echo
-echo '#####' ../test/bench/go1
-go test ../test/bench/go1 || exit 1
-) || exit $?
-
-[ "$GOOS" == android ] ||
-(xcd ../test
-unset GOMAXPROCS
-GOOS=$GOHOSTOS GOARCH=$GOHOSTARCH go build -o runtest run.go || exit 1
-time ./runtest || exit 1
-rm -f runtest
-) || exit $?
-
-[ "$GOOS" == android ] ||
-[ "$GOOS" == nacl ] ||
-(
-echo
-time go run $GOROOT/src/cmd/api/run.go || exit 1
-) || exit $?
-
-echo
-echo ALL TESTS PASSED
+exec go tool dist test $@
diff --git a/src/run.bat b/src/run.bat
index 57a8828..4957111 100644
--- a/src/run.bat
+++ b/src/run.bat
@@ -37,109 +37,10 @@
 del env.bat
 echo.
 
-echo ##### Testing packages.
-go test std cmd -short -timeout=240s
+go tool dist test --no-rebuild
 if errorlevel 1 goto fail
 echo.
 
-set OLDGOMAXPROCS=%GOMAXPROCS%
-
-:: We set GOMAXPROCS=2 in addition to -cpu=1,2,4 in order to test runtime bootstrap code,
-:: creation of first goroutines and first garbage collections in the parallel setting.
-echo ##### GOMAXPROCS=2 runtime -cpu=1,2,4
-set GOMAXPROCS=2
-go test runtime -short -timeout=600s -cpu=1,2,4
-if errorlevel 1 goto fail
-echo.
-
-set GOMAXPROCS=%OLDGOMAXPROCS%
-set OLDGOMAXPROCS=
-
-echo ##### sync -cpu=10
-go test sync -short -timeout=240s -cpu=10
-if errorlevel 1 goto fail
-echo.
-
-:: Race detector only supported on Linux and OS X,
-:: and only on amd64, and only when cgo is enabled.
-if not "%GOHOSTOS%-%GOOS%-%GOARCH%-%CGO_ENABLED%" == "windows-windows-amd64-1" goto norace
-echo ##### Testing race detector.
-go test -race -i runtime/race flag
-if errorlevel 1 goto fail
-go test -race -run=Output runtime/race
-if errorlevel 1 goto fail
-go test -race -short flag
-if errorlevel 1 goto fail
-echo.
-:norace
-
-echo ##### ..\test\bench\go1
-go test ..\test\bench\go1
-if errorlevel 1 goto fail
-echo.
-
-:: cgo tests
-if x%CGO_ENABLED% == x0 goto nocgo
-echo ##### ..\misc\cgo\life
-go run "%GOROOT%\test\run.go" - ..\misc\cgo\life
-if errorlevel 1 goto fail
-echo.
-
-echo ##### ..\misc\cgo\stdio
-go run "%GOROOT%\test\run.go" - ..\misc\cgo\stdio
-if errorlevel 1 goto fail
-echo.
-
-:: cgo tests inspect the traceback for runtime functions
-set OLDGOTRACEBACK=%GOTRACEBACK%
-set GOTRACEBACK=2
-
-echo ##### ..\misc\cgo\test
-go test ..\misc\cgo\test
-if errorlevel 1 goto fail
-echo.
-
-set GOTRACEBACK=%OLDGOTRACEBACK%
-set OLDGOTRACEBACK=
-
-echo ##### ..\misc\cgo\testso
-cd ..\misc\cgo\testso
-set FAIL=0
-call test.bat
-cd ..\..\..\src
-if %FAIL%==1 goto fail
-echo.
-:nocgo
-
-echo ##### ..\doc\progs
-go run "%GOROOT%\test\run.go" - ..\doc\progs
-if errorlevel 1 goto fail
-echo.
-
-:: TODO: The other tests in run.bash.
-
-
-set OLDGOMAXPROCS=%GOMAXPROCS%
-
-echo ##### ..\test
-cd ..\test
-set FAIL=0
-set GOMAXPROCS=
-go run run.go
-if errorlevel 1 set FAIL=1
-cd ..\src
-echo.
-if %FAIL%==1 goto fail
-
-set GOMAXPROCS=%OLDGOMAXPROCS%
-set OLDGOMAXPROCS=
-
-:: echo ##### Checking API compatibility.
-go run "%GOROOT%\src\cmd\api\run.go"
-if errorlevel 1 goto fail
-echo.
-
-echo ALL TESTS PASSED
 goto end
 
 :fail
diff --git a/src/run.rc b/src/run.rc
index c28ba34..d0ba866 100755
--- a/src/run.rc
+++ b/src/run.rc
@@ -10,60 +10,4 @@
 GOPATH = () # we disallow local import for non-local packages, if $GOROOT happens
             # to be under $GOPATH, then some tests below will fail
 
-# allow all.rc to avoid double-build of everything
-rebuild = true
-if(~ $1 --no-rebuild)
-	shift
-if not {
-	# Run only one process at a time on 9vx.
-	if(~ $sysname vx32)
-		pflag = (-p 1)
-	echo '# Building packages and commands.'
-	time go install -a -v $pflag std cmd
-	echo
-}
-
-# we must unset GOROOT_FINAL before tests, because runtime/debug requires
-# correct access to source code, so if we have GOROOT_FINAL in effect,
-# at least runtime/debug test will fail.
-GOROOT_FINAL = ()
-
-echo '# Testing packages.'
-time go test std cmd -short -timeout 120s
-echo
-
-# Temporary GCE builder hack until Plan 9 on GCE is fast enough.
-# See https://golang.org/issue/9491
-if(~ $GOTESTONLY std) {
-	echo
-	echo PARTIAL TESTS PASSED: std
-	exit
-}
-
-# We set GOMAXPROCS=2 in addition to -cpu=1,2,4 in order to test runtime bootstrap code,
-# creation of first goroutines and first garbage collections in the parallel setting.
-echo '# GOMAXPROCS=2 runtime -cpu=1,2,4'
-GOMAXPROCS=2 go test runtime -short -timeout 240s -cpu 1,2,4
-echo
-
-echo '# sync -cpu=10'
-go test sync -short -timeout 120s -cpu 10
-echo
-
-fn xcd {
-	echo
-	echo '#' $1
-	cd $"GOROOT/src/$1
-}
-
-echo
-echo '#' ../test/bench/go1
-go test ../test/bench/go1
-
-@{
-	xcd ../test
-	GOMAXPROCS='' time go run run.go -v
-}
-
-echo
-echo ALL TESTS PASSED
+exec go tool dist test $*
diff --git a/src/runtime/arch1_arm64.go b/src/runtime/arch1_arm64.go
new file mode 100644
index 0000000..49a56b6
--- /dev/null
+++ b/src/runtime/arch1_arm64.go
@@ -0,0 +1,16 @@
+// Copyright 2011 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 runtime
+
+const (
+	thechar           = '7'
+	_BigEndian        = 0
+	_CacheLineSize    = 32
+	_RuntimeGogoBytes = 64
+	_PhysPageSize     = 4096
+	_PCQuantum        = 4
+	_Int64Align       = 8
+	hugePageSize      = 0
+)
diff --git a/src/runtime/arch_arm64.go b/src/runtime/arch_arm64.go
new file mode 100644
index 0000000..270cd7b
--- /dev/null
+++ b/src/runtime/arch_arm64.go
@@ -0,0 +1,8 @@
+// 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.
+
+package runtime
+
+type uintreg uint64
+type intptr int64 // TODO(rsc): remove
diff --git a/src/runtime/asm_386.s b/src/runtime/asm_386.s
index 2b907d6..3472e07 100644
--- a/src/runtime/asm_386.s
+++ b/src/runtime/asm_386.s
@@ -114,7 +114,7 @@
 	CALL	runtime·schedinit(SB)
 
 	// create a new goroutine to start program
-	PUSHL	$runtime·main·f(SB)	// entry
+	PUSHL	$runtime·mainPC(SB)	// entry
 	PUSHL	$0	// arg size
 	CALL	runtime·newproc(SB)
 	POPL	AX
@@ -126,8 +126,8 @@
 	INT $3
 	RET
 
-DATA	runtime·main·f+0(SB)/4,$runtime·main(SB)
-GLOBL	runtime·main·f(SB),RODATA,$4
+DATA	runtime·mainPC+0(SB)/4,$runtime·main(SB)
+GLOBL	runtime·mainPC(SB),RODATA,$4
 
 TEXT runtime·breakpoint(SB),NOSPLIT,$0-0
 	INT $3
@@ -608,6 +608,14 @@
 	ORB	BX, (AX)
 	RET
 
+// void	runtime·atomicand8(byte volatile*, byte);
+TEXT runtime·atomicand8(SB), NOSPLIT, $0-5
+	MOVL	ptr+0(FP), AX
+	MOVB	val+4(FP), BX
+	LOCK
+	ANDB	BX, (AX)
+	RET
+
 // void jmpdefer(fn, sp);
 // called from deferreturn.
 // 1. pop the caller
@@ -1451,7 +1459,7 @@
 	MOVL	AX, ret+24(FP)
 	RET
 
-TEXT bytes·IndexByte(SB),NOSPLIT,$0
+TEXT bytes·IndexByte(SB),NOSPLIT,$0-20
 	MOVL	s+0(FP), SI
 	MOVL	s_len+4(FP), CX
 	MOVB	c+12(FP), AL
@@ -1465,7 +1473,7 @@
 	MOVL	DI, ret+16(FP)
 	RET
 
-TEXT strings·IndexByte(SB),NOSPLIT,$0
+TEXT strings·IndexByte(SB),NOSPLIT,$0-16
 	MOVL	s+0(FP), SI
 	MOVL	s_len+4(FP), CX
 	MOVB	c+8(FP), AL
diff --git a/src/runtime/asm_amd64.s b/src/runtime/asm_amd64.s
index 139b505..fdea053 100644
--- a/src/runtime/asm_amd64.s
+++ b/src/runtime/asm_amd64.s
@@ -109,7 +109,7 @@
 	CALL	runtime·schedinit(SB)
 
 	// create a new goroutine to start program
-	MOVQ	$runtime·main·f(SB), AX		// entry
+	MOVQ	$runtime·mainPC(SB), AX		// entry
 	PUSHQ	AX
 	PUSHQ	$0			// arg size
 	CALL	runtime·newproc(SB)
@@ -122,8 +122,8 @@
 	MOVL	$0xf1, 0xf1  // crash
 	RET
 
-DATA	runtime·main·f+0(SB)/8,$runtime·main(SB)
-GLOBL	runtime·main·f(SB),RODATA,$8
+DATA	runtime·mainPC+0(SB)/8,$runtime·main(SB)
+GLOBL	runtime·mainPC(SB),RODATA,$8
 
 TEXT runtime·breakpoint(SB),NOSPLIT,$0-0
 	BYTE	$0xcc
@@ -588,6 +588,14 @@
 	ORB	BX, (AX)
 	RET
 
+// void	runtime·atomicand8(byte volatile*, byte);
+TEXT runtime·atomicand8(SB), NOSPLIT, $0-9
+	MOVQ	ptr+0(FP), AX
+	MOVB	val+8(FP), BX
+	LOCK
+	ANDB	BX, (AX)
+	RET
+
 // void jmpdefer(fn, sp);
 // called from deferreturn.
 // 1. pop the caller
@@ -1509,7 +1517,7 @@
 	LEAQ	-1(CX)(AX*2), AX	// 1,0,-1 result
 	RET
 
-TEXT bytes·IndexByte(SB),NOSPLIT,$0
+TEXT bytes·IndexByte(SB),NOSPLIT,$0-40
 	MOVQ s+0(FP), SI
 	MOVQ s_len+8(FP), BX
 	MOVB c+24(FP), AL
@@ -1517,7 +1525,7 @@
 	MOVQ AX, ret+32(FP)
 	RET
 
-TEXT strings·IndexByte(SB),NOSPLIT,$0
+TEXT strings·IndexByte(SB),NOSPLIT,$0-32
 	MOVQ s+0(FP), SI
 	MOVQ s_len+8(FP), BX
 	MOVB c+16(FP), AL
diff --git a/src/runtime/asm_amd64p32.s b/src/runtime/asm_amd64p32.s
index 72dd9d7..e144c40 100644
--- a/src/runtime/asm_amd64p32.s
+++ b/src/runtime/asm_amd64p32.s
@@ -73,7 +73,7 @@
 	CALL	runtime·schedinit(SB)
 
 	// create a new goroutine to start program
-	MOVL	$runtime·main·f(SB), AX	// entry
+	MOVL	$runtime·mainPC(SB), AX	// entry
 	MOVL	$0, 0(SP)
 	MOVL	AX, 4(SP)
 	CALL	runtime·newproc(SB)
@@ -84,8 +84,8 @@
 	MOVL	$0xf1, 0xf1  // crash
 	RET
 
-DATA	runtime·main·f+0(SB)/4,$runtime·main(SB)
-GLOBL	runtime·main·f(SB),RODATA,$4
+DATA	runtime·mainPC+0(SB)/4,$runtime·main(SB)
+GLOBL	runtime·mainPC(SB),RODATA,$4
 
 TEXT runtime·breakpoint(SB),NOSPLIT,$0-0
 	INT $3
@@ -541,6 +541,14 @@
 	ORB	AX, 0(BX)
 	RET
 
+// void	runtime·atomicand8(byte volatile*, byte);
+TEXT runtime·atomicand8(SB), NOSPLIT, $0-5
+	MOVL	ptr+0(FP), BX
+	MOVB	val+4(FP), AX
+	LOCK
+	ANDB	AX, 0(BX)
+	RET
+
 // void jmpdefer(fn, sp);
 // called from deferreturn.
 // 1. pop the caller
@@ -822,7 +830,7 @@
 	MOVL	s2+12(FP), DI
 	MOVL	s2+16(FP), DX
 	CALL	runtime·cmpbody(SB)
-	MOVQ	AX, res+24(FP)
+	MOVL	AX, res+24(FP)
 	RET
 
 // input:
@@ -943,7 +951,7 @@
 	LEAQ	-1(CX)(AX*2), AX	// 1,0,-1 result
 	RET
 
-TEXT bytes·IndexByte(SB),NOSPLIT,$0
+TEXT bytes·IndexByte(SB),NOSPLIT,$0-20
 	MOVL s+0(FP), SI
 	MOVL s_len+4(FP), BX
 	MOVB c+12(FP), AL
@@ -951,7 +959,7 @@
 	MOVL AX, ret+16(FP)
 	RET
 
-TEXT strings·IndexByte(SB),NOSPLIT,$0
+TEXT strings·IndexByte(SB),NOSPLIT,$0-20
 	MOVL s+0(FP), SI
 	MOVL s_len+4(FP), BX
 	MOVB c+8(FP), AL
diff --git a/src/runtime/asm_arm.s b/src/runtime/asm_arm.s
index 21f1d45..a5f6bde 100644
--- a/src/runtime/asm_arm.s
+++ b/src/runtime/asm_arm.s
@@ -60,7 +60,7 @@
 	BL	runtime·schedinit(SB)
 
 	// create a new goroutine to start program
-	MOVW	$runtime·main·f(SB), R0
+	MOVW	$runtime·mainPC(SB), R0
 	MOVW.W	R0, -4(R13)
 	MOVW	$8, R0
 	MOVW.W	R0, -4(R13)
@@ -76,8 +76,8 @@
 	MOVW	$1000, R1
 	MOVW	R0, (R1)	// fail hard
 
-DATA	runtime·main·f+0(SB)/4,$runtime·main(SB)
-GLOBL	runtime·main·f(SB),RODATA,$4
+DATA	runtime·mainPC+0(SB)/4,$runtime·main(SB)
+GLOBL	runtime·mainPC(SB),RODATA,$4
 
 TEXT runtime·breakpoint(SB),NOSPLIT,$0-0
 	// gdb won't skip this breakpoint instruction automatically,
@@ -782,6 +782,57 @@
 	MOVB	R0, ret+8(FP)
 	RET
 
+TEXT runtime·cmpstring(SB),NOSPLIT,$0-20
+	MOVW	s1_base+0(FP), R2
+	MOVW	s1_len+4(FP), R0
+	MOVW	s2_base+8(FP), R3
+	MOVW	s2_len+12(FP), R1
+	BL	runtime·cmpbody(SB)
+	MOVW	R8, ret+16(FP)
+	RET
+
+TEXT bytes·Compare(SB),NOSPLIT,$0-28
+	MOVW	s1+0(FP), R2
+	MOVW	s1+4(FP), R0
+	MOVW	s2+12(FP), R3
+	MOVW	s2+16(FP), R1
+	BL	runtime·cmpbody(SB)
+	MOVW	R8, ret+24(FP)
+	RET
+
+// On entry:
+// R0 is the length of s1
+// R1 is the length of s2
+// R2 points to the start of s1
+// R3 points to the start of s2
+//
+// On exit:
+// R8 is -1/0/+1
+// R5, R4, and R6 are clobbered
+TEXT runtime·cmpbody(SB),NOSPLIT,$-4-0
+	CMP 	R0, R1
+	MOVW 	R0, R6
+	MOVW.LT	R1, R6	// R6 is min(R0, R1)
+
+	ADD	R2, R6	// R2 is current byte in s1, R6 is last byte in s1 to compare
+loop:
+	CMP	R2, R6
+	BEQ	samebytes // all compared bytes were the same; compare lengths
+	MOVBU.P	1(R2), R4
+	MOVBU.P	1(R3), R5
+	CMP	R4, R5
+	BEQ	loop
+	// bytes differed
+	MOVW.LT	$1, R8
+	MOVW.GT	$-1, R8
+	RET
+samebytes:
+	CMP	R0, R1
+	MOVW.LT	$1, R8
+	MOVW.GT	$-1, R8
+	MOVW.EQ	$0, R8
+	RET
+
 // eqstring tests whether two strings are equal.
 // The compiler guarantees that strings passed
 // to eqstring have equal length.
@@ -808,7 +859,7 @@
 	RET
 
 // TODO: share code with memeq?
-TEXT bytes·Equal(SB),NOSPLIT,$0
+TEXT bytes·Equal(SB),NOSPLIT,$0-25
 	MOVW	a_len+4(FP), R1
 	MOVW	b_len+16(FP), R3
 	
@@ -837,12 +888,12 @@
 	MOVBU	R0, ret+24(FP)
 	RET
 
-TEXT bytes·IndexByte(SB),NOSPLIT,$0
+TEXT bytes·IndexByte(SB),NOSPLIT,$0-20
 	MOVW	s+0(FP), R0
 	MOVW	s_len+4(FP), R1
 	MOVBU	c+12(FP), R2	// byte to find
 	MOVW	R0, R4		// store base for later
-	ADD	R0, R1		// end 
+	ADD	R0, R1		// end
 
 _loop:
 	CMP	R0, R1
@@ -853,7 +904,7 @@
 
 	SUB	$1, R0		// R0 will be one beyond the position we want
 	SUB	R4, R0		// remove base
-	MOVW    R0, ret+16(FP) 
+	MOVW    R0, ret+16(FP)
 	RET
 
 _notfound:
@@ -861,12 +912,12 @@
 	MOVW	R0, ret+16(FP)
 	RET
 
-TEXT strings·IndexByte(SB),NOSPLIT,$0
+TEXT strings·IndexByte(SB),NOSPLIT,$0-16
 	MOVW	s+0(FP), R0
 	MOVW	s_len+4(FP), R1
 	MOVBU	c+8(FP), R2	// byte to find
 	MOVW	R0, R4		// store base for later
-	ADD	R0, R1		// end 
+	ADD	R0, R1		// end
 
 _sib_loop:
 	CMP	R0, R1
@@ -877,7 +928,7 @@
 
 	SUB	$1, R0		// R0 will be one beyond the position we want
 	SUB	R4, R0		// remove base
-	MOVW	R0, ret+12(FP) 
+	MOVW	R0, ret+12(FP)
 	RET
 
 _sib_notfound:
diff --git a/src/runtime/asm_arm64.s b/src/runtime/asm_arm64.s
new file mode 100644
index 0000000..0068e84
--- /dev/null
+++ b/src/runtime/asm_arm64.s
@@ -0,0 +1,1061 @@
+// Copyright 2015 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.
+
+#include "go_asm.h"
+#include "go_tls.h"
+#include "funcdata.h"
+#include "textflag.h"
+
+TEXT runtime·rt0_go(SB),NOSPLIT,$0
+	// SP = stack; R0 = argc; R1 = argv
+
+	// initialize essential registers
+	BL	runtime·reginit(SB)
+
+	SUB	$32, RSP
+	MOVW	R0, 8(RSP) // argc
+	MOVD	R1, 16(RSP) // argv
+
+	// create istack out of the given (operating system) stack.
+	// _cgo_init may update stackguard.
+	MOVD	$runtime·g0(SB), g
+	MOVD RSP, R7
+	MOVD	$(-64*1024)(R7), R0
+	MOVD	R0, g_stackguard0(g)
+	MOVD	R0, g_stackguard1(g)
+	MOVD	R0, (g_stack+stack_lo)(g)
+	MOVD	R7, (g_stack+stack_hi)(g)
+
+	// if there is a _cgo_init, call it using the gcc ABI.
+	MOVD	_cgo_init(SB), R12
+	CMP	$0, R12
+	BEQ	nocgo
+
+	BL	runtime·abort(SB)
+
+nocgo:
+	// update stackguard after _cgo_init
+	MOVD	(g_stack+stack_lo)(g), R0
+	ADD	$const__StackGuard, R0
+	MOVD	R0, g_stackguard0(g)
+	MOVD	R0, g_stackguard1(g)
+
+	// set the per-goroutine and per-mach "registers"
+	MOVD	$runtime·m0(SB), R0
+
+	// save m->g0 = g0
+	MOVD	g, m_g0(R0)
+	// save m0 to g0->m
+	MOVD	R0, g_m(g)
+
+	BL	runtime·check(SB)
+
+	MOVW	8(RSP), R0	// copy argc
+	MOVW	R0, -8(RSP)
+	MOVD	16(RSP), R0		// copy argv
+	MOVD	R0, 0(RSP)
+	BL	runtime·args(SB)
+	BL	runtime·osinit(SB)
+	BL	runtime·schedinit(SB)
+
+	// create a new goroutine to start program
+	MOVD	$runtime·mainPC(SB), R0		// entry
+	MOVD	RSP, R7
+	MOVD.W	$0, -8(R7)
+	MOVD.W	R0, -8(R7)
+	MOVD.W	$0, -8(R7)
+	MOVD.W	$0, -8(R7)
+	MOVD	R7, RSP
+	BL	runtime·newproc(SB)
+	ADD	$32, RSP
+
+	// start this M
+	BL	runtime·mstart(SB)
+
+	MOVD	$0, R0
+	MOVD	R0, (R0)	// boom
+	UNDEF
+
+DATA	runtime·mainPC+0(SB)/8,$runtime·main(SB)
+GLOBL	runtime·mainPC(SB),RODATA,$8
+
+TEXT runtime·breakpoint(SB),NOSPLIT,$-8-0
+	BRK
+	RET
+
+TEXT runtime·asminit(SB),NOSPLIT,$-8-0
+	RET
+
+TEXT runtime·reginit(SB),NOSPLIT,$-8-0
+	// initialize essential FP registers
+	FMOVD	$4503601774854144.0, F27
+	FMOVD	$0.5, F29
+	FSUBD	F29, F29, F28
+	FADDD	F29, F29, F30
+	FADDD	F30, F30, F31
+	RET
+
+/*
+ *  go-routine
+ */
+
+// void gosave(Gobuf*)
+// save state in Gobuf; setjmp
+TEXT runtime·gosave(SB), NOSPLIT, $-8-8
+	MOVD	buf+0(FP), R3
+	MOVD	RSP, R0
+	MOVD	R0, gobuf_sp(R3)
+	MOVD	LR, gobuf_pc(R3)
+	MOVD	g, gobuf_g(R3)
+	MOVD	ZR, gobuf_lr(R3)
+	MOVD	ZR, gobuf_ret(R3)
+	MOVD	ZR, gobuf_ctxt(R3)
+	RET
+
+// void gogo(Gobuf*)
+// restore state from Gobuf; longjmp
+TEXT runtime·gogo(SB), NOSPLIT, $-8-8
+	MOVD	buf+0(FP), R5
+	MOVD	gobuf_g(R5), g
+	BL	runtime·save_g(SB)
+
+	MOVD	0(g), R4	// make sure g is not nil
+	MOVD	gobuf_sp(R5), R0
+	MOVD	R0, RSP
+	MOVD	gobuf_lr(R5), LR
+	MOVD	gobuf_ret(R5), R0
+	MOVD	gobuf_ctxt(R5), R26
+	MOVD	$0, gobuf_sp(R5)
+	MOVD	$0, gobuf_ret(R5)
+	MOVD	$0, gobuf_lr(R5)
+	MOVD	$0, gobuf_ctxt(R5)
+	CMP	ZR, ZR // set condition codes for == test, needed by stack split
+	MOVD	gobuf_pc(R5), R6
+	B	(R6)
+
+// void mcall(fn func(*g))
+// Switch to m->g0's stack, call fn(g).
+// Fn must never return.  It should gogo(&g->sched)
+// to keep running g.
+TEXT runtime·mcall(SB), NOSPLIT, $-8-8
+	// Save caller state in g->sched
+	MOVD	RSP, R0
+	MOVD	R0, (g_sched+gobuf_sp)(g)
+	MOVD	LR, (g_sched+gobuf_pc)(g)
+	MOVD	$0, (g_sched+gobuf_lr)(g)
+	MOVD	g, (g_sched+gobuf_g)(g)
+
+	// Switch to m->g0 & its stack, call fn.
+	MOVD	g, R3
+	MOVD	g_m(g), R8
+	MOVD	m_g0(R8), g
+	BL	runtime·save_g(SB)
+	CMP	g, R3
+	BNE	2(PC)
+	B	runtime·badmcall(SB)
+	MOVD	fn+0(FP), R26			// context
+	MOVD	0(R26), R4			// code pointer
+	MOVD	(g_sched+gobuf_sp)(g), R0
+	MOVD	R0, RSP	// sp = m->g0->sched.sp
+	MOVD	R3, -8(RSP)
+	MOVD	$0, -16(RSP)
+	SUB	$16, RSP
+	BL	(R4)
+	B	runtime·badmcall2(SB)
+
+// systemstack_switch is a dummy routine that systemstack leaves at the bottom
+// of the G stack.  We need to distinguish the routine that
+// lives at the bottom of the G stack from the one that lives
+// at the top of the system stack because the one at the top of
+// the system stack terminates the stack walk (see topofstack()).
+TEXT runtime·systemstack_switch(SB), NOSPLIT, $0-0
+	UNDEF
+	BL	(LR)	// make sure this function is not leaf
+	RET
+
+// func systemstack(fn func())
+TEXT runtime·systemstack(SB), NOSPLIT, $0-8
+	MOVD	fn+0(FP), R3	// R3 = fn
+	MOVD	R3, R26		// context
+	MOVD	g_m(g), R4	// R4 = m
+
+	MOVD	m_gsignal(R4), R5	// R5 = gsignal
+	CMP	g, R5
+	BEQ	noswitch
+
+	MOVD	m_g0(R4), R5	// R5 = g0
+	CMP	g, R5
+	BEQ	noswitch
+
+	MOVD	m_curg(R4), R6
+	CMP	g, R6
+	BEQ	switch
+
+	// Bad: g is not gsignal, not g0, not curg. What is it?
+	// Hide call from linker nosplit analysis.
+	MOVD	$runtime·badsystemstack(SB), R3
+	BL	(R3)
+
+switch:
+	// save our state in g->sched.  Pretend to
+	// be systemstack_switch if the G stack is scanned.
+	MOVD	$runtime·systemstack_switch(SB), R6
+	ADD	$8, R6	// get past prologue
+	MOVD	R6, (g_sched+gobuf_pc)(g)
+	MOVD	RSP, R0
+	MOVD	R0, (g_sched+gobuf_sp)(g)
+	MOVD	$0, (g_sched+gobuf_lr)(g)
+	MOVD	g, (g_sched+gobuf_g)(g)
+
+	// switch to g0
+	MOVD	R5, g
+	BL	runtime·save_g(SB)
+	MOVD	(g_sched+gobuf_sp)(g), R3
+	// make it look like mstart called systemstack on g0, to stop traceback
+	SUB	$16, R3
+	AND	$~15, R3
+	MOVD	$runtime·mstart(SB), R4
+	MOVD	R4, 0(R3)
+	MOVD	R3, RSP
+
+	// call target function
+	MOVD	0(R26), R3	// code pointer
+	BL	(R3)
+
+	// switch back to g
+	MOVD	g_m(g), R3
+	MOVD	m_curg(R3), g
+	BL	runtime·save_g(SB)
+	MOVD	(g_sched+gobuf_sp)(g), R0
+	MOVD	R0, RSP
+	MOVD	$0, (g_sched+gobuf_sp)(g)
+	RET
+
+noswitch:
+	// already on m stack, just call directly
+	MOVD	0(R26), R3	// code pointer
+	BL	(R3)
+	RET
+
+/*
+ * support for morestack
+ */
+
+// Called during function prolog when more stack is needed.
+// Caller has already loaded:
+// R3 prolog's LR (R30)
+//
+// The traceback routines see morestack on a g0 as being
+// the top of a stack (for example, morestack calling newstack
+// calling the scheduler calling newm calling gc), so we must
+// record an argument size. For that purpose, it has no arguments.
+TEXT runtime·morestack(SB),NOSPLIT,$-8-0
+	// Cannot grow scheduler stack (m->g0).
+	MOVD	g_m(g), R8
+	MOVD	m_g0(R8), R4
+	CMP	g, R4
+	BNE	2(PC)
+	B	runtime·abort(SB)
+
+	// Cannot grow signal stack (m->gsignal).
+	MOVD	m_gsignal(R8), R4
+	CMP	g, R4
+	BNE	2(PC)
+	B	runtime·abort(SB)
+
+	// Called from f.
+	// Set g->sched to context in f
+	MOVD	R26, (g_sched+gobuf_ctxt)(g)
+	MOVD	RSP, R0
+	MOVD	R0, (g_sched+gobuf_sp)(g)
+	MOVD	LR, (g_sched+gobuf_pc)(g)
+	MOVD	R3, (g_sched+gobuf_lr)(g)
+
+	// Called from f.
+	// Set m->morebuf to f's callers.
+	MOVD	R3, (m_morebuf+gobuf_pc)(R8)	// f's caller's PC
+	MOVD	RSP, R0
+	MOVD	R0, (m_morebuf+gobuf_sp)(R8)	// f's caller's RSP
+	MOVD	g, (m_morebuf+gobuf_g)(R8)
+
+	// Call newstack on m->g0's stack.
+	MOVD	m_g0(R8), g
+	BL	runtime·save_g(SB)
+	MOVD	(g_sched+gobuf_sp)(g), R0
+	MOVD	R0, RSP
+	BL	runtime·newstack(SB)
+
+	// Not reached, but make sure the return PC from the call to newstack
+	// is still in this function, and not the beginning of the next.
+	UNDEF
+
+TEXT runtime·morestack_noctxt(SB),NOSPLIT,$-4-0
+	MOVW	$0, R26
+	B runtime·morestack(SB)
+
+// reflectcall: call a function with the given argument list
+// func call(argtype *_type, f *FuncVal, arg *byte, argsize, retoffset uint32).
+// we don't have variable-sized frames, so we use a small number
+// of constant-sized-frame functions to encode a few bits of size in the pc.
+// Caution: ugly multiline assembly macros in your future!
+
+#define DISPATCH(NAME,MAXSIZE)		\
+	MOVD	$MAXSIZE, R27;		\
+	CMP	R27, R16;		\
+	BGT	3(PC);			\
+	MOVD	$NAME(SB), R27;	\
+	B	(R27)
+// Note: can't just "B NAME(SB)" - bad inlining results.
+
+TEXT reflect·call(SB), NOSPLIT, $0-0
+	B	·reflectcall(SB)
+
+TEXT ·reflectcall(SB), NOSPLIT, $-8-32
+	MOVWU argsize+24(FP), R16
+	// NOTE(rsc): No call16, because CALLFN needs four words
+	// of argument space to invoke callwritebarrier.
+	DISPATCH(runtime·call32, 32)
+	DISPATCH(runtime·call64, 64)
+	DISPATCH(runtime·call128, 128)
+	DISPATCH(runtime·call256, 256)
+	DISPATCH(runtime·call512, 512)
+	DISPATCH(runtime·call1024, 1024)
+	DISPATCH(runtime·call2048, 2048)
+	DISPATCH(runtime·call4096, 4096)
+	DISPATCH(runtime·call8192, 8192)
+	DISPATCH(runtime·call16384, 16384)
+	DISPATCH(runtime·call32768, 32768)
+	DISPATCH(runtime·call65536, 65536)
+	DISPATCH(runtime·call131072, 131072)
+	DISPATCH(runtime·call262144, 262144)
+	DISPATCH(runtime·call524288, 524288)
+	DISPATCH(runtime·call1048576, 1048576)
+	DISPATCH(runtime·call2097152, 2097152)
+	DISPATCH(runtime·call4194304, 4194304)
+	DISPATCH(runtime·call8388608, 8388608)
+	DISPATCH(runtime·call16777216, 16777216)
+	DISPATCH(runtime·call33554432, 33554432)
+	DISPATCH(runtime·call67108864, 67108864)
+	DISPATCH(runtime·call134217728, 134217728)
+	DISPATCH(runtime·call268435456, 268435456)
+	DISPATCH(runtime·call536870912, 536870912)
+	DISPATCH(runtime·call1073741824, 1073741824)
+	MOVD	$runtime·badreflectcall(SB), R0
+	B	(R0)
+
+#define CALLFN(NAME,MAXSIZE)			\
+TEXT NAME(SB), WRAPPER, $MAXSIZE-24;		\
+	NO_LOCAL_POINTERS;			\
+	/* copy arguments to stack */		\
+	MOVD	arg+16(FP), R3;			\
+	MOVWU	argsize+24(FP), R4;			\
+	MOVD	RSP, R5;				\
+	ADD	$(8-1), R5;			\
+	SUB	$1, R3;				\
+	ADD	R5, R4;				\
+	CMP	R5, R4;				\
+	BEQ	4(PC);				\
+	MOVBU.W	1(R3), R6;			\
+	MOVBU.W	R6, 1(R5);			\
+	B	-4(PC);				\
+	/* call function */			\
+	MOVD	f+8(FP), R26;			\
+	MOVD	(R26), R0;			\
+	PCDATA  $PCDATA_StackMapIndex, $0;	\
+	BL	(R0);				\
+	/* copy return values back */		\
+	MOVD	arg+16(FP), R3;			\
+	MOVWU	n+24(FP), R4;			\
+	MOVWU	retoffset+28(FP), R6;		\
+	MOVD	RSP, R5;				\
+	ADD	R6, R5; 			\
+	ADD	R6, R3;				\
+	SUB	R6, R4;				\
+	ADD	$(8-1), R5;			\
+	SUB	$1, R3;				\
+	ADD	R5, R4;				\
+loop:						\
+	CMP	R5, R4;				\
+	BEQ	end;				\
+	MOVBU.W	1(R5), R6;			\
+	MOVBU.W	R6, 1(R3);			\
+	B	loop;				\
+end:						\
+	/* execute write barrier updates */	\
+	MOVD	argtype+0(FP), R7;		\
+	MOVD	arg+16(FP), R3;			\
+	MOVWU	n+24(FP), R4;			\
+	MOVWU	retoffset+28(FP), R6;		\
+	MOVD	R7, 8(RSP);			\
+	MOVD	R3, 16(RSP);			\
+	MOVD	R4, 24(RSP);			\
+	MOVD	R6, 32(RSP);			\
+	BL	runtime·callwritebarrier(SB);	\
+	RET
+
+CALLFN(·call16, 16)
+CALLFN(·call32, 32)
+CALLFN(·call64, 64)
+CALLFN(·call128, 128)
+CALLFN(·call256, 256)
+CALLFN(·call512, 512)
+CALLFN(·call1024, 1024)
+CALLFN(·call2048, 2048)
+CALLFN(·call4096, 4096)
+CALLFN(·call8192, 8192)
+CALLFN(·call16384, 16384)
+CALLFN(·call32768, 32768)
+CALLFN(·call65536, 65536)
+CALLFN(·call131072, 131072)
+CALLFN(·call262144, 262144)
+CALLFN(·call524288, 524288)
+CALLFN(·call1048576, 1048576)
+CALLFN(·call2097152, 2097152)
+CALLFN(·call4194304, 4194304)
+CALLFN(·call8388608, 8388608)
+CALLFN(·call16777216, 16777216)
+CALLFN(·call33554432, 33554432)
+CALLFN(·call67108864, 67108864)
+CALLFN(·call134217728, 134217728)
+CALLFN(·call268435456, 268435456)
+CALLFN(·call536870912, 536870912)
+CALLFN(·call1073741824, 1073741824)
+
+// bool cas(uint32 *ptr, uint32 old, uint32 new)
+// Atomically:
+//	if(*val == old){
+//		*val = new;
+//		return 1;
+//	} else
+//		return 0;
+TEXT runtime·cas(SB), NOSPLIT, $0-17
+	MOVD	ptr+0(FP), R0
+	MOVW	old+8(FP), R1
+	MOVW	new+12(FP), R2
+again:
+	LDAXRW	(R0), R3
+	CMPW	R1, R3
+	BNE	ok
+	STLXRW	R2, (R0), R3
+	CBNZ	R3, again
+ok:
+	CSET	EQ, R0
+	MOVB	R0, ret+16(FP)
+	RET
+
+TEXT runtime·casuintptr(SB), NOSPLIT, $0-25
+	B	runtime·cas64(SB)
+
+TEXT runtime·atomicloaduintptr(SB), NOSPLIT, $-8-16
+	B	runtime·atomicload64(SB)
+
+TEXT runtime·atomicloaduint(SB), NOSPLIT, $-8-16
+	B	runtime·atomicload64(SB)
+
+TEXT runtime·atomicstoreuintptr(SB), NOSPLIT, $0-16
+	B	runtime·atomicstore64(SB)
+
+// bool casp(void **val, void *old, void *new)
+// Atomically:
+//	if(*val == old){
+//		*val = new;
+//		return 1;
+//	} else
+//		return 0;
+TEXT runtime·casp1(SB), NOSPLIT, $0-25
+	B runtime·cas64(SB)
+
+TEXT runtime·procyield(SB),NOSPLIT,$0-0
+	MOVWU	cycles+0(FP), R0
+again:
+	YIELD
+	SUBW	$1, R0
+	CBNZ	R0, again
+	RET
+
+// void jmpdefer(fv, sp);
+// called from deferreturn.
+// 1. grab stored LR for caller
+// 2. sub 4 bytes to get back to BL deferreturn
+// 3. BR to fn
+TEXT runtime·jmpdefer(SB), NOSPLIT, $-8-16
+	MOVD	0(RSP), R0
+	SUB	$4, R0
+	MOVD	R0, LR
+
+	MOVD	fv+0(FP), R26
+	MOVD	argp+8(FP), R0
+	MOVD	R0, RSP
+	SUB	$8, RSP
+	MOVD	0(R26), R3
+	B	(R3)
+
+// Save state of caller into g->sched. Smashes R0.
+TEXT gosave<>(SB),NOSPLIT,$-8
+	MOVD	LR, (g_sched+gobuf_pc)(g)
+	MOVD RSP, R0
+	MOVD	R0, (g_sched+gobuf_sp)(g)
+	MOVD	$0, (g_sched+gobuf_lr)(g)
+	MOVD	$0, (g_sched+gobuf_ret)(g)
+	MOVD	$0, (g_sched+gobuf_ctxt)(g)
+	RET
+
+// asmcgocall(void(*fn)(void*), void *arg)
+// Call fn(arg) on the scheduler stack,
+// aligned appropriately for the gcc ABI.
+// See cgocall.c for more details.
+TEXT ·asmcgocall(SB),NOSPLIT,$0-16
+	MOVD	fn+0(FP), R3
+	MOVD	arg+8(FP), R4
+	BL	asmcgocall<>(SB)
+	RET
+
+TEXT ·asmcgocall_errno(SB),NOSPLIT,$0-20
+	MOVD	fn+0(FP), R3
+	MOVD	arg+8(FP), R4
+	BL	asmcgocall<>(SB)
+	MOVW	R0, ret+16(FP)
+	RET
+
+// asmcgocall common code. fn in R3, arg in R4. returns errno in R0.
+TEXT asmcgocall<>(SB),NOSPLIT,$0-0
+	MOVD	RSP, R2		// save original stack pointer
+	MOVD	g, R5
+
+	// Figure out if we need to switch to m->g0 stack.
+	// We get called to create new OS threads too, and those
+	// come in on the m->g0 stack already.
+	MOVD	g_m(g), R6
+	MOVD	m_g0(R6), R6
+	CMP	R6, g
+	BEQ	g0
+	BL	gosave<>(SB)
+	MOVD	R6, g
+	BL	runtime·save_g(SB)
+	MOVD	(g_sched+gobuf_sp)(g), R13
+	MOVD	R13, RSP
+
+	// Now on a scheduling stack (a pthread-created stack).
+g0:
+	// Save room for two of our pointers, plus 32 bytes of callee
+	// save area that lives on the caller stack.
+	MOVD	RSP, R13
+	SUB	$48, R13
+	AND	$~15, R13	// 16-byte alignment for gcc ABI
+	MOVD	R13, RSP
+	MOVD	R5, 40(RSP)	// save old g on stack
+	MOVD	(g_stack+stack_hi)(R5), R5
+	SUB	R2, R5
+	MOVD	R5, 32(RSP)	// save depth in old g stack (can't just save RSP, as stack might be copied during a callback)
+	MOVD	R0, 0(RSP)	// clear back chain pointer (TODO can we give it real back trace information?)
+	// This is a "global call", so put the global entry point in r12
+	MOVD	R3, R12
+	MOVD	R4, R0
+	BL	(R12)
+
+	// Restore g, stack pointer.  R0 is errno, so don't touch it
+	MOVD	40(RSP), g
+	BL	runtime·save_g(SB)
+	MOVD	(g_stack+stack_hi)(g), R5
+	MOVD	32(RSP), R6
+	SUB	R6, R5
+	MOVD	R5, RSP
+	RET
+
+// cgocallback(void (*fn)(void*), void *frame, uintptr framesize)
+// Turn the fn into a Go func (by taking its address) and call
+// cgocallback_gofunc.
+TEXT runtime·cgocallback(SB),NOSPLIT,$24-24
+	MOVD	$fn+0(FP), R3
+	MOVD	R3, 8(RSP)
+	MOVD	frame+8(FP), R3
+	MOVD	R3, 16(RSP)
+	MOVD	framesize+16(FP), R3
+	MOVD	R3, 24(RSP)
+	MOVD	$runtime·cgocallback_gofunc(SB), R3
+	BL	(R3)
+	RET
+
+// cgocallback_gofunc(FuncVal*, void *frame, uintptr framesize)
+// See cgocall.c for more details.
+TEXT ·cgocallback_gofunc(SB),NOSPLIT,$16-24
+	NO_LOCAL_POINTERS
+
+	// Load m and g from thread-local storage.
+	MOVB	runtime·iscgo(SB), R3
+	CMP	$0, R3 
+	BEQ	nocgo
+	// TODO(aram):
+	BL runtime·abort(SB)
+nocgo:
+
+	// If g is nil, Go did not create the current thread.
+	// Call needm to obtain one for temporary use.
+	// In this case, we're running on the thread stack, so there's
+	// lots of space, but the linker doesn't know. Hide the call from
+	// the linker analysis by using an indirect call.
+	CMP	$0, g
+	BNE	havem
+	MOVD	g, savedm-8(SP) // g is zero, so is m.
+	MOVD	$runtime·needm(SB), R3
+	BL	(R3)
+
+	// Set m->sched.sp = SP, so that if a panic happens
+	// during the function we are about to execute, it will
+	// have a valid SP to run on the g0 stack.
+	// The next few lines (after the havem label)
+	// will save this SP onto the stack and then write
+	// the same SP back to m->sched.sp. That seems redundant,
+	// but if an unrecovered panic happens, unwindm will
+	// restore the g->sched.sp from the stack location
+	// and then systemstack will try to use it. If we don't set it here,
+	// that restored SP will be uninitialized (typically 0) and
+	// will not be usable.
+	MOVD	g_m(g), R3
+	MOVD	m_g0(R3), R3
+	MOVD	RSP, R0
+	MOVD	R0, (g_sched+gobuf_sp)(R3)
+
+havem:
+	MOVD	g_m(g), R8
+	MOVD	R8, savedm-8(SP)
+	// Now there's a valid m, and we're running on its m->g0.
+	// Save current m->g0->sched.sp on stack and then set it to SP.
+	// Save current sp in m->g0->sched.sp in preparation for
+	// switch back to m->curg stack.
+	// NOTE: unwindm knows that the saved g->sched.sp is at 8(R1) aka savedsp-16(SP).
+	MOVD	m_g0(R8), R3
+	MOVD	(g_sched+gobuf_sp)(R3), R4
+	MOVD	R4, savedsp-16(SP)
+	MOVD	RSP, R0
+	MOVD	R0, (g_sched+gobuf_sp)(R3)
+
+	// Switch to m->curg stack and call runtime.cgocallbackg.
+	// Because we are taking over the execution of m->curg
+	// but *not* resuming what had been running, we need to
+	// save that information (m->curg->sched) so we can restore it.
+	// We can restore m->curg->sched.sp easily, because calling
+	// runtime.cgocallbackg leaves SP unchanged upon return.
+	// To save m->curg->sched.pc, we push it onto the stack.
+	// This has the added benefit that it looks to the traceback
+	// routine like cgocallbackg is going to return to that
+	// PC (because the frame we allocate below has the same
+	// size as cgocallback_gofunc's frame declared above)
+	// so that the traceback will seamlessly trace back into
+	// the earlier calls.
+	//
+	// In the new goroutine, -16(SP) and -8(SP) are unused.
+	MOVD	m_curg(R8), g
+	BL	runtime·save_g(SB)
+	MOVD	(g_sched+gobuf_sp)(g), R4 // prepare stack as R4
+	MOVD	(g_sched+gobuf_pc)(g), R5
+	MOVD	R5, -24(R4)
+	MOVD	$-24(R4), R0
+	MOVD	R0, RSP
+	BL	runtime·cgocallbackg(SB)
+
+	// Restore g->sched (== m->curg->sched) from saved values.
+	MOVD	0(RSP), R5
+	MOVD	R5, (g_sched+gobuf_pc)(g)
+	MOVD	$24(RSP), R4
+	MOVD	R4, (g_sched+gobuf_sp)(g)
+
+	// Switch back to m->g0's stack and restore m->g0->sched.sp.
+	// (Unlike m->curg, the g0 goroutine never uses sched.pc,
+	// so we do not have to restore it.)
+	MOVD	g_m(g), R8
+	MOVD	m_g0(R8), g
+	BL	runtime·save_g(SB)
+	MOVD	(g_sched+gobuf_sp)(g), R0
+	MOVD	R0, RSP
+	MOVD	savedsp-16(SP), R4
+	MOVD	R4, (g_sched+gobuf_sp)(g)
+
+	// If the m on entry was nil, we called needm above to borrow an m
+	// for the duration of the call. Since the call is over, return it with dropm.
+	MOVD	savedm-8(SP), R6
+	CMP	$0, R6
+	BNE	droppedm
+	MOVD	$runtime·dropm(SB), R3
+	BL	(R3)
+droppedm:
+
+	// Done!
+	RET
+
+// void setg(G*); set g. for use by needm.
+TEXT runtime·setg(SB), NOSPLIT, $0-8
+	MOVD	gg+0(FP), g
+	// This only happens if iscgo, so jump straight to save_g
+	BL	runtime·save_g(SB)
+	RET
+
+// save_g saves the g register into pthread-provided
+// thread-local memory, so that we can call externally compiled
+// ppc64 code that will overwrite this register.
+//
+// If !iscgo, this is a no-op.
+TEXT runtime·save_g(SB),NOSPLIT,$-8-0
+	MOVB	runtime·iscgo(SB), R0
+	CMP	$0, R0
+	BEQ	nocgo
+
+	// TODO: implement cgo.
+	BL	runtime·abort(SB)
+
+nocgo:
+	RET
+
+
+TEXT runtime·getcallerpc(SB),NOSPLIT,$-8-16
+	MOVD	0(RSP), R0
+	MOVD	R0, ret+8(FP)
+	RET
+
+TEXT runtime·setcallerpc(SB),NOSPLIT,$-8-16
+	MOVD	pc+8(FP), R0
+	MOVD	R0, 0(RSP)		// set calling pc
+	RET
+
+TEXT runtime·getcallersp(SB),NOSPLIT,$0-16
+	MOVD	argp+0(FP), R0
+	SUB	$8, R0
+	MOVD	R0, ret+8(FP)
+	RET
+
+TEXT runtime·abort(SB),NOSPLIT,$-8-0
+	B	(ZR)
+	UNDEF
+
+// memhash_varlen(p unsafe.Pointer, h seed) uintptr
+// redirects to memhash(p, h, size) using the size
+// stored in the closure.
+TEXT runtime·memhash_varlen(SB),NOSPLIT,$40-24
+	GO_ARGS
+	NO_LOCAL_POINTERS
+	MOVD	p+0(FP), R3
+	MOVD	h+8(FP), R4
+	MOVD	8(R26), R5
+	MOVD	R3, 8(RSP)
+	MOVD	R4, 16(RSP)
+	MOVD	R5, 24(RSP)
+	BL	runtime·memhash(SB)
+	MOVD	32(RSP), R3
+	MOVD	R3, ret+16(FP)
+	RET
+
+TEXT runtime·memeq(SB),NOSPLIT,$-8-25
+	MOVD	a+0(FP), R1
+	MOVD	b+8(FP), R2
+	MOVD	size+16(FP), R3
+	ADD	R1, R3, R6
+	MOVD	$1, R0
+	MOVB	R0, ret+24(FP)
+loop:
+	CMP	R1, R6
+	BEQ	done
+	MOVBU.P	1(R1), R4
+	MOVBU.P	1(R2), R5
+	CMP	R4, R5
+	BEQ	loop
+
+	MOVB	$0, ret+24(FP)
+done:
+	RET
+
+// memequal_varlen(a, b unsafe.Pointer) bool
+TEXT runtime·memequal_varlen(SB),NOSPLIT,$40-17
+	MOVD	a+0(FP), R3
+	MOVD	b+8(FP), R4
+	CMP	R3, R4
+	BEQ	eq
+	MOVD	8(R26), R5    // compiler stores size at offset 8 in the closure
+	MOVD	R3, 8(RSP)
+	MOVD	R4, 16(RSP)
+	MOVD	R5, 24(RSP)
+	BL	runtime·memeq(SB)
+	MOVBU	32(RSP), R3
+	MOVB	R3, ret+16(FP)
+	RET
+eq:
+	MOVD	$1, R3
+	MOVB	R3, ret+16(FP)
+	RET
+
+// eqstring tests whether two strings are equal.
+// The compiler guarantees that strings passed
+// to eqstring have equal length.
+// See runtime_test.go:eqstring_generic for
+// equivalent Go code.
+TEXT runtime·eqstring(SB),NOSPLIT,$0-33
+	MOVD	s1str+0(FP), R0
+	MOVD	s1len+8(FP), R1
+	MOVD	s2str+16(FP), R2
+	ADD	R0, R1		// end
+loop:
+	CMP	R0, R1
+	BEQ	equal		// reaches the end
+	MOVBU.P	1(R0), R4
+	MOVBU.P	1(R2), R5
+	CMP	R4, R5
+	BEQ	loop
+notequal:
+	MOVB	ZR, ret+32(FP)
+	RET
+equal:
+	MOVD	$1, R0
+	MOVB	R0, ret+32(FP)
+	RET
+
+//
+// functions for other packages
+//
+TEXT bytes·IndexByte(SB),NOSPLIT,$0-40
+	MOVD	b+0(FP), R0
+	MOVD	b_len+8(FP), R1
+	MOVBU	c+24(FP), R2	// byte to find
+	MOVD	R0, R4		// store base for later
+	ADD	R0, R1		// end
+loop:
+	CMP	R0, R1
+	BEQ	notfound
+	MOVBU.P	1(R0), R3
+	CMP	R2, R3
+	BNE	loop
+
+	SUB	$1, R0		// R0 will be one beyond the position we want
+	SUB	R4, R0		// remove base
+	MOVD	R0, ret+32(FP)
+	RET
+
+notfound:
+	MOVD	$-1, R0
+	MOVD	R0, ret+32(FP)
+	RET
+
+TEXT strings·IndexByte(SB),NOSPLIT,$0-32
+	MOVD	s+0(FP), R0
+	MOVD	s_len+8(FP), R1
+	MOVBU	c+16(FP), R2	// byte to find
+	MOVD	R0, R4		// store base for later
+	ADD	R0, R1		// end
+loop:
+	CMP	R0, R1
+	BEQ	notfound
+	MOVBU.P	1(R0), R3
+	CMP	R2, R3
+	BNE	loop
+
+	SUB	$1, R0		// R0 will be one beyond the position we want
+	SUB	R4, R0		// remove base
+	MOVD	R0, ret+24(FP)
+	RET
+
+notfound:
+	MOVD	$-1, R0
+	MOVD	R0, ret+24(FP)
+	RET
+
+// TODO: share code with memeq?
+TEXT bytes·Equal(SB),NOSPLIT,$0-49
+	MOVD	a_len+8(FP), R1
+	MOVD	b_len+32(FP), R3
+	CMP	R1, R3		// unequal lengths are not equal
+	BNE	notequal
+	MOVD	a+0(FP), R0
+	MOVD	b+24(FP), R2
+	ADD	R0, R1		// end
+loop:
+	CMP	R0, R1
+	BEQ	equal		// reaches the end
+	MOVBU.P	1(R0), R4
+	MOVBU.P	1(R2), R5
+	CMP	R4, R5
+	BEQ	loop
+notequal:
+	MOVB	ZR, ret+48(FP)
+	RET
+equal:
+	MOVD	$1, R0
+	MOVB	R0, ret+48(FP)
+	RET
+
+// A Duff's device for zeroing memory.
+// The compiler jumps to computed addresses within
+// this routine to zero chunks of memory.  Do not
+// change this code without also changing the code
+// in ../cmd/7g/ggen.c:/^clearfat.
+// ZR: always zero
+// R16 (aka REGRT1): ptr to memory to be zeroed - 8
+// On return, R16 points to the last zeroed dword.
+TEXT runtime·duffzero(SB), NOSPLIT, $-8-0
+	MOVD.W	ZR, 8(R16)
+	MOVD.W	ZR, 8(R16)
+	MOVD.W	ZR, 8(R16)
+	MOVD.W	ZR, 8(R16)
+	MOVD.W	ZR, 8(R16)
+	MOVD.W	ZR, 8(R16)
+	MOVD.W	ZR, 8(R16)
+	MOVD.W	ZR, 8(R16)
+	MOVD.W	ZR, 8(R16)
+	MOVD.W	ZR, 8(R16)
+	MOVD.W	ZR, 8(R16)
+	MOVD.W	ZR, 8(R16)
+	MOVD.W	ZR, 8(R16)
+	MOVD.W	ZR, 8(R16)
+	MOVD.W	ZR, 8(R16)
+	MOVD.W	ZR, 8(R16)
+	MOVD.W	ZR, 8(R16)
+	MOVD.W	ZR, 8(R16)
+	MOVD.W	ZR, 8(R16)
+	MOVD.W	ZR, 8(R16)
+	MOVD.W	ZR, 8(R16)
+	MOVD.W	ZR, 8(R16)
+	MOVD.W	ZR, 8(R16)
+	MOVD.W	ZR, 8(R16)
+	MOVD.W	ZR, 8(R16)
+	MOVD.W	ZR, 8(R16)
+	MOVD.W	ZR, 8(R16)
+	MOVD.W	ZR, 8(R16)
+	MOVD.W	ZR, 8(R16)
+	MOVD.W	ZR, 8(R16)
+	MOVD.W	ZR, 8(R16)
+	MOVD.W	ZR, 8(R16)
+	MOVD.W	ZR, 8(R16)
+	MOVD.W	ZR, 8(R16)
+	MOVD.W	ZR, 8(R16)
+	MOVD.W	ZR, 8(R16)
+	MOVD.W	ZR, 8(R16)
+	MOVD.W	ZR, 8(R16)
+	MOVD.W	ZR, 8(R16)
+	MOVD.W	ZR, 8(R16)
+	MOVD.W	ZR, 8(R16)
+	MOVD.W	ZR, 8(R16)
+	MOVD.W	ZR, 8(R16)
+	MOVD.W	ZR, 8(R16)
+	MOVD.W	ZR, 8(R16)
+	MOVD.W	ZR, 8(R16)
+	MOVD.W	ZR, 8(R16)
+	MOVD.W	ZR, 8(R16)
+	MOVD.W	ZR, 8(R16)
+	MOVD.W	ZR, 8(R16)
+	MOVD.W	ZR, 8(R16)
+	MOVD.W	ZR, 8(R16)
+	MOVD.W	ZR, 8(R16)
+	MOVD.W	ZR, 8(R16)
+	MOVD.W	ZR, 8(R16)
+	MOVD.W	ZR, 8(R16)
+	MOVD.W	ZR, 8(R16)
+	MOVD.W	ZR, 8(R16)
+	MOVD.W	ZR, 8(R16)
+	MOVD.W	ZR, 8(R16)
+	MOVD.W	ZR, 8(R16)
+	MOVD.W	ZR, 8(R16)
+	MOVD.W	ZR, 8(R16)
+	MOVD.W	ZR, 8(R16)
+	MOVD.W	ZR, 8(R16)
+	MOVD.W	ZR, 8(R16)
+	MOVD.W	ZR, 8(R16)
+	MOVD.W	ZR, 8(R16)
+	MOVD.W	ZR, 8(R16)
+	MOVD.W	ZR, 8(R16)
+	MOVD.W	ZR, 8(R16)
+	MOVD.W	ZR, 8(R16)
+	MOVD.W	ZR, 8(R16)
+	MOVD.W	ZR, 8(R16)
+	MOVD.W	ZR, 8(R16)
+	MOVD.W	ZR, 8(R16)
+	MOVD.W	ZR, 8(R16)
+	MOVD.W	ZR, 8(R16)
+	MOVD.W	ZR, 8(R16)
+	MOVD.W	ZR, 8(R16)
+	MOVD.W	ZR, 8(R16)
+	MOVD.W	ZR, 8(R16)
+	MOVD.W	ZR, 8(R16)
+	MOVD.W	ZR, 8(R16)
+	MOVD.W	ZR, 8(R16)
+	MOVD.W	ZR, 8(R16)
+	MOVD.W	ZR, 8(R16)
+	MOVD.W	ZR, 8(R16)
+	MOVD.W	ZR, 8(R16)
+	MOVD.W	ZR, 8(R16)
+	MOVD.W	ZR, 8(R16)
+	MOVD.W	ZR, 8(R16)
+	MOVD.W	ZR, 8(R16)
+	MOVD.W	ZR, 8(R16)
+	MOVD.W	ZR, 8(R16)
+	MOVD.W	ZR, 8(R16)
+	MOVD.W	ZR, 8(R16)
+	MOVD.W	ZR, 8(R16)
+	MOVD.W	ZR, 8(R16)
+	MOVD.W	ZR, 8(R16)
+	MOVD.W	ZR, 8(R16)
+	MOVD.W	ZR, 8(R16)
+	MOVD.W	ZR, 8(R16)
+	MOVD.W	ZR, 8(R16)
+	MOVD.W	ZR, 8(R16)
+	MOVD.W	ZR, 8(R16)
+	MOVD.W	ZR, 8(R16)
+	MOVD.W	ZR, 8(R16)
+	MOVD.W	ZR, 8(R16)
+	MOVD.W	ZR, 8(R16)
+	MOVD.W	ZR, 8(R16)
+	MOVD.W	ZR, 8(R16)
+	MOVD.W	ZR, 8(R16)
+	MOVD.W	ZR, 8(R16)
+	MOVD.W	ZR, 8(R16)
+	MOVD.W	ZR, 8(R16)
+	MOVD.W	ZR, 8(R16)
+	MOVD.W	ZR, 8(R16)
+	MOVD.W	ZR, 8(R16)
+	MOVD.W	ZR, 8(R16)
+	MOVD.W	ZR, 8(R16)
+	MOVD.W	ZR, 8(R16)
+	MOVD.W	ZR, 8(R16)
+	MOVD.W	ZR, 8(R16)
+	MOVD.W	ZR, 8(R16)
+	MOVD.W	ZR, 8(R16)
+	MOVD.W	ZR, 8(R16)
+	MOVD.W	ZR, 8(R16)
+	RET
+
+TEXT runtime·fastrand1(SB),NOSPLIT,$-8-4
+	MOVD	g_m(g), R1
+	MOVWU	m_fastrand(R1), R0
+	ADD	R0, R0
+	CMPW	$0, R0
+	BGE	notneg
+	EOR	$0x88888eef, R0
+notneg:
+	MOVW	R0, m_fastrand(R1)
+	MOVW	R0, ret+0(FP)
+	RET
+
+TEXT runtime·return0(SB), NOSPLIT, $0
+	MOVW	$0, R0
+	RET
+
+// The top-most function running on a goroutine
+// returns to goexit+PCQuantum.
+TEXT runtime·goexit(SB),NOSPLIT,$-8-0
+	MOVD	R0, R0	// NOP
+	BL	runtime·goexit1(SB)	// does not return
+
+TEXT runtime·getg(SB),NOSPLIT,$-8-8
+	MOVD	g, ret+0(FP)
+	RET
+
+// TODO(aram): use PRFM here.
+TEXT runtime·prefetcht0(SB),NOSPLIT,$0-8
+	RET
+
+TEXT runtime·prefetcht1(SB),NOSPLIT,$0-8
+	RET
+
+TEXT runtime·prefetcht2(SB),NOSPLIT,$0-8
+	RET
+
+TEXT runtime·prefetchnta(SB),NOSPLIT,$0-8
+	RET
+
diff --git a/src/runtime/asm_ppc64x.s b/src/runtime/asm_ppc64x.s
index a8adc4c..10461bb 100644
--- a/src/runtime/asm_ppc64x.s
+++ b/src/runtime/asm_ppc64x.s
@@ -69,7 +69,7 @@
 	BL	runtime·schedinit(SB)
 
 	// create a new goroutine to start program
-	MOVD	$runtime·main·f(SB), R3		// entry
+	MOVD	$runtime·mainPC(SB), R3		// entry
 	MOVDU	R3, -8(R1)
 	MOVDU	R0, -8(R1)
 	MOVDU	R0, -8(R1)
@@ -82,8 +82,8 @@
 	MOVD	R0, 1(R0)
 	RETURN
 
-DATA	runtime·main·f+0(SB)/8,$runtime·main(SB)
-GLOBL	runtime·main·f(SB),RODATA,$8
+DATA	runtime·mainPC+0(SB)/8,$runtime·main(SB)
+GLOBL	runtime·mainPC(SB),RODATA,$8
 
 TEXT runtime·breakpoint(SB),NOSPLIT,$-8-0
 	MOVD	R0, 2(R0) // TODO: TD
@@ -609,12 +609,42 @@
 	// Shift val for aligned ptr.  R4 = val << R6
 	SLD	R6, R4, R4
 
-atomicor8_again:
+again:
 	SYNC
 	LWAR	(R5), R6
 	OR	R4, R6
 	STWCCC	R6, (R5)
-	BNE	atomicor8_again
+	BNE	again
+	SYNC
+	ISYNC
+	RETURN
+
+// void	runtime·atomicand8(byte volatile*, byte);
+TEXT runtime·atomicand8(SB), NOSPLIT, $0-9
+	MOVD	ptr+0(FP), R3
+	MOVBZ	val+8(FP), R4
+	// Align ptr down to 4 bytes so we can use 32-bit load/store.
+	// R5 = (R3 << 0) & ~3
+	RLDCR	$0, R3, $~3, R5
+	// Compute val shift.
+#ifdef GOARCH_ppc64
+	// Big endian.  ptr = ptr ^ 3
+	XOR	$3, R3
+#endif
+	// R6 = ((ptr & 3) * 8) = (ptr << 3) & (3*8)
+	RLDC	$3, R3, $(3*8), R6
+	// Shift val for aligned ptr.  R4 = val << R6 | ^(0xFF << R6)
+	MOVD	$0xFF, R7
+	SLD	R6, R4
+	SLD	R6, R7
+	XOR $-1, R7
+	OR	R7, R4
+again:
+	SYNC
+	LWAR	(R5), R6
+	AND	R4, R6
+	STWCCC	R6, (R5)
+	BNE	again
 	SYNC
 	ISYNC
 	RETURN
@@ -1039,7 +1069,7 @@
 	MOVD	R3, ret+32(FP)
 	RETURN
 
-TEXT strings·IndexByte(SB),NOSPLIT,$0
+TEXT strings·IndexByte(SB),NOSPLIT,$0-32
 	MOVD	p+0(FP), R3
 	MOVD	b_len+8(FP), R4
 	MOVBZ	c+16(FP), R5	// byte to find
diff --git a/src/runtime/atomic_386.go b/src/runtime/atomic_386.go
index 0171d90..7828c66 100644
--- a/src/runtime/atomic_386.go
+++ b/src/runtime/atomic_386.go
@@ -58,8 +58,13 @@
 func atomicload64(ptr *uint64) uint64
 
 //go:noescape
+func atomicand8(ptr *uint8, val uint8)
+
+//go:noescape
 func atomicor8(ptr *uint8, val uint8)
 
+// NOTE: Do not add atomicxor8 (XOR is not idempotent).
+
 //go:noescape
 func cas64(ptr *uint64, old, new uint64) bool
 
diff --git a/src/runtime/atomic_amd64x.go b/src/runtime/atomic_amd64x.go
index c5355f6..e539387 100644
--- a/src/runtime/atomic_amd64x.go
+++ b/src/runtime/atomic_amd64x.go
@@ -49,8 +49,13 @@
 func xchguintptr(ptr *uintptr, new uintptr) uintptr
 
 //go:noescape
+func atomicand8(ptr *uint8, val uint8)
+
+//go:noescape
 func atomicor8(ptr *uint8, val uint8)
 
+// NOTE: Do not add atomicxor8 (XOR is not idempotent).
+
 //go:noescape
 func cas64(ptr *uint64, old, new uint64) bool
 
diff --git a/src/runtime/atomic_arm.go b/src/runtime/atomic_arm.go
index ff73144..75206ab 100644
--- a/src/runtime/atomic_arm.go
+++ b/src/runtime/atomic_arm.go
@@ -153,3 +153,19 @@
 		}
 	}
 }
+
+//go:nosplit
+func atomicand8(addr *uint8, v uint8) {
+	// Align down to 4 bytes and use 32-bit CAS.
+	uaddr := uintptr(unsafe.Pointer(addr))
+	addr32 := (*uint32)(unsafe.Pointer(uaddr &^ 3))
+	word := uint32(v) << ((uaddr & 3) * 8)    // little endian
+	mask := uint32(0xFF) << ((uaddr & 3) * 8) // little endian
+	word |= ^mask
+	for {
+		old := *addr32
+		if cas(addr32, old, old&word) {
+			return
+		}
+	}
+}
diff --git a/src/runtime/atomic_arm64.go b/src/runtime/atomic_arm64.go
new file mode 100644
index 0000000..6a78a8d
--- /dev/null
+++ b/src/runtime/atomic_arm64.go
@@ -0,0 +1,78 @@
+// Copyright 2015 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 runtime
+
+import "unsafe"
+
+//go:noescape
+func xadd(ptr *uint32, delta int32) uint32
+
+//go:noescape
+func xadd64(ptr *uint64, delta int64) uint64
+
+//go:noescape
+func xchg(ptr *uint32, new uint32) uint32
+
+//go:noescape
+func xchg64(ptr *uint64, new uint64) uint64
+
+// NO go:noescape annotation; see atomic_pointer.go.
+func xchgp1(ptr unsafe.Pointer, new unsafe.Pointer) unsafe.Pointer
+
+//go:noescape
+func xchguintptr(ptr *uintptr, new uintptr) uintptr
+
+//go:noescape
+func atomicload(ptr *uint32) uint32
+
+//go:noescape
+func atomicload64(ptr *uint64) uint64
+
+//go:noescape
+func atomicloadp(ptr unsafe.Pointer) unsafe.Pointer
+
+//go:nosplit
+func atomicor8(addr *uint8, v uint8) {
+	// TODO(dfc) implement this in asm.
+	// Align down to 4 bytes and use 32-bit CAS.
+	uaddr := uintptr(unsafe.Pointer(addr))
+	addr32 := (*uint32)(unsafe.Pointer(uaddr &^ 3))
+	word := uint32(v) << ((uaddr & 3) * 8) // little endian
+	for {
+		old := *addr32
+		if cas(addr32, old, old|word) {
+			return
+		}
+	}
+}
+
+//go:nosplit
+func atomicand8(addr *uint8, v uint8) {
+	// TODO(dfc) implement this in asm.
+	// Align down to 4 bytes and use 32-bit CAS.
+	uaddr := uintptr(unsafe.Pointer(addr))
+	addr32 := (*uint32)(unsafe.Pointer(uaddr &^ 3))
+	word := uint32(v) << ((uaddr & 3) * 8)    // little endian
+	mask := uint32(0xFF) << ((uaddr & 3) * 8) // little endian
+	word |= ^mask
+	for {
+		old := *addr32
+		if cas(addr32, old, old&word) {
+			return
+		}
+	}
+}
+
+//go:noescape
+func cas64(ptr *uint64, old, new uint64) bool
+
+//go:noescape
+func atomicstore(ptr *uint32, val uint32)
+
+//go:noescape
+func atomicstore64(ptr *uint64, val uint64)
+
+// NO go:noescape annotation; see atomic_pointer.go.
+func atomicstorep1(ptr unsafe.Pointer, val unsafe.Pointer)
diff --git a/src/runtime/atomic_arm64.s b/src/runtime/atomic_arm64.s
new file mode 100644
index 0000000..acd0a62
--- /dev/null
+++ b/src/runtime/atomic_arm64.s
@@ -0,0 +1,113 @@
+// 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.
+
+#include "textflag.h"
+
+// uint32 runtime·atomicload(uint32 volatile* addr)
+TEXT ·atomicload(SB),NOSPLIT,$-8-12
+	MOVD	ptr+0(FP), R0
+	LDARW	(R0), R0
+	MOVW	R0, ret+8(FP)
+	RET
+
+// uint64 runtime·atomicload64(uint64 volatile* addr)
+TEXT ·atomicload64(SB),NOSPLIT,$-8-16
+	MOVD	ptr+0(FP), R0
+	LDAR	(R0), R0
+	MOVD	R0, ret+8(FP)
+	RET
+
+// void *runtime·atomicloadp(void *volatile *addr)
+TEXT ·atomicloadp(SB),NOSPLIT,$-8-16
+	MOVD	ptr+0(FP), R0
+	LDAR	(R0), R0
+	MOVD	R0, ret+8(FP)
+	RET
+
+TEXT runtime·atomicstorep1(SB), NOSPLIT, $0-16
+	B	runtime·atomicstore64(SB)
+
+TEXT runtime·atomicstore(SB), NOSPLIT, $0-12
+	MOVD	ptr+0(FP), R0
+	MOVW	val+8(FP), R1
+	STLRW	R1, (R0)
+	RET
+
+TEXT runtime·atomicstore64(SB), NOSPLIT, $0-16
+	MOVD	ptr+0(FP), R0
+	MOVD	val+8(FP), R1
+	STLR	R1, (R0)
+	RET
+
+TEXT runtime·xchg(SB), NOSPLIT, $0-20
+again:
+	MOVD	ptr+0(FP), R0
+	MOVW	new+8(FP), R1
+	LDAXRW	(R0), R2
+	STLXRW	R1, (R0), R3
+	CBNZ	R3, again
+	MOVW	R2, ret+16(FP)
+	RET
+
+TEXT runtime·xchg64(SB), NOSPLIT, $0-24
+again:
+	MOVD	ptr+0(FP), R0
+	MOVD	new+8(FP), R1
+	LDAXR	(R0), R2
+	STLXR	R1, (R0), R3
+	CBNZ	R3, again
+	MOVD	R2, ret+16(FP)
+	RET
+
+// bool runtime·cas64(uint64 *ptr, uint64 old, uint64 new)
+// Atomically:
+//      if(*val == *old){
+//              *val = new;
+//              return 1;
+//      } else {
+//              return 0;
+//      }
+TEXT runtime·cas64(SB), NOSPLIT, $0-25
+	MOVD	ptr+0(FP), R0
+	MOVD	old+8(FP), R1
+	MOVD	new+16(FP), R2
+again:
+	LDAXR	(R0), R3
+	CMP	R1, R3
+	BNE	ok
+	STLXR	R2, (R0), R3
+	CBNZ	R3, again
+ok:
+	CSET	EQ, R0
+	MOVB	R0, ret+24(FP)
+	RET
+
+// uint32 xadd(uint32 volatile *ptr, int32 delta)
+// Atomically:
+//      *val += delta;
+//      return *val;
+TEXT runtime·xadd(SB), NOSPLIT, $0-20
+again:
+	MOVD	ptr+0(FP), R0
+	MOVW	delta+8(FP), R1
+	LDAXRW	(R0), R2
+	ADDW	R2, R1, R2
+	STLXRW	R2, (R0), R3
+	CBNZ	R3, again
+	MOVW	R2, ret+16(FP)
+	RET
+
+TEXT runtime·xadd64(SB), NOSPLIT, $0-24
+again:
+	MOVD	ptr+0(FP), R0
+	MOVD	delta+8(FP), R1
+	LDAXR	(R0), R2
+	ADD	R2, R1, R2
+	STLXR	R2, (R0), R3
+	CBNZ	R3, again
+	MOVD	R2, ret+16(FP)
+	RET
+
+TEXT runtime·xchguintptr(SB), NOSPLIT, $0-24
+	B	runtime·xchg64(SB)
diff --git a/src/runtime/atomic_ppc64x.go b/src/runtime/atomic_ppc64x.go
index 65dd9fc..17c642d 100644
--- a/src/runtime/atomic_ppc64x.go
+++ b/src/runtime/atomic_ppc64x.go
@@ -36,8 +36,13 @@
 func atomicloadp(ptr unsafe.Pointer) unsafe.Pointer
 
 //go:noescape
+func atomicand8(ptr *uint8, val uint8)
+
+//go:noescape
 func atomicor8(ptr *uint8, val uint8)
 
+// NOTE: Do not add atomicxor8 (XOR is not idempotent).
+
 //go:noescape
 func cas64(ptr *uint64, old, new uint64) bool
 
diff --git a/src/runtime/cgo.go b/src/runtime/cgo.go
index 7e6b253..5dc83c0 100644
--- a/src/runtime/cgo.go
+++ b/src/runtime/cgo.go
@@ -21,3 +21,10 @@
 	_cgo_free         unsafe.Pointer
 	_cgo_thread_start unsafe.Pointer
 )
+
+// iscgo is set to true by the runtime/cgo package
+var iscgo bool
+
+// cgoHasExtraM is set on startup when an extra M is created for cgo.
+// The extra M must be created before any C/C++ code calls cgocallback.
+var cgoHasExtraM bool
diff --git a/src/runtime/cgo/gcc_darwin_arm.c b/src/runtime/cgo/gcc_darwin_arm.c
index aa7f438..c303b91 100644
--- a/src/runtime/cgo/gcc_darwin_arm.c
+++ b/src/runtime/cgo/gcc_darwin_arm.c
@@ -84,6 +84,8 @@
 	ts = *(ThreadStart*)v;
 	free(v);
 
+	darwin_arm_init_thread_exception_port();
+
 	crosscall_arm1(ts.fn, setg_gcc, (void*)ts.g);
 	return nil;
 }
@@ -145,5 +147,7 @@
 	// yes, tlsbase from mrc might not be correctly aligned.
 	inittls(tlsg, (void**)((uintptr)tlsbase & ~3));
 
+	darwin_arm_init_mach_exception_handler();
+	darwin_arm_init_thread_exception_port();
 	init_working_dir();
 }
diff --git a/src/runtime/cgo/gcc_dragonfly_386.c b/src/runtime/cgo/gcc_dragonfly_386.c
deleted file mode 100644
index 074418f..0000000
--- a/src/runtime/cgo/gcc_dragonfly_386.c
+++ /dev/null
@@ -1,70 +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.
-
-#include <sys/types.h>
-#include <sys/signalvar.h>
-#include <pthread.h>
-#include <signal.h>
-#include <string.h>
-#include "libcgo.h"
-
-static void* threadentry(void*);
-static void (*setg_gcc)(void*);
-
-void
-x_cgo_init(G *g, void (*setg)(void*))
-{
-	pthread_attr_t attr;
-	size_t size;
-
-	setg_gcc = setg;
-	pthread_attr_init(&attr);
-	pthread_attr_getstacksize(&attr, &size);
-	g->stacklo = (uintptr)&attr - size + 4096;
-	pthread_attr_destroy(&attr);
-}
-
-
-void
-_cgo_sys_thread_start(ThreadStart *ts)
-{
-	pthread_attr_t attr;
-	sigset_t ign, oset;
-	pthread_t p;
-	size_t size;
-	int err;
-
-	SIGFILLSET(ign);
-	pthread_sigmask(SIG_SETMASK, &ign, &oset);
-
-	pthread_attr_init(&attr);
-	pthread_attr_getstacksize(&attr, &size);
-	// Leave stacklo=0 and set stackhi=size; mstack will do the rest.
-	ts->g->stackhi = size;
-	err = pthread_create(&p, &attr, threadentry, ts);
-
-	pthread_sigmask(SIG_SETMASK, &oset, nil);
-
-	if (err != 0) {
-		fprintf(stderr, "runtime/cgo: pthread_create failed: %s\n", strerror(err));
-		abort();
-	}
-}
-
-static void*
-threadentry(void *v)
-{
-	ThreadStart ts;
-
-	ts = *(ThreadStart*)v;
-	free(v);
-
-	/*
-	 * Set specific keys.
-	 */
-	setg_gcc((void*)ts.g);
-
-	crosscall_386(ts.fn);
-	return nil;
-}
diff --git a/src/runtime/cgo/gcc_signal_darwin_armx.c b/src/runtime/cgo/gcc_signal_darwin_armx.c
new file mode 100644
index 0000000..cb32898
--- /dev/null
+++ b/src/runtime/cgo/gcc_signal_darwin_armx.c
@@ -0,0 +1,185 @@
+// Copyright 2015 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.
+
+// Emulation of the Unix signal SIGSEGV.
+//
+// On iOS, Go tests and apps under development are run by lldb.
+// The debugger uses a task-level exception handler to intercept signals.
+// Despite having a 'handle' mechanism like gdb, lldb will not allow a
+// SIGSEGV to pass to the running program. For Go, this means we cannot
+// generate a panic, which cannot be recovered, and so tests fail.
+//
+// We work around this by registering a thread-level mach exception handler
+// and intercepting EXC_BAD_ACCESS. The kernel offers thread handlers a
+// chance to resolve exceptions before the task handler, so we can generate
+// the panic and avoid lldb's SIGSEGV handler.
+//
+// If you want to debug a segfault under lldb, compile the standard library
+// with the build tag lldb:
+//
+//	go test -tags lldb -installsuffix lldb
+
+// +build darwin,arm,!lldb
+
+// TODO(crawshaw): darwin,arm64,!lldb
+
+#include <limits.h>
+#include <pthread.h>
+#include <stdio.h>
+#include <signal.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include <mach/arm/thread_status.h>
+#include <mach/exception_types.h>
+#include <mach/mach.h>
+#include <mach/mach_init.h>
+#include <mach/mach_port.h>
+#include <mach/thread_act.h>
+#include <mach/thread_status.h>
+
+#include "libcgo.h"
+
+uintptr_t x_cgo_panicmem;
+
+static pthread_mutex_t mach_exception_handler_port_set_mu;
+static mach_port_t mach_exception_handler_port_set = MACH_PORT_NULL;
+
+kern_return_t
+catch_exception_raise(
+	mach_port_t exception_port,
+	mach_port_t thread,
+	mach_port_t task,
+	exception_type_t exception,
+	exception_data_t code_vector,
+	mach_msg_type_number_t code_count)
+{
+	kern_return_t ret;
+	arm_unified_thread_state_t thread_state;
+	mach_msg_type_number_t state_count = ARM_UNIFIED_THREAD_STATE_COUNT;
+
+	// Returning KERN_SUCCESS intercepts the exception.
+	//
+	// Returning KERN_FAILURE lets the exception fall through to the
+	// next handler, which is the standard signal emulation code
+	// registered on the task port.
+
+	if (exception != EXC_BAD_ACCESS) {
+		return KERN_FAILURE;
+	}
+
+	ret = thread_get_state(thread, ARM_UNIFIED_THREAD_STATE, (thread_state_t)&thread_state, &state_count);
+	if (ret) {
+		fprintf(stderr, "runtime/cgo: thread_get_state failed: %d\n", ret);
+		abort();
+	}
+
+	// Bounce call to sigpanic through asm that makes it look like
+	// we call sigpanic directly from the faulting code.
+	thread_state.ts_32.__r[1] = thread_state.ts_32.__lr;
+	thread_state.ts_32.__r[2] = thread_state.ts_32.__pc;
+	thread_state.ts_32.__pc = x_cgo_panicmem;
+
+	ret = thread_set_state(thread, ARM_UNIFIED_THREAD_STATE, (thread_state_t)&thread_state, state_count);
+	if (ret) {
+		fprintf(stderr, "runtime/cgo: thread_set_state failed: %d\n", ret);
+		abort();
+	}
+
+	return KERN_SUCCESS;
+}
+
+void
+darwin_arm_init_thread_exception_port()
+{
+	// Called by each new OS thread to bind its EXC_BAD_ACCESS exception
+	// to mach_exception_handler_port_set.
+	int ret;
+	mach_port_t port = MACH_PORT_NULL;
+
+	ret = mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &port);
+	if (ret) {
+		fprintf(stderr, "runtime/cgo: mach_port_allocate failed: %d\n", ret);
+		abort();
+	}
+	ret = mach_port_insert_right(
+		mach_task_self(),
+		port,
+		port,
+		MACH_MSG_TYPE_MAKE_SEND);
+	if (ret) {
+		fprintf(stderr, "runtime/cgo: mach_port_insert_right failed: %d\n", ret);
+		abort();
+	}
+
+	ret = thread_set_exception_ports(
+		mach_thread_self(),
+		EXC_MASK_BAD_ACCESS,
+		port,
+		EXCEPTION_DEFAULT,
+		THREAD_STATE_NONE);
+	if (ret) {
+		fprintf(stderr, "runtime/cgo: thread_set_exception_ports failed: %d\n", ret);
+		abort();
+	}
+
+	ret = pthread_mutex_lock(&mach_exception_handler_port_set_mu);
+	if (ret) {
+		fprintf(stderr, "runtime/cgo: pthread_mutex_lock failed: %d\n", ret);
+		abort();
+	}
+	ret = mach_port_move_member(
+		mach_task_self(),
+		port,
+		mach_exception_handler_port_set);
+	if (ret) {
+		fprintf(stderr, "runtime/cgo: mach_port_move_member failed: %d\n", ret);
+		abort();
+	}
+	ret = pthread_mutex_unlock(&mach_exception_handler_port_set_mu);
+	if (ret) {
+		fprintf(stderr, "runtime/cgo: pthread_mutex_unlock failed: %d\n", ret);
+		abort();
+	}
+}
+
+static void*
+mach_exception_handler(void *port)
+{
+	// Calls catch_exception_raise.
+	extern boolean_t exc_server();
+	mach_msg_server(exc_server, 2048, (mach_port_t)port, 0);
+	abort(); // never returns
+}
+
+void
+darwin_arm_init_mach_exception_handler()
+{
+	pthread_mutex_init(&mach_exception_handler_port_set_mu, NULL);
+
+	// Called once per process to initialize a mach port server, listening
+	// for EXC_BAD_ACCESS thread exceptions.
+	int ret;
+	pthread_t thr = NULL;
+	pthread_attr_t attr;
+
+	ret = mach_port_allocate(
+		mach_task_self(),
+		MACH_PORT_RIGHT_PORT_SET,
+		&mach_exception_handler_port_set);
+	if (ret) {
+		fprintf(stderr, "runtime/cgo: mach_port_allocate failed for port_set: %d\n", ret);
+		abort();
+	}
+
+	// Start a thread to handle exceptions.
+	pthread_attr_init(&attr);
+	pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
+	ret = pthread_create(&thr, &attr, mach_exception_handler, (void*)mach_exception_handler_port_set);
+	if (ret) {
+		fprintf(stderr, "runtime/cgo: pthread_create failed: %d\n", ret);
+		abort();
+	}
+	pthread_attr_destroy(&attr);
+}
diff --git a/src/runtime/cgo/gcc_signal_darwin_lldb.c b/src/runtime/cgo/gcc_signal_darwin_lldb.c
new file mode 100644
index 0000000..d3a3ddd
--- /dev/null
+++ b/src/runtime/cgo/gcc_signal_darwin_lldb.c
@@ -0,0 +1,14 @@
+// Copyright 2015 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.
+
+// +build darwin
+// +build arm arm64
+// +build lldb
+
+#include <stdint.h>
+
+uintptr_t x_cgo_panicmem;
+
+void darwin_arm_init_thread_exception_port() {}
+void darwin_arm_init_mach_exception_handler() {}
diff --git a/src/runtime/cgo/iscgo.go b/src/runtime/cgo/iscgo.go
index 61cba73..54f0a13 100644
--- a/src/runtime/cgo/iscgo.go
+++ b/src/runtime/cgo/iscgo.go
@@ -15,6 +15,3 @@
 
 //go:linkname _iscgo runtime.iscgo
 var _iscgo bool = true
-
-//go:linkname _needextram runtime.needextram
-var _needextram uint32 = 1 // create an extra M on first cgo call
diff --git a/src/runtime/cgo/libcgo.h b/src/runtime/cgo/libcgo.h
index 9d918fd..6d4f23e 100644
--- a/src/runtime/cgo/libcgo.h
+++ b/src/runtime/cgo/libcgo.h
@@ -63,3 +63,13 @@
  * Prints error then calls abort. For linux and android.
  */
 void fatalf(const char* format, ...);
+
+/*
+ * Registers the current mach thread port for EXC_BAD_ACCESS processing.
+ */
+void darwin_arm_init_thread_exception_port(void);
+
+/*
+ * Starts a mach message server processing EXC_BAD_ACCESS.
+ */
+void darwin_arm_init_mach_exception_handler(void);
diff --git a/src/runtime/cgo/signal_darwin_arm.s b/src/runtime/cgo/signal_darwin_arm.s
new file mode 100644
index 0000000..ee5c3d3
--- /dev/null
+++ b/src/runtime/cgo/signal_darwin_arm.s
@@ -0,0 +1,49 @@
+// Copyright 2015 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.
+
+#include "textflag.h"
+
+// panicmem is the entrypoint for SIGSEGV as intercepted via a
+// mach thread port as EXC_BAD_ACCESS. As the segfault may have happened
+// in C code, we first need to load_g then call panicmem.
+//
+//	R1 - LR at moment of fault
+//	R2 - PC at moment of fault
+TEXT ·panicmem(SB),NOSPLIT,$-4
+	// If in external C code, we need to load the g register.
+	BL  runtime·load_g(SB)
+	CMP $0, g
+	BNE ongothread
+
+	// On a foreign thread. We call badsignal, which will, if all
+	// goes according to plan, not return.
+	SUB  $4, R13
+	MOVW $11, R1
+	MOVW $11, R2
+	MOVM.DB.W [R1,R2], (R13)
+	// TODO: badsignal should not return, but it does. Issue #10139.
+	//BL runtime·badsignal(SB)
+	MOVW $139, R1
+	MOVW R1, 4(R13)
+	B    runtime·exit(SB)
+
+ongothread:
+	// Trigger a SIGSEGV panic.
+	//
+	// The goal is to arrange the stack so it looks like the runtime
+	// function sigpanic was called from the PC that faulted. It has
+	// to be sigpanic, as the stack unwinding code in traceback.go
+	// looks explicitly for it.
+	//
+	// To do this we call into runtime·setsigsegv, which sets the
+	// appropriate state inside the g object. We give it the faulting
+	// PC on the stack, then put it in the LR before calling sigpanic.
+	MOVM.DB.W [R1,R2], (R13)
+	BL runtime·setsigsegv(SB)
+	MOVM.IA.W (R13), [R1,R2]
+
+	SUB $4, R13
+	MOVW R1, 0(R13)
+	MOVW R2, R14
+	B runtime·sigpanic(SB)
diff --git a/src/runtime/cgo/signal_darwin_armx.go b/src/runtime/cgo/signal_darwin_armx.go
new file mode 100644
index 0000000..9c1ba5d
--- /dev/null
+++ b/src/runtime/cgo/signal_darwin_armx.go
@@ -0,0 +1,31 @@
+// Copyright 2015 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.
+
+// +build darwin
+// +build arm arm64
+
+package cgo
+
+import "unsafe"
+
+//go:cgo_import_static x_cgo_panicmem
+//go:linkname x_cgo_panicmem x_cgo_panicmem
+var x_cgo_panicmem uintptr
+
+// TODO(crawshaw): move this into x_cgo_init, it will not run until
+// runtime has finished loading, which may be after its use.
+func init() {
+	x_cgo_panicmem = funcPC(panicmem)
+}
+
+func funcPC(f interface{}) uintptr {
+	var ptrSize = unsafe.Sizeof(uintptr(0))
+	return **(**uintptr)(add(unsafe.Pointer(&f), ptrSize))
+}
+
+func add(p unsafe.Pointer, x uintptr) unsafe.Pointer {
+	return unsafe.Pointer(uintptr(p) + x)
+}
+
+func panicmem()
diff --git a/src/runtime/cgocall.go b/src/runtime/cgocall.go
index e7aeb7b..052830d 100644
--- a/src/runtime/cgocall.go
+++ b/src/runtime/cgocall.go
@@ -101,11 +101,6 @@
 		racereleasemerge(unsafe.Pointer(&racecgosync))
 	}
 
-	// Create an extra M for callbacks on threads not created by Go on first cgo call.
-	if needextram == 1 && cas(&needextram, 1, 0) {
-		systemstack(newextram)
-	}
-
 	/*
 	 * Lock g to m to ensure we stay on the same stack if we do a
 	 * cgo callback. Add entry to defer stack in case of panic.
diff --git a/src/runtime/cgocallback.go b/src/runtime/cgocallback.go
index 2c89143..20ce87d 100644
--- a/src/runtime/cgocallback.go
+++ b/src/runtime/cgocallback.go
@@ -6,7 +6,7 @@
 
 import "unsafe"
 
-// These functions are called from C code via cgo/callbacks.c.
+// These functions are called from C code via cgo/callbacks.go.
 
 // Allocate memory.  This allocates the requested number of bytes in
 // memory controlled by the Go runtime.  The allocated memory will be
diff --git a/src/runtime/chan.go b/src/runtime/chan.go
index 56560f9..87e05bd 100644
--- a/src/runtime/chan.go
+++ b/src/runtime/chan.go
@@ -14,7 +14,24 @@
 	debugChan = false
 )
 
-// TODO(khr): make hchan.buf an unsafe.Pointer, not a *uint8
+type hchan struct {
+	qcount   uint           // total data in the queue
+	dataqsiz uint           // size of the circular queue
+	buf      unsafe.Pointer // points to an array of dataqsiz elements
+	elemsize uint16
+	closed   uint32
+	elemtype *_type // element type
+	sendx    uint   // send index
+	recvx    uint   // receive index
+	recvq    waitq  // list of recv waiters
+	sendq    waitq  // list of send waiters
+	lock     mutex
+}
+
+type waitq struct {
+	first *sudog
+	last  *sudog
+}
 
 //go:linkname reflect_makechan reflect.makechan
 func reflect_makechan(t *chantype, size int64) *hchan {
@@ -44,15 +61,15 @@
 		// TODO(dvyukov,rlh): Rethink when collector can move allocated objects.
 		c = (*hchan)(mallocgc(hchanSize+uintptr(size)*uintptr(elem.size), nil, flagNoScan))
 		if size > 0 && elem.size != 0 {
-			c.buf = (*uint8)(add(unsafe.Pointer(c), hchanSize))
+			c.buf = add(unsafe.Pointer(c), hchanSize)
 		} else {
 			// race detector uses this location for synchronization
 			// Also prevents us from pointing beyond the allocation (see issue 9401).
-			c.buf = (*uint8)(unsafe.Pointer(c))
+			c.buf = unsafe.Pointer(c)
 		}
 	} else {
 		c = new(hchan)
-		c.buf = (*uint8)(newarray(elem, uintptr(size)))
+		c.buf = newarray(elem, uintptr(size))
 	}
 	c.elemsize = uint16(elem.size)
 	c.elemtype = elem
@@ -66,7 +83,7 @@
 
 // chanbuf(c, i) is pointer to the i'th slot in the buffer.
 func chanbuf(c *hchan, i uint) unsafe.Pointer {
-	return add(unsafe.Pointer(c.buf), uintptr(i)*uintptr(c.elemsize))
+	return add(c.buf, uintptr(i)*uintptr(c.elemsize))
 }
 
 // entry point for c <- x from compiled code
@@ -96,7 +113,7 @@
 		if !block {
 			return false
 		}
-		gopark(nil, nil, "chan send (nil chan)", traceEvGoStop)
+		gopark(nil, nil, "chan send (nil chan)", traceEvGoStop, 2)
 		throw("unreachable")
 	}
 
@@ -155,7 +172,7 @@
 			if sg.releasetime != 0 {
 				sg.releasetime = cputicks()
 			}
-			goready(recvg)
+			goready(recvg, 3)
 			return true
 		}
 
@@ -178,7 +195,7 @@
 		mysg.selectdone = nil
 		gp.param = nil
 		c.sendq.enqueue(mysg)
-		goparkunlock(&c.lock, "chan send", traceEvGoBlockSend)
+		goparkunlock(&c.lock, "chan send", traceEvGoBlockSend, 3)
 
 		// someone woke us up.
 		if mysg != gp.waiting {
@@ -202,7 +219,7 @@
 	// asynchronous channel
 	// wait for some space to write our data
 	var t1 int64
-	for c.qcount >= c.dataqsiz {
+	for futile := byte(0); c.qcount >= c.dataqsiz; futile = traceFutileWakeup {
 		if !block {
 			unlock(&c.lock)
 			return false
@@ -217,7 +234,7 @@
 		mysg.elem = nil
 		mysg.selectdone = nil
 		c.sendq.enqueue(mysg)
-		goparkunlock(&c.lock, "chan send", traceEvGoBlockSend)
+		goparkunlock(&c.lock, "chan send", traceEvGoBlockSend|futile, 3)
 
 		// someone woke us up - try again
 		if mysg.releasetime > 0 {
@@ -251,7 +268,7 @@
 		if sg.releasetime != 0 {
 			sg.releasetime = cputicks()
 		}
-		goready(recvg)
+		goready(recvg, 3)
 	} else {
 		unlock(&c.lock)
 	}
@@ -292,7 +309,7 @@
 		if sg.releasetime != 0 {
 			sg.releasetime = cputicks()
 		}
-		goready(gp)
+		goready(gp, 3)
 	}
 
 	// release all writers
@@ -307,7 +324,7 @@
 		if sg.releasetime != 0 {
 			sg.releasetime = cputicks()
 		}
-		goready(gp)
+		goready(gp, 3)
 	}
 	unlock(&c.lock)
 }
@@ -340,7 +357,7 @@
 		if !block {
 			return
 		}
-		gopark(nil, nil, "chan receive (nil chan)", traceEvGoStop)
+		gopark(nil, nil, "chan receive (nil chan)", traceEvGoStop, 2)
 		throw("unreachable")
 	}
 
@@ -389,7 +406,7 @@
 			if sg.releasetime != 0 {
 				sg.releasetime = cputicks()
 			}
-			goready(gp)
+			goready(gp, 3)
 			selected = true
 			received = true
 			return
@@ -414,7 +431,7 @@
 		mysg.selectdone = nil
 		gp.param = nil
 		c.recvq.enqueue(mysg)
-		goparkunlock(&c.lock, "chan receive", traceEvGoBlockRecv)
+		goparkunlock(&c.lock, "chan receive", traceEvGoBlockRecv, 3)
 
 		// someone woke us up
 		if mysg != gp.waiting {
@@ -445,7 +462,7 @@
 	// asynchronous channel
 	// wait for some data to appear
 	var t1 int64
-	for c.qcount <= 0 {
+	for futile := byte(0); c.qcount <= 0; futile = traceFutileWakeup {
 		if c.closed != 0 {
 			selected, received = recvclosed(c, ep)
 			if t1 > 0 {
@@ -471,7 +488,7 @@
 		mysg.selectdone = nil
 
 		c.recvq.enqueue(mysg)
-		goparkunlock(&c.lock, "chan receive", traceEvGoBlockRecv)
+		goparkunlock(&c.lock, "chan receive", traceEvGoBlockRecv|futile, 3)
 
 		// someone woke us up - try again
 		if mysg.releasetime > 0 {
@@ -504,7 +521,7 @@
 		if sg.releasetime != 0 {
 			sg.releasetime = cputicks()
 		}
-		goready(gp)
+		goready(gp, 3)
 	} else {
 		unlock(&c.lock)
 	}
diff --git a/src/runtime/chan1.go b/src/runtime/chan1.go
deleted file mode 100644
index 000775b..0000000
--- a/src/runtime/chan1.go
+++ /dev/null
@@ -1,61 +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 runtime
-
-import "unsafe"
-
-//#define	MAXALIGN	8
-
-type waitq struct {
-	first *sudog
-	last  *sudog
-}
-
-type hchan struct {
-	qcount   uint // total data in the q
-	dataqsiz uint // size of the circular q
-	buf      *byte
-	elemsize uint16
-	closed   uint32
-	elemtype *_type // element type
-	sendx    uint   // send index
-	recvx    uint   // receive index
-	recvq    waitq  // list of recv waiters
-	sendq    waitq  // list of send waiters
-	lock     mutex
-}
-
-// Buffer follows Hchan immediately in memory.
-// chanbuf(c, i) is pointer to the i'th slot in the buffer.
-// #define chanbuf(c, i) ((byte*)((c)->buf)+(uintptr)(c)->elemsize*(i))
-
-const (
-	// scase.kind
-	_CaseRecv = iota
-	_CaseSend
-	_CaseDefault
-)
-
-// Known to compiler.
-// Changes here must also be made in src/cmd/gc/select.c's selecttype.
-type scase struct {
-	elem        unsafe.Pointer // data element
-	_chan       *hchan         // chan
-	pc          uintptr        // return pc
-	kind        uint16
-	so          uint16 // vararg of selected bool
-	receivedp   *bool  // pointer to received bool (recv2)
-	releasetime int64
-}
-
-// Known to compiler.
-// Changes here must also be made in src/cmd/gc/select.c's selecttype.
-type _select struct {
-	tcase     uint16   // total count of scase[]
-	ncase     uint16   // currently filled scase[]
-	pollorder *uint16  // case poll order
-	lockorder **hchan  // channel lock order
-	scase     [1]scase // one per case (in order of appearance)
-}
diff --git a/src/runtime/chan_test.go b/src/runtime/chan_test.go
index 8a357c1..0b918bb 100644
--- a/src/runtime/chan_test.go
+++ b/src/runtime/chan_test.go
@@ -218,6 +218,81 @@
 	}
 }
 
+// This test checks that select acts on the state of the channels at one
+// moment in the execution, not over a smeared time window.
+// In the test, one goroutine does:
+//	create c1, c2
+//	make c1 ready for receiving
+//	create second goroutine
+//	make c2 ready for receiving
+//	make c1 no longer ready for receiving (if possible)
+// The second goroutine does a non-blocking select receiving from c1 and c2.
+// From the time the second goroutine is created, at least one of c1 and c2
+// is always ready for receiving, so the select in the second goroutine must
+// always receive from one or the other. It must never execute the default case.
+func TestNonblockSelectRace(t *testing.T) {
+	n := 100000
+	if testing.Short() {
+		n = 1000
+	}
+	done := make(chan bool, 1)
+	for i := 0; i < n; i++ {
+		c1 := make(chan int, 1)
+		c2 := make(chan int, 1)
+		c1 <- 1
+		go func() {
+			select {
+			case <-c1:
+			case <-c2:
+			default:
+				done <- false
+				return
+			}
+			done <- true
+		}()
+		c2 <- 1
+		select {
+		case <-c1:
+		default:
+		}
+		if !<-done {
+			t.Fatal("no chan is ready")
+		}
+	}
+}
+
+// Same as TestNonblockSelectRace, but close(c2) replaces c2 <- 1.
+func TestNonblockSelectRace2(t *testing.T) {
+	n := 100000
+	if testing.Short() {
+		n = 1000
+	}
+	done := make(chan bool, 1)
+	for i := 0; i < n; i++ {
+		c1 := make(chan int, 1)
+		c2 := make(chan int)
+		c1 <- 1
+		go func() {
+			select {
+			case <-c1:
+			case <-c2:
+			default:
+				done <- false
+				return
+			}
+			done <- true
+		}()
+		close(c2)
+		select {
+		case <-c1:
+		default:
+		}
+		if !<-done {
+			t.Fatal("no chan is ready")
+		}
+	}
+}
+
 func TestSelfSelect(t *testing.T) {
 	// Ensure that send/recv on the same chan in select
 	// does not crash nor deadlock.
@@ -453,7 +528,7 @@
 func TestShrinkStackDuringBlockedSend(t *testing.T) {
 	// make sure that channel operations still work when we are
 	// blocked on a channel send and we shrink the stack.
-	// NOTE: this test probably won't fail unless stack.c:StackDebug
+	// NOTE: this test probably won't fail unless stack1.go:StackDebug
 	// is set to >= 1.
 	const n = 10
 	c := make(chan int)
diff --git a/src/runtime/cputicks.go b/src/runtime/cputicks.go
index e0593d5..162e026 100644
--- a/src/runtime/cputicks.go
+++ b/src/runtime/cputicks.go
@@ -3,6 +3,7 @@
 // license that can be found in the LICENSE file.
 
 // +build !arm
+// +build !arm64
 
 package runtime
 
diff --git a/src/runtime/crash_cgo_test.go b/src/runtime/crash_cgo_test.go
index f3b69ef..01ffed9 100644
--- a/src/runtime/crash_cgo_test.go
+++ b/src/runtime/crash_cgo_test.go
@@ -82,6 +82,18 @@
 	}
 }
 
+func TestCgoDLLImports(t *testing.T) {
+	// test issue 9356
+	if runtime.GOOS != "windows" {
+		t.Skip("skipping windows specific test")
+	}
+	got := executeTest(t, cgoDLLImportsMainSource, nil, "a/a.go", cgoDLLImportsPkgSource)
+	want := "OK\n"
+	if got != want {
+		t.Fatalf("expected %q, but got %v", want, got)
+	}
+}
+
 const cgoSignalDeadlockSource = `
 package main
 
@@ -269,3 +281,43 @@
 	println("OK")
 }
 `
+
+const cgoDLLImportsMainSource = `
+package main
+
+/*
+#include <windows.h>
+
+DWORD getthread() {
+	return GetCurrentThreadId();
+}
+*/
+import "C"
+
+import "./a"
+
+func main() {
+	C.getthread()
+	a.GetThread()
+	println("OK")
+}
+`
+
+const cgoDLLImportsPkgSource = `
+package a
+
+/*
+#cgo CFLAGS: -mnop-fun-dllimport
+
+#include <windows.h>
+
+DWORD agetthread() {
+	return GetCurrentThreadId();
+}
+*/
+import "C"
+
+func GetThread() uint32 {
+	return uint32(C.agetthread())
+}
+`
diff --git a/src/runtime/crash_test.go b/src/runtime/crash_test.go
index 5e26de3..7bb3d28 100644
--- a/src/runtime/crash_test.go
+++ b/src/runtime/crash_test.go
@@ -72,7 +72,14 @@
 	}
 
 	for i := 0; i < len(extra); i += 2 {
-		if err := ioutil.WriteFile(filepath.Join(dir, extra[i]), []byte(extra[i+1]), 0666); err != nil {
+		fname := extra[i]
+		contents := extra[i+1]
+		if d, _ := filepath.Split(fname); d != "" {
+			if err := os.Mkdir(filepath.Join(dir, d), 0755); err != nil {
+				t.Fatal(err)
+			}
+		}
+		if err := ioutil.WriteFile(filepath.Join(dir, fname), []byte(contents), 0666); err != nil {
 			t.Fatal(err)
 		}
 	}
diff --git a/src/runtime/debug/stubs.s b/src/runtime/debug/stubs.s
index b117063..9dc8e54 100644
--- a/src/runtime/debug/stubs.s
+++ b/src/runtime/debug/stubs.s
@@ -7,6 +7,9 @@
 #ifdef GOARCH_arm
 #define JMP B
 #endif
+#ifdef GOARCH_arm64
+#define JMP B
+#endif
 #ifdef GOARCH_ppc64
 #define JMP BR
 #endif
diff --git a/src/runtime/defs_darwin_386.go b/src/runtime/defs_darwin_386.go
index cf4812f..e051301 100644
--- a/src/runtime/defs_darwin_386.go
+++ b/src/runtime/defs_darwin_386.go
@@ -174,7 +174,7 @@
 	si_pid    int32
 	si_uid    uint32
 	si_status int32
-	si_addr   *byte
+	si_addr   uint32
 	si_value  [4]byte
 	si_band   int32
 	__pad     [7]uint32
diff --git a/src/runtime/defs_darwin_amd64.go b/src/runtime/defs_darwin_amd64.go
index 2cd4c0c..d9d9fc5 100644
--- a/src/runtime/defs_darwin_amd64.go
+++ b/src/runtime/defs_darwin_amd64.go
@@ -175,7 +175,7 @@
 	si_pid    int32
 	si_uid    uint32
 	si_status int32
-	si_addr   *byte
+	si_addr   uint64
 	si_value  [8]byte
 	si_band   int64
 	__pad     [7]uint64
diff --git a/src/runtime/defs_darwin_arm.go b/src/runtime/defs_darwin_arm.go
index 92bab50..b53336c 100644
--- a/src/runtime/defs_darwin_arm.go
+++ b/src/runtime/defs_darwin_arm.go
@@ -176,7 +176,7 @@
 	si_pid    int32
 	si_uid    uint32
 	si_status int32
-	si_addr   *byte
+	si_addr   uint32
 	si_value  [4]byte
 	si_band   int32
 	__pad     [7]uint32
diff --git a/src/runtime/defs_dragonfly.go b/src/runtime/defs_dragonfly.go
index 555b8f5..c5ebe75 100644
--- a/src/runtime/defs_dragonfly.go
+++ b/src/runtime/defs_dragonfly.go
@@ -8,7 +8,6 @@
 Input to cgo.
 
 GOARCH=amd64 go tool cgo -cdefs defs_dragonfly.go >defs_dragonfly_amd64.h
-GOARCH=386 go tool cgo -cdefs defs_dragonfly.go >defs_dragonfly_386.h
 */
 
 package runtime
diff --git a/src/runtime/defs_dragonfly_386.go b/src/runtime/defs_dragonfly_386.go
deleted file mode 100644
index e9c6353..0000000
--- a/src/runtime/defs_dragonfly_386.go
+++ /dev/null
@@ -1,198 +0,0 @@
-// created by cgo -cdefs and then converted to Go
-// cgo -cdefs defs_dragonfly.go
-
-package runtime
-
-import "unsafe"
-
-const (
-	_EINTR  = 0x4
-	_EFAULT = 0xe
-	_EBUSY  = 0x10
-	_EAGAIN = 0x23
-
-	_PROT_NONE  = 0x0
-	_PROT_READ  = 0x1
-	_PROT_WRITE = 0x2
-	_PROT_EXEC  = 0x4
-
-	_MAP_ANON    = 0x1000
-	_MAP_PRIVATE = 0x2
-	_MAP_FIXED   = 0x10
-
-	_MADV_FREE = 0x5
-
-	_SA_SIGINFO = 0x40
-	_SA_RESTART = 0x2
-	_SA_ONSTACK = 0x1
-
-	_SIGHUP    = 0x1
-	_SIGINT    = 0x2
-	_SIGQUIT   = 0x3
-	_SIGILL    = 0x4
-	_SIGTRAP   = 0x5
-	_SIGABRT   = 0x6
-	_SIGEMT    = 0x7
-	_SIGFPE    = 0x8
-	_SIGKILL   = 0x9
-	_SIGBUS    = 0xa
-	_SIGSEGV   = 0xb
-	_SIGSYS    = 0xc
-	_SIGPIPE   = 0xd
-	_SIGALRM   = 0xe
-	_SIGTERM   = 0xf
-	_SIGURG    = 0x10
-	_SIGSTOP   = 0x11
-	_SIGTSTP   = 0x12
-	_SIGCONT   = 0x13
-	_SIGCHLD   = 0x14
-	_SIGTTIN   = 0x15
-	_SIGTTOU   = 0x16
-	_SIGIO     = 0x17
-	_SIGXCPU   = 0x18
-	_SIGXFSZ   = 0x19
-	_SIGVTALRM = 0x1a
-	_SIGPROF   = 0x1b
-	_SIGWINCH  = 0x1c
-	_SIGINFO   = 0x1d
-	_SIGUSR1   = 0x1e
-	_SIGUSR2   = 0x1f
-
-	_FPE_INTDIV = 0x2
-	_FPE_INTOVF = 0x1
-	_FPE_FLTDIV = 0x3
-	_FPE_FLTOVF = 0x4
-	_FPE_FLTUND = 0x5
-	_FPE_FLTRES = 0x6
-	_FPE_FLTINV = 0x7
-	_FPE_FLTSUB = 0x8
-
-	_BUS_ADRALN = 0x1
-	_BUS_ADRERR = 0x2
-	_BUS_OBJERR = 0x3
-
-	_SEGV_MAPERR = 0x1
-	_SEGV_ACCERR = 0x2
-
-	_ITIMER_REAL    = 0x0
-	_ITIMER_VIRTUAL = 0x1
-	_ITIMER_PROF    = 0x2
-
-	_EV_ADD       = 0x1
-	_EV_DELETE    = 0x2
-	_EV_CLEAR     = 0x20
-	_EV_ERROR     = 0x4000
-	_EVFILT_READ  = -0x1
-	_EVFILT_WRITE = -0x2
-)
-
-type rtprio struct {
-	_type uint16
-	prio  uint16
-}
-
-type lwpparams struct {
-	start_func uintptr
-	arg        unsafe.Pointer
-	stack      uintptr
-	tid1       unsafe.Pointer // *int32
-	tid2       unsafe.Pointer // *int32
-}
-
-type sigaltstackt struct {
-	ss_sp    uintptr
-	ss_size  uintptr
-	ss_flags int32
-}
-
-type sigset struct {
-	__bits [4]uint32
-}
-
-type stackt struct {
-	ss_sp    uintptr
-	ss_size  uintptr
-	ss_flags int32
-}
-
-type siginfo struct {
-	si_signo  int32
-	si_errno  int32
-	si_code   int32
-	si_pid    int32
-	si_uid    uint32
-	si_status int32
-	si_addr   uintptr
-	si_value  [4]byte
-	si_band   int32
-	__spare__ [7]int32
-}
-
-type mcontext struct {
-	mc_onstack  uint32
-	mc_gs       uint32
-	mc_fs       uint32
-	mc_es       uint32
-	mc_ds       uint32
-	mc_edi      uint32
-	mc_esi      uint32
-	mc_ebp      uint32
-	mc_isp      uint32
-	mc_ebx      uint32
-	mc_edx      uint32
-	mc_ecx      uint32
-	mc_eax      uint32
-	mc_xflags   uint32
-	mc_trapno   uint32
-	mc_err      uint32
-	mc_eip      uint32
-	mc_cs       uint32
-	mc_eflags   uint32
-	mc_esp      uint32
-	mc_ss       uint32
-	mc_len      uint32
-	mc_fpformat uint32
-	mc_ownedfp  uint32
-	mc_fpregs   [128]uint32
-	__spare__   [16]uint32
-}
-
-type ucontext struct {
-	uc_sigmask  sigset
-	uc_mcontext mcontext
-	uc_link     *ucontext
-	uc_stack    stackt
-	__spare__   [8]int32
-}
-
-type timespec struct {
-	tv_sec  int32
-	tv_nsec int32
-}
-
-func (ts *timespec) set_sec(x int64) {
-	ts.tv_sec = int32(x)
-}
-
-type timeval struct {
-	tv_sec  int32
-	tv_usec int32
-}
-
-func (tv *timeval) set_usec(x int32) {
-	tv.tv_usec = x
-}
-
-type itimerval struct {
-	it_interval timeval
-	it_value    timeval
-}
-
-type keventt struct {
-	ident  uint32
-	filter int16
-	flags  uint16
-	fflags uint32
-	data   int32
-	udata  *byte
-}
diff --git a/src/runtime/defs_linux_arm64.go b/src/runtime/defs_linux_arm64.go
new file mode 100644
index 0000000..1a4d884
--- /dev/null
+++ b/src/runtime/defs_linux_arm64.go
@@ -0,0 +1,178 @@
+// Created by cgo -cdefs and converted (by hand) to Go
+// ../cmd/cgo/cgo -cdefs defs_linux.go defs1_linux.go defs2_linux.go
+
+package runtime
+
+const (
+	_EINTR  = 0x4
+	_EAGAIN = 0xb
+	_ENOMEM = 0xc
+
+	_PROT_NONE  = 0x0
+	_PROT_READ  = 0x1
+	_PROT_WRITE = 0x2
+	_PROT_EXEC  = 0x4
+
+	_MAP_ANON    = 0x20
+	_MAP_PRIVATE = 0x2
+	_MAP_FIXED   = 0x10
+
+	_MADV_DONTNEED   = 0x4
+	_MADV_HUGEPAGE   = 0xe
+	_MADV_NOHUGEPAGE = 0xf
+
+	_SA_RESTART  = 0x10000000
+	_SA_ONSTACK  = 0x8000000
+	_SA_RESTORER = 0x0 // Only used on intel
+	_SA_SIGINFO  = 0x4
+
+	_SIGHUP    = 0x1
+	_SIGINT    = 0x2
+	_SIGQUIT   = 0x3
+	_SIGILL    = 0x4
+	_SIGTRAP   = 0x5
+	_SIGABRT   = 0x6
+	_SIGBUS    = 0x7
+	_SIGFPE    = 0x8
+	_SIGKILL   = 0x9
+	_SIGUSR1   = 0xa
+	_SIGSEGV   = 0xb
+	_SIGUSR2   = 0xc
+	_SIGPIPE   = 0xd
+	_SIGALRM   = 0xe
+	_SIGSTKFLT = 0x10
+	_SIGCHLD   = 0x11
+	_SIGCONT   = 0x12
+	_SIGSTOP   = 0x13
+	_SIGTSTP   = 0x14
+	_SIGTTIN   = 0x15
+	_SIGTTOU   = 0x16
+	_SIGURG    = 0x17
+	_SIGXCPU   = 0x18
+	_SIGXFSZ   = 0x19
+	_SIGVTALRM = 0x1a
+	_SIGPROF   = 0x1b
+	_SIGWINCH  = 0x1c
+	_SIGIO     = 0x1d
+	_SIGPWR    = 0x1e
+	_SIGSYS    = 0x1f
+
+	_FPE_INTDIV = 0x1
+	_FPE_INTOVF = 0x2
+	_FPE_FLTDIV = 0x3
+	_FPE_FLTOVF = 0x4
+	_FPE_FLTUND = 0x5
+	_FPE_FLTRES = 0x6
+	_FPE_FLTINV = 0x7
+	_FPE_FLTSUB = 0x8
+
+	_BUS_ADRALN = 0x1
+	_BUS_ADRERR = 0x2
+	_BUS_OBJERR = 0x3
+
+	_SEGV_MAPERR = 0x1
+	_SEGV_ACCERR = 0x2
+
+	_ITIMER_REAL    = 0x0
+	_ITIMER_VIRTUAL = 0x1
+	_ITIMER_PROF    = 0x2
+
+	_EPOLLIN       = 0x1
+	_EPOLLOUT      = 0x4
+	_EPOLLERR      = 0x8
+	_EPOLLHUP      = 0x10
+	_EPOLLRDHUP    = 0x2000
+	_EPOLLET       = 0x80000000
+	_EPOLL_CLOEXEC = 0x80000
+	_EPOLL_CTL_ADD = 0x1
+	_EPOLL_CTL_DEL = 0x2
+	_EPOLL_CTL_MOD = 0x3
+)
+
+type timespec struct {
+	tv_sec  int64
+	tv_nsec int64
+}
+
+func (ts *timespec) set_sec(x int64) {
+	ts.tv_sec = x
+}
+
+func (ts *timespec) set_nsec(x int32) {
+	ts.tv_nsec = int64(x)
+}
+
+type timeval struct {
+	tv_sec  int64
+	tv_usec int64
+}
+
+func (tv *timeval) set_usec(x int32) {
+	tv.tv_usec = int64(x)
+}
+
+type sigactiont struct {
+	sa_handler  uintptr
+	sa_flags    uint64
+	sa_restorer uintptr
+	sa_mask     uint64
+}
+
+type siginfo struct {
+	si_signo int32
+	si_errno int32
+	si_code  int32
+	// below here is a union; si_addr is the only field we use
+	si_addr uint64
+}
+
+type itimerval struct {
+	it_interval timeval
+	it_value    timeval
+}
+
+type epollevent struct {
+	events uint32
+	_pad   uint32
+	data   [8]byte // to match amd64
+}
+
+// Created by cgo -cdefs and then converted to Go by hand
+// ../cmd/cgo/cgo -cdefs defs_linux.go defs1_linux.go defs2_linux.go
+
+const (
+	_O_RDONLY  = 0x0
+	_O_CLOEXEC = 0x80000
+)
+
+type usigset struct {
+	__val [16]uint64
+}
+
+type sigaltstackt struct {
+	ss_sp     *byte
+	ss_flags  int32
+	pad_cgo_0 [4]byte
+	ss_size   uintptr
+}
+
+type sigcontext struct {
+	fault_address uint64
+	/* AArch64 registers */
+	regs       [31]uint64
+	sp         uint64
+	pc         uint64
+	pstate     uint64
+	_pad       [8]byte // __attribute__((__aligned__(16)))
+	__reserved [4096]byte
+}
+
+type ucontext struct {
+	uc_flags    uint64
+	uc_link     *ucontext
+	uc_stack    sigaltstackt
+	uc_sigmask  uint64
+	_pad        [(1024 - 64) / 8]byte
+	_pad2       [8]byte // sigcontext must be aligned to 16-byte
+	uc_mcontext sigcontext
+}
diff --git a/src/runtime/defs_openbsd_arm.go b/src/runtime/defs_openbsd_arm.go
new file mode 100644
index 0000000..aab9276
--- /dev/null
+++ b/src/runtime/defs_openbsd_arm.go
@@ -0,0 +1,170 @@
+// created by cgo -cdefs and then converted to Go
+// cgo -cdefs defs_openbsd.go
+
+package runtime
+
+import "unsafe"
+
+const (
+	_EINTR  = 0x4
+	_EFAULT = 0xe
+
+	_PROT_NONE  = 0x0
+	_PROT_READ  = 0x1
+	_PROT_WRITE = 0x2
+	_PROT_EXEC  = 0x4
+
+	_MAP_ANON    = 0x1000
+	_MAP_PRIVATE = 0x2
+	_MAP_FIXED   = 0x10
+
+	_MADV_FREE = 0x6
+
+	_SA_SIGINFO = 0x40
+	_SA_RESTART = 0x2
+	_SA_ONSTACK = 0x1
+
+	_SIGHUP    = 0x1
+	_SIGINT    = 0x2
+	_SIGQUIT   = 0x3
+	_SIGILL    = 0x4
+	_SIGTRAP   = 0x5
+	_SIGABRT   = 0x6
+	_SIGEMT    = 0x7
+	_SIGFPE    = 0x8
+	_SIGKILL   = 0x9
+	_SIGBUS    = 0xa
+	_SIGSEGV   = 0xb
+	_SIGSYS    = 0xc
+	_SIGPIPE   = 0xd
+	_SIGALRM   = 0xe
+	_SIGTERM   = 0xf
+	_SIGURG    = 0x10
+	_SIGSTOP   = 0x11
+	_SIGTSTP   = 0x12
+	_SIGCONT   = 0x13
+	_SIGCHLD   = 0x14
+	_SIGTTIN   = 0x15
+	_SIGTTOU   = 0x16
+	_SIGIO     = 0x17
+	_SIGXCPU   = 0x18
+	_SIGXFSZ   = 0x19
+	_SIGVTALRM = 0x1a
+	_SIGPROF   = 0x1b
+	_SIGWINCH  = 0x1c
+	_SIGINFO   = 0x1d
+	_SIGUSR1   = 0x1e
+	_SIGUSR2   = 0x1f
+
+	_FPE_INTDIV = 0x1
+	_FPE_INTOVF = 0x2
+	_FPE_FLTDIV = 0x3
+	_FPE_FLTOVF = 0x4
+	_FPE_FLTUND = 0x5
+	_FPE_FLTRES = 0x6
+	_FPE_FLTINV = 0x7
+	_FPE_FLTSUB = 0x8
+
+	_BUS_ADRALN = 0x1
+	_BUS_ADRERR = 0x2
+	_BUS_OBJERR = 0x3
+
+	_SEGV_MAPERR = 0x1
+	_SEGV_ACCERR = 0x2
+
+	_ITIMER_REAL    = 0x0
+	_ITIMER_VIRTUAL = 0x1
+	_ITIMER_PROF    = 0x2
+
+	_EV_ADD       = 0x1
+	_EV_DELETE    = 0x2
+	_EV_CLEAR     = 0x20
+	_EV_ERROR     = 0x4000
+	_EVFILT_READ  = -0x1
+	_EVFILT_WRITE = -0x2
+)
+
+type tforkt struct {
+	tf_tcb   unsafe.Pointer
+	tf_tid   *int32
+	tf_stack uintptr
+}
+
+type sigaltstackt struct {
+	ss_sp    uintptr
+	ss_size  uintptr
+	ss_flags int32
+}
+
+type sigcontext struct {
+	__sc_unused int32
+	sc_mask     int32
+
+	sc_spsr   uint32
+	sc_r0     uint32
+	sc_r1     uint32
+	sc_r2     uint32
+	sc_r3     uint32
+	sc_r4     uint32
+	sc_r5     uint32
+	sc_r6     uint32
+	sc_r7     uint32
+	sc_r8     uint32
+	sc_r9     uint32
+	sc_r10    uint32
+	sc_r11    uint32
+	sc_r12    uint32
+	sc_usr_sp uint32
+	sc_usr_lr uint32
+	sc_svc_lr uint32
+	sc_pc     uint32
+}
+
+type siginfo struct {
+	si_signo int32
+	si_code  int32
+	si_errno int32
+	_data    [116]byte
+}
+
+type stackt struct {
+	ss_sp    uintptr
+	ss_size  uintptr
+	ss_flags int32
+}
+
+type timespec struct {
+	tv_sec  int64
+	tv_nsec int32
+}
+
+func (ts *timespec) set_sec(x int64) {
+	ts.tv_sec = x
+}
+
+func (ts *timespec) set_nsec(x int32) {
+	ts.tv_nsec = x
+}
+
+type timeval struct {
+	tv_sec  int64
+	tv_usec int32
+}
+
+func (tv *timeval) set_usec(x int32) {
+	tv.tv_usec = x
+}
+
+type itimerval struct {
+	it_interval timeval
+	it_value    timeval
+}
+
+type keventt struct {
+	ident  uint32
+	filter int16
+	flags  uint16
+	fflags uint32
+	data   int64
+	udata  *byte
+}
diff --git a/src/runtime/env_plan9.go b/src/runtime/env_plan9.go
index ec50cac..b988020 100644
--- a/src/runtime/env_plan9.go
+++ b/src/runtime/env_plan9.go
@@ -6,15 +6,6 @@
 
 import "unsafe"
 
-func getenv(s *byte) *byte {
-	val := gogetenv(gostringnocopy(s))
-	if val == "" {
-		return nil
-	}
-	// Strings found in environment are NUL-terminated.
-	return &bytes(val)[0]
-}
-
 var tracebackbuf [128]byte
 
 func gogetenv(key string) string {
diff --git a/src/runtime/env_posix.go b/src/runtime/env_posix.go
index b6567d3..5e49287 100644
--- a/src/runtime/env_posix.go
+++ b/src/runtime/env_posix.go
@@ -8,15 +8,6 @@
 
 import "unsafe"
 
-func getenv(s *byte) *byte {
-	val := gogetenv(gostringnocopy(s))
-	if val == "" {
-		return nil
-	}
-	// Strings found in environment are NUL-terminated.
-	return &bytes(val)[0]
-}
-
 func gogetenv(key string) string {
 	env := environ()
 	if env == nil {
diff --git a/src/runtime/env_test.go b/src/runtime/env_test.go
new file mode 100644
index 0000000..203f380
--- /dev/null
+++ b/src/runtime/env_test.go
@@ -0,0 +1,41 @@
+// Copyright 2015 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 runtime_test
+
+import (
+	"runtime"
+	"syscall"
+	"testing"
+)
+
+func TestFixedGOROOT(t *testing.T) {
+	if runtime.GOOS == "plan9" {
+		t.Skipf("skipping plan9, it is inconsistent by allowing GOROOT to be updated by Setenv")
+	}
+
+	envs := runtime.Envs()
+	oldenvs := append([]string{}, envs...)
+	defer runtime.SetEnvs(oldenvs)
+
+	// attempt to reuse existing envs backing array.
+	want := runtime.GOROOT()
+	runtime.SetEnvs(append(envs[:0], "GOROOT="+want))
+
+	if got := runtime.GOROOT(); got != want {
+		t.Errorf(`initial runtime.GOROOT()=%q, want %q`, got, want)
+	}
+	if err := syscall.Setenv("GOROOT", "/os"); err != nil {
+		t.Fatal(err)
+	}
+	if got := runtime.GOROOT(); got != want {
+		t.Errorf(`after setenv runtime.GOROOT()=%q, want %q`, got, want)
+	}
+	if err := syscall.Unsetenv("GOROOT"); err != nil {
+		t.Fatal(err)
+	}
+	if got := runtime.GOROOT(); got != want {
+		t.Errorf(`after unsetenv runtime.GOROOT()=%q, want %q`, got, want)
+	}
+}
diff --git a/src/runtime/error.go b/src/runtime/error.go
index 0b40c70..4280306 100644
--- a/src/runtime/error.go
+++ b/src/runtime/error.go
@@ -11,9 +11,9 @@
 	error
 
 	// RuntimeError is a no-op function but
-	// serves to distinguish types that are runtime
+	// serves to distinguish types that are run time
 	// errors from ordinary errors: a type is a
-	// runtime error if it has a RuntimeError method.
+	// run time error if it has a RuntimeError method.
 	RuntimeError()
 }
 
@@ -43,25 +43,6 @@
 		": missing method " + e.missingMethod
 }
 
-// For calling from C.
-func newTypeAssertionError(ps1, ps2, ps3 *string, pmeth *string, ret *interface{}) {
-	var s1, s2, s3, meth string
-
-	if ps1 != nil {
-		s1 = *ps1
-	}
-	if ps2 != nil {
-		s2 = *ps2
-	}
-	if ps3 != nil {
-		s3 = *ps3
-	}
-	if pmeth != nil {
-		meth = *pmeth
-	}
-	*ret = &TypeAssertionError{s1, s2, s3, meth}
-}
-
 // An errorString represents a runtime error described by a single string.
 type errorString string
 
diff --git a/src/runtime/export_test.go b/src/runtime/export_test.go
index a5d923e..71fbcde 100644
--- a/src/runtime/export_test.go
+++ b/src/runtime/export_test.go
@@ -117,3 +117,11 @@
 var Maxstring = &maxstring
 
 type Uintreg uintreg
+
+var Open = open
+var Close = close
+var Read = read
+var Write = write
+
+func Envs() []string     { return envs }
+func SetEnvs(e []string) { envs = e }
diff --git a/src/runtime/gcinfo_test.go b/src/runtime/gcinfo_test.go
index 6d6b5e4..f353a4e 100644
--- a/src/runtime/gcinfo_test.go
+++ b/src/runtime/gcinfo_test.go
@@ -134,7 +134,7 @@
 			typeScalar, typeScalar, typeScalar, typeScalar, // t int; y uint16; u uint64
 			typePointer, typeDead, // i string
 		}
-	case "amd64", "ppc64", "ppc64le":
+	case "arm64", "amd64", "ppc64", "ppc64le":
 		return []byte{
 			typePointer,                        // q *int
 			typeScalar, typeScalar, typeScalar, // w byte; e [17]byte
diff --git a/src/runtime/hash64.go b/src/runtime/hash64.go
index d10b781..716db61 100644
--- a/src/runtime/hash64.go
+++ b/src/runtime/hash64.go
@@ -6,7 +6,7 @@
 //   xxhash: https://code.google.com/p/xxhash/
 // cityhash: https://code.google.com/p/cityhash/
 
-// +build amd64 amd64p32 ppc64 ppc64le
+// +build amd64 amd64p32 arm64 ppc64 ppc64le
 
 package runtime
 
diff --git a/src/runtime/hashmap.go b/src/runtime/hashmap.go
index ca049dd..aaaef48 100644
--- a/src/runtime/hashmap.go
+++ b/src/runtime/hashmap.go
@@ -68,7 +68,7 @@
 	// Maximum key or value size to keep inline (instead of mallocing per element).
 	// Must fit in a uint8.
 	// Fast versions cannot handle big values - the cutoff size for
-	// fast versions in ../../cmd/gc/walk.c must be at most this value.
+	// fast versions in ../../cmd/internal/gc/walk.go must be at most this value.
 	maxKeySize   = 128
 	maxValueSize = 128
 
@@ -103,7 +103,7 @@
 
 // A header for a Go map.
 type hmap struct {
-	// Note: the format of the Hmap is encoded in ../../cmd/gc/reflect.c and
+	// Note: the format of the Hmap is encoded in ../../cmd/internal/gc/reflect.go and
 	// ../reflect/type.go.  Don't change this structure without also changing that code!
 	count int // # live cells == size of map.  Must be first (used by len() builtin)
 	flags uint8
@@ -137,11 +137,11 @@
 }
 
 // A hash iteration structure.
-// If you modify hiter, also change cmd/gc/reflect.c to indicate
+// If you modify hiter, also change cmd/internal/gc/reflect.go to indicate
 // the layout of this structure.
 type hiter struct {
-	key         unsafe.Pointer // Must be in first position.  Write nil to indicate iteration end (see cmd/gc/range.c).
-	value       unsafe.Pointer // Must be in second position (see cmd/gc/range.c).
+	key         unsafe.Pointer // Must be in first position.  Write nil to indicate iteration end (see cmd/internal/gc/range.go).
+	value       unsafe.Pointer // Must be in second position (see cmd/internal/gc/range.go).
 	t           *maptype
 	h           *hmap
 	buckets     unsafe.Pointer // bucket ptr at hash_iter initialization time
@@ -597,7 +597,7 @@
 	}
 
 	if unsafe.Sizeof(hiter{})/ptrSize != 12 {
-		throw("hash_iter size incorrect") // see ../../cmd/gc/reflect.c
+		throw("hash_iter size incorrect") // see ../../cmd/internal/gc/reflect.go
 	}
 	it.t = t
 	it.h = h
diff --git a/src/runtime/heapdump.go b/src/runtime/heapdump.go
index f577095..090a490 100644
--- a/src/runtime/heapdump.go
+++ b/src/runtime/heapdump.go
@@ -432,17 +432,17 @@
 
 func dumproots() {
 	// data segment
-	dumpbvtypes(&gcdatamask, unsafe.Pointer(&data))
+	dumpbvtypes(&gcdatamask, unsafe.Pointer(themoduledata.data))
 	dumpint(tagData)
-	dumpint(uint64(uintptr(unsafe.Pointer(&data))))
-	dumpmemrange(unsafe.Pointer(&data), uintptr(unsafe.Pointer(&edata))-uintptr(unsafe.Pointer(&data)))
+	dumpint(uint64(themoduledata.data))
+	dumpmemrange(unsafe.Pointer(themoduledata.data), themoduledata.edata-themoduledata.data)
 	dumpfields(gcdatamask)
 
 	// bss segment
-	dumpbvtypes(&gcbssmask, unsafe.Pointer(&bss))
+	dumpbvtypes(&gcbssmask, unsafe.Pointer(themoduledata.bss))
 	dumpint(tagBSS)
-	dumpint(uint64(uintptr(unsafe.Pointer(&bss))))
-	dumpmemrange(unsafe.Pointer(&bss), uintptr(unsafe.Pointer(&ebss))-uintptr(unsafe.Pointer(&bss)))
+	dumpint(uint64(themoduledata.bss))
+	dumpmemrange(unsafe.Pointer(themoduledata.bss), themoduledata.ebss-themoduledata.bss)
 	dumpfields(gcbssmask)
 
 	// MSpan.types
diff --git a/src/runtime/iface.go b/src/runtime/iface.go
index 811a31b..0d4989b 100644
--- a/src/runtime/iface.go
+++ b/src/runtime/iface.go
@@ -130,13 +130,15 @@
 	return tab
 }
 
-func convT2E(t *_type, elem unsafe.Pointer) (e interface{}) {
+func convT2E(t *_type, elem unsafe.Pointer, x unsafe.Pointer) (e interface{}) {
 	ep := (*eface)(unsafe.Pointer(&e))
 	if isDirectIface(t) {
 		ep._type = t
 		typedmemmove(t, unsafe.Pointer(&ep.data), elem)
 	} else {
-		x := newobject(t)
+		if x == nil {
+			x = newobject(t)
+		}
 		// TODO: We allocate a zeroed object only to overwrite it with
 		// actual data.  Figure out how to avoid zeroing.  Also below in convT2I.
 		typedmemmove(t, x, elem)
@@ -146,7 +148,7 @@
 	return
 }
 
-func convT2I(t *_type, inter *interfacetype, cache **itab, elem unsafe.Pointer) (i fInterface) {
+func convT2I(t *_type, inter *interfacetype, cache **itab, elem unsafe.Pointer, x unsafe.Pointer) (i fInterface) {
 	tab := (*itab)(atomicloadp(unsafe.Pointer(cache)))
 	if tab == nil {
 		tab = getitab(inter, t, false)
@@ -157,7 +159,9 @@
 		pi.tab = tab
 		typedmemmove(t, unsafe.Pointer(&pi.data), elem)
 	} else {
-		x := newobject(t)
+		if x == nil {
+			x = newobject(t)
+		}
 		typedmemmove(t, x, elem)
 		pi.tab = tab
 		pi.data = x
@@ -165,6 +169,14 @@
 	return
 }
 
+func panicdottype(have, want, iface *_type) {
+	haveString := ""
+	if have != nil {
+		haveString = *have._string
+	}
+	panic(&TypeAssertionError{*iface._string, haveString, *want._string, ""})
+}
+
 func assertI2T(t *_type, i fInterface, r unsafe.Pointer) {
 	ip := (*iface)(unsafe.Pointer(&i))
 	tab := ip.tab
@@ -219,20 +231,17 @@
 	}
 }
 
+// The compiler ensures that r is non-nil.
 func assertE2T2(t *_type, e interface{}, r unsafe.Pointer) bool {
 	ep := (*eface)(unsafe.Pointer(&e))
 	if ep._type != t {
-		if r != nil {
-			memclr(r, uintptr(t.size))
-		}
+		memclr(r, uintptr(t.size))
 		return false
 	}
-	if r != nil {
-		if isDirectIface(t) {
-			writebarrierptr((*uintptr)(r), uintptr(ep.data))
-		} else {
-			typedmemmove(t, r, ep.data)
-		}
+	if isDirectIface(t) {
+		writebarrierptr((*uintptr)(r), uintptr(ep.data))
+	} else {
+		typedmemmove(t, r, ep.data)
 	}
 	return true
 }
@@ -262,17 +271,16 @@
 	return
 }
 
+// The compiler ensures that r is non-nil.
 func assertI2E2(inter *interfacetype, i fInterface, r *interface{}) bool {
 	ip := (*iface)(unsafe.Pointer(&i))
 	tab := ip.tab
 	if tab == nil {
 		return false
 	}
-	if r != nil {
-		rp := (*eface)(unsafe.Pointer(r))
-		rp._type = tab._type
-		rp.data = ip.data
-	}
+	rp := (*eface)(unsafe.Pointer(r))
+	rp._type = tab._type
+	rp.data = ip.data
 	return true
 }
 
@@ -386,17 +394,14 @@
 	*r = e
 }
 
+// The compiler ensures that r is non-nil.
 func assertE2E2(inter *interfacetype, e interface{}, r *interface{}) bool {
 	ep := (*eface)(unsafe.Pointer(&e))
 	if ep._type == nil {
-		if r != nil {
-			*r = nil
-		}
+		*r = nil
 		return false
 	}
-	if r != nil {
-		*r = e
-	}
+	*r = e
 	return true
 }
 
diff --git a/src/runtime/iface_test.go b/src/runtime/iface_test.go
index bfeb94b..7f27baa 100644
--- a/src/runtime/iface_test.go
+++ b/src/runtime/iface_test.go
@@ -37,6 +37,7 @@
 	ts TS
 	tm TM
 	tl TL
+	ok bool
 )
 
 // Issue 9370
@@ -178,3 +179,85 @@
 		e_ = e
 	}
 }
+
+func BenchmarkAssertE2T2(b *testing.B) {
+	e = tm
+	for i := 0; i < b.N; i++ {
+		tm, ok = e.(TM)
+	}
+}
+
+func BenchmarkAssertE2T2Blank(b *testing.B) {
+	e = tm
+	for i := 0; i < b.N; i++ {
+		_, ok = e.(TM)
+	}
+}
+
+func BenchmarkAssertI2E2(b *testing.B) {
+	i1 = tm
+	for i := 0; i < b.N; i++ {
+		e, ok = i1.(interface{})
+	}
+}
+
+func BenchmarkAssertI2E2Blank(b *testing.B) {
+	i1 = tm
+	for i := 0; i < b.N; i++ {
+		_, ok = i1.(interface{})
+	}
+}
+
+func BenchmarkAssertE2E2(b *testing.B) {
+	e = tm
+	for i := 0; i < b.N; i++ {
+		e_, ok = e.(interface{})
+	}
+}
+
+func BenchmarkAssertE2E2Blank(b *testing.B) {
+	e = tm
+	for i := 0; i < b.N; i++ {
+		_, ok = e.(interface{})
+	}
+}
+
+func TestNonEscapingConvT2E(t *testing.T) {
+	m := make(map[interface{}]bool)
+	m[42] = true
+	if !m[42] {
+		t.Fatalf("42 is not present in the map")
+	}
+	if m[0] {
+		t.Fatalf("0 is present in the map")
+	}
+
+	n := testing.AllocsPerRun(1000, func() {
+		if m[0] {
+			t.Fatalf("0 is present in the map")
+		}
+	})
+	if n != 0 {
+		t.Fatalf("want 0 allocs, got %v", n)
+	}
+}
+
+func TestNonEscapingConvT2I(t *testing.T) {
+	m := make(map[I1]bool)
+	m[TM(42)] = true
+	if !m[TM(42)] {
+		t.Fatalf("42 is not present in the map")
+	}
+	if m[TM(0)] {
+		t.Fatalf("0 is present in the map")
+	}
+
+	n := testing.AllocsPerRun(1000, func() {
+		if m[TM(0)] {
+			t.Fatalf("0 is present in the map")
+		}
+	})
+	if n != 0 {
+		t.Fatalf("want 0 allocs, got %v", n)
+	}
+}
diff --git a/src/runtime/lfstack_linux_arm64.go b/src/runtime/lfstack_linux_arm64.go
new file mode 100644
index 0000000..54cae39
--- /dev/null
+++ b/src/runtime/lfstack_linux_arm64.go
@@ -0,0 +1,25 @@
+// 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.
+
+package runtime
+
+import "unsafe"
+
+// In addition to the 16 bits taken from the top, we can take 3 from the
+// bottom, because node must be pointer-aligned, giving a total of 19 bits
+// of count.
+const (
+	addrBits = 48
+	cntBits  = 64 - addrBits + 3
+)
+
+func lfstackPack(node *lfnode, cnt uintptr) uint64 {
+	return uint64(uintptr(unsafe.Pointer(node)))<<(64-addrBits) | uint64(cnt&(1<<cntBits-1))
+}
+
+func lfstackUnpack(val uint64) (node *lfnode, cnt uintptr) {
+	node = (*lfnode)(unsafe.Pointer(uintptr(val >> cntBits << 3)))
+	cnt = uintptr(val & (1<<cntBits - 1))
+	return
+}
diff --git a/src/runtime/lock_sema.go b/src/runtime/lock_sema.go
index 47cb883..d9d91c9 100644
--- a/src/runtime/lock_sema.go
+++ b/src/runtime/lock_sema.go
@@ -72,7 +72,7 @@
 			// for this lock, chained through m->nextwaitm.
 			// Queue this M.
 			for {
-				gp.m.nextwaitm = (*m)((unsafe.Pointer)(v &^ locked))
+				gp.m.nextwaitm = v &^ locked
 				if casuintptr(&l.key, v, uintptr(unsafe.Pointer(gp.m))|locked) {
 					break
 				}
@@ -90,6 +90,8 @@
 	}
 }
 
+//go:nowritebarrier
+// We might not be holding a p in this code.
 func unlock(l *mutex) {
 	gp := getg()
 	var mp *m
@@ -103,7 +105,7 @@
 			// Other M's are waiting for the lock.
 			// Dequeue an M.
 			mp = (*m)((unsafe.Pointer)(v &^ locked))
-			if casuintptr(&l.key, v, uintptr(unsafe.Pointer(mp.nextwaitm))) {
+			if casuintptr(&l.key, v, mp.nextwaitm) {
 				// Dequeued an M.  Wake it.
 				semawakeup(mp)
 				break
diff --git a/src/runtime/malloc.go b/src/runtime/malloc.go
index 6a2c85a..fde58e2 100644
--- a/src/runtime/malloc.go
+++ b/src/runtime/malloc.go
@@ -114,7 +114,7 @@
 	_64bit = 1 << (^uintptr(0) >> 63) / 2
 
 	// Computed constant.  The definition of MaxSmallSize and the
-	// algorithm in msize.c produce some number of different allocation
+	// algorithm in msize.go produces some number of different allocation
 	// size classes.  NumSizeClasses is that number.  It's needed here
 	// because there are static arrays of this length; when msize runs its
 	// size choosing algorithm it double-checks that NumSizeClasses agrees.
@@ -253,12 +253,20 @@
 		// but it hardly matters: e0 00 is not valid UTF-8 either.
 		//
 		// If this fails we fall back to the 32 bit memory mechanism
+		//
+		// However, on arm64, we ignore all this advice above and slam the
+		// allocation at 0x40 << 32 because when using 4k pages with 3-level
+		// translation buffers, the user address space is limited to 39 bits
 		arenaSize := round(_MaxMem, _PageSize)
 		bitmapSize = arenaSize / (ptrSize * 8 / 4)
 		spansSize = arenaSize / _PageSize * ptrSize
 		spansSize = round(spansSize, _PageSize)
 		for i := 0; i <= 0x7f; i++ {
-			p = uintptr(i)<<40 | uintptrMask&(0x00c0<<32)
+			if GOARCH == "arm64" {
+				p = uintptr(i)<<40 | uintptrMask&(0x0040<<32)
+			} else {
+				p = uintptr(i)<<40 | uintptrMask&(0x00c0<<32)
+			}
 			pSize = bitmapSize + spansSize + arenaSize + _PageSize
 			p = uintptr(sysReserve(unsafe.Pointer(p), pSize, &reserved))
 			if p != 0 {
@@ -314,7 +322,7 @@
 			// So adjust it upward a little bit ourselves: 1/4 MB to get
 			// away from the running binary image and then round up
 			// to a MB boundary.
-			p = round(uintptr(unsafe.Pointer(&end))+(1<<18), 1<<20)
+			p = round(themoduledata.end+(1<<18), 1<<20)
 			pSize = bitmapSize + spansSize + arenaSize + _PageSize
 			p = uintptr(sysReserve(unsafe.Pointer(p), pSize, &reserved))
 			if p != 0 {
@@ -472,16 +480,26 @@
 // Small objects are allocated from the per-P cache's free lists.
 // Large objects (> 32 kB) are allocated straight from the heap.
 func mallocgc(size uintptr, typ *_type, flags uint32) unsafe.Pointer {
-	shouldhelpgc := false
+	if gcphase == _GCmarktermination {
+		throw("mallocgc called with gcphase == _GCmarktermination")
+	}
+
 	if size == 0 {
 		return unsafe.Pointer(&zerobase)
 	}
-	dataSize := size
 
 	if flags&flagNoScan == 0 && typ == nil {
 		throw("malloc missing type")
 	}
 
+	if debug.sbrk != 0 {
+		align := uintptr(16)
+		if typ != nil {
+			align = uintptr(typ.align)
+		}
+		return persistentalloc(size, align, &memstats.other_sys)
+	}
+
 	// Set mp.mallocing to keep from being preempted by GC.
 	mp := acquirem()
 	if mp.mallocing != 0 {
@@ -489,6 +507,8 @@
 	}
 	mp.mallocing = 1
 
+	shouldhelpgc := false
+	dataSize := size
 	c := gomcache()
 	var s *mspan
 	var x unsafe.Pointer
@@ -750,12 +770,16 @@
 	mProf_Malloc(x, size)
 }
 
-var persistent struct {
-	lock mutex
+type persistentAlloc struct {
 	base unsafe.Pointer
 	off  uintptr
 }
 
+var globalAlloc struct {
+	mutex
+	persistentAlloc
+}
+
 // Wrapper around sysAlloc that can allocate small chunks.
 // There is no associated free operation.
 // Intended for things like function/type/debug-related persistent data.
@@ -784,19 +808,31 @@
 		return sysAlloc(size, stat)
 	}
 
-	lock(&persistent.lock)
+	mp := acquirem()
+	var persistent *persistentAlloc
+	if mp != nil && mp.p != nil {
+		persistent = &mp.p.palloc
+	} else {
+		lock(&globalAlloc.mutex)
+		persistent = &globalAlloc.persistentAlloc
+	}
 	persistent.off = round(persistent.off, align)
 	if persistent.off+size > chunk || persistent.base == nil {
 		persistent.base = sysAlloc(chunk, &memstats.other_sys)
 		if persistent.base == nil {
-			unlock(&persistent.lock)
+			if persistent == &globalAlloc.persistentAlloc {
+				unlock(&globalAlloc.mutex)
+			}
 			throw("runtime: cannot allocate memory")
 		}
 		persistent.off = 0
 	}
 	p := add(persistent.base, persistent.off)
 	persistent.off += size
-	unlock(&persistent.lock)
+	releasem(mp)
+	if persistent == &globalAlloc.persistentAlloc {
+		unlock(&globalAlloc.mutex)
+	}
 
 	if stat != &memstats.other_sys {
 		xadd64(stat, int64(size))
diff --git a/src/runtime/mbarrier.go b/src/runtime/mbarrier.go
index f6e9269..e6183e7 100644
--- a/src/runtime/mbarrier.go
+++ b/src/runtime/mbarrier.go
@@ -53,11 +53,13 @@
 //
 // ld r1, [slotmark]       ld r2, [slot]
 //
-// This is a classic example of independent reads of independent writes,
-// aka IRIW. The question is if r1==r2==0 is allowed and for most HW the
-// answer is yes without inserting a memory barriers between the st and the ld.
-// These barriers are expensive so we have decided that we will
-// always grey the ptr object regardless of the slot's color.
+// Without an expensive memory barrier between the st and the ld, the final
+// result on most HW (including 386/amd64) can be r1==r2==0. This is a classic
+// example of what can happen when loads are allowed to be reordered with older
+// stores (avoiding such reorderings lies at the heart of the classic
+// Peterson/Dekker algorithms for mutual exclusion). Rather than require memory
+// barriers, which will slow down both the mutator and the GC, we always grey
+// the ptr object regardless of the slot's color.
 //go:nowritebarrier
 func gcmarkwb_m(slot *uintptr, ptr uintptr) {
 	switch gcphase {
@@ -81,6 +83,19 @@
 	return gcphase == _GCmark || gcphase == _GCmarktermination || mheap_.shadow_enabled
 }
 
+// Write barrier calls must not happen during critical GC and scheduler
+// related operations. In particular there are times when the GC assumes
+// that the world is stopped but scheduler related code is still being
+// executed, dealing with syscalls, dealing with putting gs on runnable
+// queues and so forth. This code can not execute write barriers because
+// the GC might drop them on the floor. Stopping the world involves removing
+// the p associated with an m. We use the fact that m.p == nil to indicate
+// that we are in one these critical section and throw if the write is of
+// a pointer to a heap object.
+// The p, m, and g pointers are the pointers that are used by the scheduler
+// and need to be operated on without write barriers. We use
+// the setPNoWriteBarrier, setMNoWriteBarrier and setGNowriteBarrier to
+// avoid having to do the write barrier.
 //go:nosplit
 func writebarrierptr_nostore1(dst *uintptr, src uintptr) {
 	mp := acquirem()
@@ -88,8 +103,11 @@
 		releasem(mp)
 		return
 	}
-	mp.inwb = true
 	systemstack(func() {
+		if mp.p == nil && memstats.enablegc && !mp.inwb && inheap(src) {
+			throw("writebarrierptr_nostore1 called with mp.p == nil")
+		}
+		mp.inwb = true
 		gcmarkwb_m(dst, src)
 	})
 	mp.inwb = false
@@ -410,29 +428,29 @@
 	mheap_.shadow_reserved = reserved
 	start := ^uintptr(0)
 	end := uintptr(0)
-	if start > uintptr(unsafe.Pointer(&noptrdata)) {
-		start = uintptr(unsafe.Pointer(&noptrdata))
+	if start > themoduledata.noptrdata {
+		start = themoduledata.noptrdata
 	}
-	if start > uintptr(unsafe.Pointer(&data)) {
-		start = uintptr(unsafe.Pointer(&data))
+	if start > themoduledata.data {
+		start = themoduledata.data
 	}
-	if start > uintptr(unsafe.Pointer(&noptrbss)) {
-		start = uintptr(unsafe.Pointer(&noptrbss))
+	if start > themoduledata.noptrbss {
+		start = themoduledata.noptrbss
 	}
-	if start > uintptr(unsafe.Pointer(&bss)) {
-		start = uintptr(unsafe.Pointer(&bss))
+	if start > themoduledata.bss {
+		start = themoduledata.bss
 	}
-	if end < uintptr(unsafe.Pointer(&enoptrdata)) {
-		end = uintptr(unsafe.Pointer(&enoptrdata))
+	if end < themoduledata.enoptrdata {
+		end = themoduledata.enoptrdata
 	}
-	if end < uintptr(unsafe.Pointer(&edata)) {
-		end = uintptr(unsafe.Pointer(&edata))
+	if end < themoduledata.edata {
+		end = themoduledata.edata
 	}
-	if end < uintptr(unsafe.Pointer(&enoptrbss)) {
-		end = uintptr(unsafe.Pointer(&enoptrbss))
+	if end < themoduledata.enoptrbss {
+		end = themoduledata.enoptrbss
 	}
-	if end < uintptr(unsafe.Pointer(&ebss)) {
-		end = uintptr(unsafe.Pointer(&ebss))
+	if end < themoduledata.ebss {
+		end = themoduledata.ebss
 	}
 	start &^= _PhysPageSize - 1
 	end = round(end, _PhysPageSize)
diff --git a/src/runtime/mbitmap.go b/src/runtime/mbitmap.go
index 4592044..ebee742 100644
--- a/src/runtime/mbitmap.go
+++ b/src/runtime/mbitmap.go
@@ -32,7 +32,7 @@
 // describe p and the high 4 bits describe p+ptrSize.
 //
 // The 4 bits for each word are:
-//	0001 - bitBoundary: this is the start of an object
+//	0001 - not used
 //	0010 - bitMarked: this object has been marked by GC
 //	tt00 - word type bits, as in a type bitmap.
 //
@@ -77,7 +77,6 @@
 
 	heapBitsWidth   = 4
 	heapBitmapScale = ptrSize * (8 / heapBitsWidth) // number of data bytes per heap bitmap byte
-	bitBoundary     = 1
 	bitMarked       = 2
 	typeShift       = 2
 )
@@ -151,30 +150,21 @@
 
 // heapBitsForObject returns the base address for the heap object
 // containing the address p, along with the heapBits for base.
-// If p does not point into a heap object, heapBitsForObject returns base == 0.
-func heapBitsForObject(p uintptr) (base uintptr, hbits heapBits) {
+// If p does not point into a heap object,
+// return base == 0
+// otherwise return the base of the object.
+func heapBitsForObject(p uintptr) (base uintptr, hbits heapBits, s *mspan) {
 	if p < mheap_.arena_start || p >= mheap_.arena_used {
 		return
 	}
 
-	// If heap bits for the pointer-sized word containing p have bitBoundary set,
-	// then we know this is the base of the object, and we can stop now.
-	// This handles the case where p is the base and, due to rounding
-	// when looking up the heap bits, also the case where p points beyond
-	// the base but still into the first pointer-sized word of the object.
-	hbits = heapBitsForAddr(p)
-	if hbits.isBoundary() {
-		base = p &^ (ptrSize - 1)
-		return
-	}
-
-	// Otherwise, p points into the middle of an object.
+	// p points into the heap, but possibly to the middle of an object.
 	// Consult the span table to find the block beginning.
 	// TODO(rsc): Factor this out.
 	k := p >> _PageShift
 	x := k
 	x -= mheap_.arena_start >> _PageShift
-	s := h_spans[x]
+	s = h_spans[x]
 	if s == nil || pageID(k) < s.start || p >= s.limit || s.state != mSpanInUse {
 		if s == nil || s.state == _MSpanStack {
 			// If s is nil, the virtual address has never been part of the heap.
@@ -202,21 +192,30 @@
 	}
 	base = s.base()
 	if p-base >= s.elemsize {
-		base += (p - base) / s.elemsize * s.elemsize
-	}
-	if base == p {
-		print("runtime: failed to find block beginning for ", hex(p), " s=", hex(s.start*_PageSize), " s.limit=", hex(s.limit), "\n")
-		throw("failed to find block beginning")
-	}
+		// n := (p - base) / s.elemsize, using division by multiplication
+		n := uintptr(uint64(p-base) >> s.divShift * uint64(s.divMul) >> s.divShift2)
 
+		const debugMagic = false
+		if debugMagic {
+			n2 := (p - base) / s.elemsize
+			if n != n2 {
+				println("runtime: bad div magic", (p - base), s.elemsize, s.divShift, s.divMul, s.divShift2)
+				throw("bad div magic")
+			}
+		}
+
+		base += n * s.elemsize
+	}
 	// Now that we know the actual base, compute heapBits to return to caller.
 	hbits = heapBitsForAddr(base)
-	if !hbits.isBoundary() {
-		throw("missing boundary at computed object start")
-	}
 	return
 }
 
+// prefetch the bits.
+func (h heapBits) prefetch() {
+	prefetchnta(uintptr(unsafe.Pointer((h.bitp))))
+}
+
 // next returns the heapBits describing the next pointer-sized word in memory.
 // That is, if h describes address p, h.next() describes p+ptrSize.
 // Note that next does not modify h. The caller must record the result.
@@ -246,14 +245,6 @@
 	*h.bitp |= bitMarked << h.shift
 }
 
-// isBoundary reports whether the heap bits have the boundary bit set.
-func (h heapBits) isBoundary() bool {
-	return *h.bitp&(bitBoundary<<h.shift) != 0
-}
-
-// Note that there is no setBoundary or setBoundaryNonAtomic.
-// Boundaries are always in bulk, for the entire span.
-
 // typeBits returns the heap bits' type bits.
 func (h heapBits) typeBits() uint8 {
 	return (*h.bitp >> (h.shift + typeShift)) & typeMask
@@ -287,60 +278,8 @@
 
 // initSpan initializes the heap bitmap for a span.
 func (h heapBits) initSpan(size, n, total uintptr) {
-	if size == ptrSize {
-		// Only possible on 64-bit system, since minimum size is 8.
-		// Set all nibbles to bitBoundary using uint64 writes.
-		nbyte := n * ptrSize / heapBitmapScale
-		nuint64 := nbyte / 8
-		bitp := subtractb(h.bitp, nbyte-1)
-		for i := uintptr(0); i < nuint64; i++ {
-			const boundary64 = bitBoundary |
-				bitBoundary<<4 |
-				bitBoundary<<8 |
-				bitBoundary<<12 |
-				bitBoundary<<16 |
-				bitBoundary<<20 |
-				bitBoundary<<24 |
-				bitBoundary<<28 |
-				bitBoundary<<32 |
-				bitBoundary<<36 |
-				bitBoundary<<40 |
-				bitBoundary<<44 |
-				bitBoundary<<48 |
-				bitBoundary<<52 |
-				bitBoundary<<56 |
-				bitBoundary<<60
-
-			*(*uint64)(unsafe.Pointer(bitp)) = boundary64
-			bitp = addb(bitp, 8)
-		}
-		return
-	}
-
-	if size*n < total {
-		// To detect end of object during GC object scan,
-		// add boundary just past end of last block.
-		// The object scan knows to stop when it reaches
-		// the end of the span, but in this case the object
-		// ends before the end of the span.
-		//
-		// TODO(rsc): If the bitmap bits were going to be typeDead
-		// otherwise, what's the point of this?
-		// Can we delete this logic?
-		n++
-	}
-	step := size / heapBitmapScale
-	bitp := h.bitp
-	for i := uintptr(0); i < n; i++ {
-		*bitp = bitBoundary
-		bitp = subtractb(bitp, step)
-	}
-}
-
-// clearSpan clears the heap bitmap bytes for the span.
-func (h heapBits) clearSpan(size, n, total uintptr) {
 	if total%heapBitmapScale != 0 {
-		throw("clearSpan: unaligned length")
+		throw("initSpan: unaligned length")
 	}
 	nbyte := total / heapBitmapScale
 	memclr(unsafe.Pointer(subtractb(h.bitp, nbyte-1)), nbyte)
@@ -359,9 +298,7 @@
 		bitp := h.bitp
 		for i := uintptr(0); i < n; i += 2 {
 			x := int(*bitp)
-			if x&0x11 != 0x11 {
-				throw("missing bitBoundary")
-			}
+
 			if (x>>typeShift)&typeMask == typeDead {
 				x += (typeScalar - typeDead) << typeShift
 			}
@@ -380,9 +317,6 @@
 	bitp := h.bitp
 	step := size / heapBitmapScale
 	for i := uintptr(0); i < n; i++ {
-		if *bitp&bitBoundary == 0 {
-			throw("missing bitBoundary")
-		}
 		x := *bitp
 		if (x>>typeShift)&typeMask == typeDead {
 			x += (typeScalar - typeDead) << typeShift
@@ -404,10 +338,6 @@
 		bitp := h.bitp
 		for i := uintptr(0); i < n; i += 2 {
 			x := int(*bitp)
-			if x&(bitBoundary|bitBoundary<<4) != (bitBoundary | bitBoundary<<4) {
-				throw("missing bitBoundary")
-			}
-
 			switch typ := (x >> typeShift) & typeMask; typ {
 			case typeScalar:
 				x += (typeDead - typeScalar) << typeShift
@@ -436,10 +366,6 @@
 	step := size / heapBitmapScale
 	for i := uintptr(0); i < n; i++ {
 		x := int(*bitp)
-		if x&bitBoundary == 0 {
-			throw("missing bitBoundary")
-		}
-
 		switch typ := (x >> typeShift) & typeMask; {
 		case typ == typeScalarCheckmarked && (x>>(4+typeShift))&typeMask != typeDead:
 			x += (typeScalar - typeScalarCheckmarked) << typeShift
@@ -491,7 +417,7 @@
 		if x&bitMarked != 0 {
 			x &^= bitMarked
 		} else {
-			x = bitBoundary // clear marked bit, set type bits to typeDead
+			x = 0
 			f(base + i*size)
 		}
 		*bitp = uint8(x)
@@ -510,10 +436,6 @@
 	// From here till marked label marking the object as allocated
 	// and storing type info in the GC bitmap.
 	h := heapBitsForAddr(x)
-	if debugMalloc && (*h.bitp>>h.shift)&0x0f != bitBoundary {
-		println("runtime: bits =", (*h.bitp>>h.shift)&0x0f)
-		throw("bad bits in markallocated")
-	}
 
 	var ti, te uintptr
 	var ptrmask *uint8
@@ -560,7 +482,8 @@
 		ptrmask = (*uint8)(unsafe.Pointer(typ.gc[0])) // pointer to unrolled mask
 	}
 	if size == 2*ptrSize {
-		*h.bitp = *ptrmask | bitBoundary
+		// h.shift is 0 for all sizes > ptrSize.
+		*h.bitp = *ptrmask
 		return
 	}
 	te = uintptr(typ.size) / ptrSize
@@ -569,15 +492,17 @@
 		te /= 2
 	}
 	// Copy pointer bitmask into the bitmap.
+	// TODO(rlh): add comment addressing the following concerns:
+	// If size > 2*ptrSize, is x guaranteed to be at least 2*ptrSize-aligned?
+	// And if type occupies and odd number of words, why are we only going through half
+	// of ptrmask and why don't we have to shift everything by 4 on odd iterations?
+
 	for i := uintptr(0); i < dataSize; i += 2 * ptrSize {
 		v := *(*uint8)(add(unsafe.Pointer(ptrmask), ti))
 		ti++
 		if ti == te {
 			ti = 0
 		}
-		if i == 0 {
-			v |= bitBoundary
-		}
 		if i+ptrSize == dataSize {
 			v &^= typeMask << (4 + typeShift)
 		}
@@ -771,12 +696,6 @@
 
 	// Mark first word as bitAllocated.
 	// Mark word after last as typeDead.
-	// TODO(rsc): Explain why we need to set this boundary.
-	// Aren't the boundaries always set for the whole span?
-	// Did unrollgcproc1 overwrite the boundary bit?
-	// Is that okay?
-	h := heapBitsForAddr(uintptr(v))
-	*h.bitp |= bitBoundary << h.shift
 	if size0 < size {
 		h := heapBitsForAddr(uintptr(v) + size0)
 		*h.bitp &^= typeMask << typeShift
@@ -828,12 +747,12 @@
 	const typeBitsPerByte = 8 / typeBitsWidth
 
 	// data
-	if uintptr(unsafe.Pointer(&data)) <= uintptr(p) && uintptr(p) < uintptr(unsafe.Pointer(&edata)) {
+	if themoduledata.data <= uintptr(p) && uintptr(p) < themoduledata.edata {
 		n := (*ptrtype)(unsafe.Pointer(t)).elem.size
 		*len = n / ptrSize
 		*mask = &make([]byte, *len)[0]
 		for i := uintptr(0); i < n; i += ptrSize {
-			off := (uintptr(p) + i - uintptr(unsafe.Pointer(&data))) / ptrSize
+			off := (uintptr(p) + i - themoduledata.data) / ptrSize
 			bits := (*(*byte)(add(unsafe.Pointer(gcdatamask.bytedata), off/typeBitsPerByte)) >> ((off % typeBitsPerByte) * typeBitsWidth)) & typeMask
 			*(*byte)(add(unsafe.Pointer(*mask), i/ptrSize)) = bits
 		}
@@ -841,12 +760,12 @@
 	}
 
 	// bss
-	if uintptr(unsafe.Pointer(&bss)) <= uintptr(p) && uintptr(p) < uintptr(unsafe.Pointer(&ebss)) {
+	if themoduledata.bss <= uintptr(p) && uintptr(p) < themoduledata.ebss {
 		n := (*ptrtype)(unsafe.Pointer(t)).elem.size
 		*len = n / ptrSize
 		*mask = &make([]byte, *len)[0]
 		for i := uintptr(0); i < n; i += ptrSize {
-			off := (uintptr(p) + i - uintptr(unsafe.Pointer(&bss))) / ptrSize
+			off := (uintptr(p) + i - themoduledata.bss) / ptrSize
 			bits := (*(*byte)(add(unsafe.Pointer(gcbssmask.bytedata), off/typeBitsPerByte)) >> ((off % typeBitsPerByte) * typeBitsWidth)) & typeMask
 			*(*byte)(add(unsafe.Pointer(*mask), i/ptrSize)) = bits
 		}
diff --git a/src/runtime/mcache.go b/src/runtime/mcache.go
index ec9ccb4..9ff4259 100644
--- a/src/runtime/mcache.go
+++ b/src/runtime/mcache.go
@@ -24,8 +24,6 @@
 
 	stackcache [_NumStackOrders]stackfreelist
 
-	sudogcache *sudog
-
 	// Local allocator stats, flushed during GC.
 	local_nlookup    uintptr                  // number of pointer lookups
 	local_largefree  uintptr                  // bytes freed for large objects (>maxsmallsize)
diff --git a/src/runtime/mcentral.go b/src/runtime/mcentral.go
index 965cd10..8aab903 100644
--- a/src/runtime/mcentral.go
+++ b/src/runtime/mcentral.go
@@ -4,7 +4,7 @@
 
 // Central free lists.
 //
-// See malloc.h for an overview.
+// See malloc.go for an overview.
 //
 // The MCentral doesn't actually contain the list of free objects; the MSpan does.
 // Each MCentral is two lists of MSpans: those with free objects (c->nonempty)
@@ -173,7 +173,7 @@
 	s.needzero = 1
 	s.freelist = 0
 	unlock(&c.lock)
-	heapBitsForSpan(s.base()).clearSpan(s.layout())
+	heapBitsForSpan(s.base()).initSpan(s.layout())
 	mHeap_Free(&mheap_, s, 0)
 	return true
 }
diff --git a/src/runtime/mem_plan9.go b/src/runtime/mem_plan9.go
index bf7d238..62c6a6f 100644
--- a/src/runtime/mem_plan9.go
+++ b/src/runtime/mem_plan9.go
@@ -116,7 +116,7 @@
 }
 
 func initBloc() {
-	bloc = memRound(uintptr(unsafe.Pointer(&end)))
+	bloc = memRound(themoduledata.end)
 }
 
 func sbrk(n uintptr) unsafe.Pointer {
diff --git a/src/runtime/memclr_arm64.s b/src/runtime/memclr_arm64.s
new file mode 100644
index 0000000..c44c123
--- /dev/null
+++ b/src/runtime/memclr_arm64.s
@@ -0,0 +1,18 @@
+// 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.
+
+#include "textflag.h"
+
+// void runtime·memclr(void*, uintptr)
+TEXT runtime·memclr(SB),NOSPLIT,$0-16
+	MOVD	ptr+0(FP), R3
+	MOVD	n+8(FP), R4
+	CMP	$0, R4
+	BEQ	done
+	ADD	R3, R4, R4
+	MOVBU.P	$0, 1(R3)
+	CMP	R3, R4
+	BNE	-2(PC)
+done:
+	RET
diff --git a/src/runtime/memmove_arm64.s b/src/runtime/memmove_arm64.s
new file mode 100644
index 0000000..66059a7
--- /dev/null
+++ b/src/runtime/memmove_arm64.s
@@ -0,0 +1,36 @@
+// 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.
+
+#include "textflag.h"
+
+// void runtime·memmove(void*, void*, uintptr)
+TEXT runtime·memmove(SB), NOSPLIT, $-8-24
+	MOVD	to+0(FP), R3
+	MOVD	from+8(FP), R4
+	MOVD	n+16(FP), R5
+	CMP	$0, R5
+	BNE	check
+	RET
+
+check:
+	CMP	R3, R4
+	BLT	backward
+
+	ADD	R3, R5
+loop:
+	MOVBU.P	1(R4), R6
+	MOVBU.P	R6, 1(R3)
+	CMP	R3, R5
+	BNE	loop
+	RET
+
+backward:
+	ADD	R5, R4
+	ADD	R3, R5
+loop1:
+	MOVBU.W	-1(R4), R6
+	MOVBU.W	R6, -1(R5)
+	CMP	R3, R5
+	BNE	loop1
+	RET
diff --git a/src/runtime/mfinal.go b/src/runtime/mfinal.go
index d066b60..2de7565 100644
--- a/src/runtime/mfinal.go
+++ b/src/runtime/mfinal.go
@@ -146,7 +146,7 @@
 			gp := getg()
 			fing = gp
 			fingwait = true
-			goparkunlock(&finlock, "finalizer wait", traceEvGoBlock)
+			goparkunlock(&finlock, "finalizer wait", traceEvGoBlock, 1)
 			continue
 		}
 		unlock(&finlock)
@@ -254,6 +254,11 @@
 // If a finalizer must run for a long time, it should do so by starting
 // a new goroutine.
 func SetFinalizer(obj interface{}, finalizer interface{}) {
+	if debug.sbrk != 0 {
+		// debug.sbrk never frees memory, so no finalizers run
+		// (and we don't have the data structures to record them).
+		return
+	}
 	e := (*eface)(unsafe.Pointer(&obj))
 	etyp := e._type
 	if etyp == nil {
@@ -284,10 +289,10 @@
 		// The relevant segments are: noptrdata, data, bss, noptrbss.
 		// We cannot assume they are in any order or even contiguous,
 		// due to external linking.
-		if uintptr(unsafe.Pointer(&noptrdata)) <= uintptr(e.data) && uintptr(e.data) < uintptr(unsafe.Pointer(&enoptrdata)) ||
-			uintptr(unsafe.Pointer(&data)) <= uintptr(e.data) && uintptr(e.data) < uintptr(unsafe.Pointer(&edata)) ||
-			uintptr(unsafe.Pointer(&bss)) <= uintptr(e.data) && uintptr(e.data) < uintptr(unsafe.Pointer(&ebss)) ||
-			uintptr(unsafe.Pointer(&noptrbss)) <= uintptr(e.data) && uintptr(e.data) < uintptr(unsafe.Pointer(&enoptrbss)) {
+		if themoduledata.noptrdata <= uintptr(e.data) && uintptr(e.data) < themoduledata.enoptrdata ||
+			themoduledata.data <= uintptr(e.data) && uintptr(e.data) < themoduledata.edata ||
+			themoduledata.bss <= uintptr(e.data) && uintptr(e.data) < themoduledata.ebss ||
+			themoduledata.noptrbss <= uintptr(e.data) && uintptr(e.data) < themoduledata.enoptrbss {
 			return
 		}
 		throw("runtime.SetFinalizer: pointer not in allocated block")
diff --git a/src/runtime/mfixalloc.go b/src/runtime/mfixalloc.go
index c1106b6..bb2f4e7 100644
--- a/src/runtime/mfixalloc.go
+++ b/src/runtime/mfixalloc.go
@@ -4,7 +4,7 @@
 
 // Fixed-size object allocator.  Returned memory is not zeroed.
 //
-// See malloc.h for overview.
+// See malloc.go for overview.
 
 package runtime
 
diff --git a/src/runtime/mgc.go b/src/runtime/mgc.go
index 830bf87..89f3fb5 100644
--- a/src/runtime/mgc.go
+++ b/src/runtime/mgc.go
@@ -130,9 +130,6 @@
 	_RootCount       = 5
 )
 
-// linker-provided
-var data, edata, bss, ebss, gcdata, gcbss, noptrdata, enoptrdata, noptrbss, enoptrbss, end struct{}
-
 //go:linkname weak_cgo_allocate go.weak.runtime._cgo_allocate_internal
 var weak_cgo_allocate byte
 
@@ -142,17 +139,6 @@
 	return &weak_cgo_allocate != nil
 }
 
-// Slow for now as we serialize this, since this is on a debug path
-// speed is not critical at this point.
-var andlock mutex
-
-//go:nowritebarrier
-func atomicand8(src *byte, val byte) {
-	lock(&andlock)
-	*src &= val
-	unlock(&andlock)
-}
-
 var gcdatamask bitvector
 var gcbssmask bitvector
 
@@ -171,11 +157,21 @@
 
 	work.markfor = parforalloc(_MaxGcproc)
 	gcpercent = readgogc()
-	gcdatamask = unrollglobgcprog((*byte)(unsafe.Pointer(&gcdata)), uintptr(unsafe.Pointer(&edata))-uintptr(unsafe.Pointer(&data)))
-	gcbssmask = unrollglobgcprog((*byte)(unsafe.Pointer(&gcbss)), uintptr(unsafe.Pointer(&ebss))-uintptr(unsafe.Pointer(&bss)))
+	gcdatamask = unrollglobgcprog((*byte)(unsafe.Pointer(themoduledata.gcdata)), themoduledata.edata-themoduledata.data)
+	gcbssmask = unrollglobgcprog((*byte)(unsafe.Pointer(themoduledata.gcbss)), themoduledata.ebss-themoduledata.bss)
 	memstats.next_gc = heapminimum
 }
 
+// gcenable is called after the bulk of the runtime initialization,
+// just before we're about to start letting user code run.
+// It kicks off the background sweeper goroutine and enables GC.
+func gcenable() {
+	c := make(chan int, 1)
+	go bgsweep(c)
+	<-c
+	memstats.enablegc = true // now that runtime is initialized, GC is okay
+}
+
 func setGCPercent(in int32) (out int32) {
 	lock(&mheap_.lock)
 	out = gcpercent
@@ -260,7 +256,7 @@
 		go backgroundgc()
 	} else if bggc.working == 0 {
 		bggc.working = 1
-		ready(bggc.g)
+		ready(bggc.g, 0)
 	}
 	unlock(&bggc.lock)
 }
@@ -281,7 +277,7 @@
 		gc(gcBackgroundMode)
 		lock(&bggc.lock)
 		bggc.working = 0
-		goparkunlock(&bggc.lock, "Concurrent GC wait", traceEvGoBlock)
+		goparkunlock(&bggc.lock, "Concurrent GC wait", traceEvGoBlock, 1)
 	}
 }
 
@@ -309,6 +305,9 @@
 
 	systemstack(stoptheworld)
 	systemstack(finishsweep_m) // finish sweep before we start concurrent scan.
+	// clearpools before we start the GC. If we wait they memory will not be
+	// reclaimed until the next GC cycle.
+	clearpools()
 
 	if mode == gcBackgroundMode { // Do as much work concurrently as possible
 		systemstack(func() {
@@ -320,23 +319,30 @@
 			gcscan_m()
 			gctimer.cycle.installmarkwb = nanotime()
 
-			// Sync.
+			// Enter mark phase and enable write barriers.
 			stoptheworld()
 			gcphase = _GCmark
-			harvestwbufs()
 
 			// Concurrent mark.
 			starttheworld()
-			gctimer.cycle.mark = nanotime()
-			var gcw gcWork
-			gcDrain(&gcw)
-			gcw.dispose()
-
-			// Begin mark termination.
-			gctimer.cycle.markterm = nanotime()
-			stoptheworld()
-			gcphase = _GCoff
 		})
+		gctimer.cycle.mark = nanotime()
+		var gcw gcWork
+		gcDrain(&gcw)
+		gcw.dispose()
+		// Despite the barrier in gcDrain, gcDrainNs may still
+		// be doing work at this point. This is okay because
+		// 1) the gcDrainNs happen on the system stack, so
+		// they will flush their work to the global queues
+		// before we can stop the world, and 2) it's fine if
+		// we go into mark termination with some work queued.
+
+		// Begin mark termination.
+		gctimer.cycle.markterm = nanotime()
+		systemstack(stoptheworld)
+		// The gcphase is _GCmark, it will transition to _GCmarktermination
+		// below. The important thing is that the wb remains active until
+		// all marking is complete. This includes writes made by the GC.
 	} else {
 		// For non-concurrent GC (mode != gcBackgroundMode)
 		// The g stacks have not been scanned so clear g state
@@ -344,14 +350,15 @@
 		gcResetGState()
 	}
 
+	// World is stopped.
+	// Start marktermination which includes enabling the write barrier.
+	gcphase = _GCmarktermination
+
 	startTime := nanotime()
 	if mp != acquirem() {
 		throw("gcwork: rescheduled")
 	}
 
-	// TODO(rsc): Should the concurrent GC clear pools earlier?
-	clearpools()
-
 	_g_ := getg()
 	_g_.m.traceback = 2
 	gp := _g_.m.curg
@@ -373,6 +380,9 @@
 			gcMark(startTime)
 			clearCheckmarks()
 		}
+
+		// marking is complete so we can turn the write barrier off
+		gcphase = _GCoff
 		gcSweep(mode)
 
 		if debug.gctrace > 1 {
@@ -382,7 +392,13 @@
 			// Reset these so that all stacks will be rescanned.
 			gcResetGState()
 			finishsweep_m()
+
+			// Still in STW but gcphase is _GCoff, reset to _GCmarktermination
+			// At this point all objects will be found during the gcMark which
+			// does a complete STW mark and object scan.
+			gcphase = _GCmarktermination
 			gcMark(startTime)
+			gcphase = _GCoff // marking is done, turn off wb.
 			gcSweep(mode)
 		}
 	})
@@ -412,6 +428,10 @@
 		}
 	}
 
+	if gcphase != _GCoff {
+		throw("gc done but gcphase != _GCoff")
+	}
+
 	systemstack(starttheworld)
 
 	releasem(mp)
@@ -432,16 +452,17 @@
 		tracegc()
 	}
 
+	if gcphase != _GCmarktermination {
+		throw("in gcMark expecting to see gcphase as _GCmarktermination")
+	}
 	t0 := start_time
 	work.tstart = start_time
-	gcphase = _GCmarktermination
-
 	var t1 int64
 	if debug.gctrace > 0 {
 		t1 = nanotime()
 	}
 
-	gcCopySpans()
+	gcCopySpans() // TODO(rlh): should this be hoisted and done only once? Right now it is done for normal marking and also for checkmarking.
 
 	work.nwait = 0
 	work.ndone = 0
@@ -476,7 +497,6 @@
 		throw("work.partial != 0")
 	}
 
-	gcphase = _GCoff
 	var t3 int64
 	if debug.gctrace > 0 {
 		t3 = nanotime()
@@ -546,6 +566,9 @@
 }
 
 func gcSweep(mode int) {
+	if gcphase != _GCoff {
+		throw("gcSweep being done but phase is not GCoff")
+	}
 	gcCopySpans()
 
 	lock(&mheap_.lock)
@@ -568,12 +591,9 @@
 
 	// Background sweep.
 	lock(&sweep.lock)
-	if !sweep.started {
-		go bgsweep()
-		sweep.started = true
-	} else if sweep.parked {
+	if sweep.parked {
 		sweep.parked = false
-		ready(sweep.g)
+		ready(sweep.g, 0)
 	}
 	unlock(&sweep.lock)
 	mProf_GC()
@@ -628,6 +648,34 @@
 		poolcleanup()
 	}
 
+	// Clear central sudog cache.
+	// Leave per-P caches alone, they have strictly bounded size.
+	// Disconnect cached list before dropping it on the floor,
+	// so that a dangling ref to one entry does not pin all of them.
+	lock(&sched.sudoglock)
+	var sg, sgnext *sudog
+	for sg = sched.sudogcache; sg != nil; sg = sgnext {
+		sgnext = sg.next
+		sg.next = nil
+	}
+	sched.sudogcache = nil
+	unlock(&sched.sudoglock)
+
+	// Clear central defer pools.
+	// Leave per-P pools alone, they have strictly bounded size.
+	lock(&sched.deferlock)
+	for i := range sched.deferpool {
+		// disconnect cached list before dropping it on the floor,
+		// so that a dangling ref to one entry does not pin all of them.
+		var d, dlink *_defer
+		for d = sched.deferpool[i]; d != nil; d = dlink {
+			dlink = d.link
+			d.link = nil
+		}
+		sched.deferpool[i] = nil
+	}
+	unlock(&sched.deferlock)
+
 	for _, p := range &allp {
 		if p == nil {
 			break
@@ -636,27 +684,6 @@
 		if c := p.mcache; c != nil {
 			c.tiny = nil
 			c.tinyoffset = 0
-
-			// disconnect cached list before dropping it on the floor,
-			// so that a dangling ref to one entry does not pin all of them.
-			var sg, sgnext *sudog
-			for sg = c.sudogcache; sg != nil; sg = sgnext {
-				sgnext = sg.next
-				sg.next = nil
-			}
-			c.sudogcache = nil
-		}
-
-		// clear defer pools
-		for i := range p.deferpool {
-			// disconnect cached list before dropping it on the floor,
-			// so that a dangling ref to one entry does not pin all of them.
-			var d, dlink *_defer
-			for d = p.deferpool[i]; d != nil; d = dlink {
-				dlink = d.link
-				d.link = nil
-			}
-			p.deferpool[i] = nil
 		}
 	}
 }
diff --git a/src/runtime/mgc0.h b/src/runtime/mgc0.h
deleted file mode 100644
index dd0c460..0000000
--- a/src/runtime/mgc0.h
+++ /dev/null
@@ -1,22 +0,0 @@
-// Copyright 2012 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.
-
-// Used by cmd/gc.
-
-enum {
-	gcBits = 4,
-	BitsPerPointer = 2,
-	BitsDead = 0,
-	BitsScalar = 1,
-	BitsPointer = 2,
-	BitsMask = 3,
-	PointersPerByte = 8/BitsPerPointer,
-	insData = 1,
-	insArray,
-	insArrayEnd,
-	insEnd,
-
-	// 64 bytes cover objects of size 1024/512 on 64/32 bits, respectively.
-	MaxGCMask	= 65536, // TODO(rsc): change back to 64
-};
diff --git a/src/runtime/mgcmark.go b/src/runtime/mgcmark.go
index 494c3c1..3a9679e 100644
--- a/src/runtime/mgcmark.go
+++ b/src/runtime/mgcmark.go
@@ -55,16 +55,15 @@
 
 //go:nowritebarrier
 func markroot(desc *parfor, i uint32) {
-	var gcw gcWorkProducer
-	gcw.initFromCache()
+	var gcw gcWork
 
-	// Note: if you add a case here, please also update heapdump.c:dumproots.
+	// Note: if you add a case here, please also update heapdump.go:dumproots.
 	switch i {
 	case _RootData:
-		scanblock(uintptr(unsafe.Pointer(&data)), uintptr(unsafe.Pointer(&edata))-uintptr(unsafe.Pointer(&data)), gcdatamask.bytedata, &gcw)
+		scanblock(themoduledata.data, themoduledata.edata-themoduledata.data, gcdatamask.bytedata, &gcw)
 
 	case _RootBss:
-		scanblock(uintptr(unsafe.Pointer(&bss)), uintptr(unsafe.Pointer(&ebss))-uintptr(unsafe.Pointer(&bss)), gcbssmask.bytedata, &gcw)
+		scanblock(themoduledata.bss, themoduledata.ebss-themoduledata.bss, gcbssmask.bytedata, &gcw)
 
 	case _RootFinalizers:
 		for fb := allfin; fb != nil; fb = fb.alllink {
@@ -178,7 +177,6 @@
 		// hanging off the P where this is being run.
 		// scanstack(gp)
 	case _GCmark:
-		// Get a full work buffer and empty it.
 		// drain your own currentwbuf first in the hopes that it will
 		// be more cache friendly.
 		var gcw gcWork
@@ -248,7 +246,7 @@
 		throw("can't scan gchelper stack")
 	}
 
-	var gcw gcWorkProducer
+	var gcw gcWork
 	gcw.initFromCache()
 	scanframe := func(frame *stkframe, unused unsafe.Pointer) bool {
 		// Pick up gcw as free variable so gentraceback and friends can
@@ -264,7 +262,7 @@
 
 // Scan a stack frame: local variables and function arguments/results.
 //go:nowritebarrier
-func scanframeworker(frame *stkframe, unused unsafe.Pointer, gcw *gcWorkProducer) {
+func scanframeworker(frame *stkframe, unused unsafe.Pointer, gcw *gcWork) {
 
 	f := frame.fn
 	targetpc := frame.continpc
@@ -289,10 +287,13 @@
 	// Scan local variables if stack frame has been allocated.
 	size := frame.varp - frame.sp
 	var minsize uintptr
-	if thechar != '6' && thechar != '8' {
-		minsize = ptrSize
-	} else {
+	switch thechar {
+	case '6', '8':
 		minsize = 0
+	case '7':
+		minsize = spAlign
+	default:
+		minsize = ptrSize
 	}
 	if size > minsize {
 		stkmap := (*stackmap)(funcdata(f, _FUNCDATA_LocalsPointerMaps))
@@ -334,7 +335,7 @@
 	}
 }
 
-// gcDrain scans objects in work buffers (starting with wbuf), blackening grey
+// gcDrain scans objects in work buffers, blackening grey
 // objects until all work buffers have been drained.
 //go:nowritebarrier
 func gcDrain(gcw *gcWork) {
@@ -359,7 +360,7 @@
 		// out of the wbuf passed in + a single object placed
 		// into an empty wbuf in scanobject so there could be
 		// a performance hit as we keep fetching fresh wbufs.
-		scanobject(b, 0, nil, &gcw.gcWorkProducer)
+		scanobject(b, 0, nil, gcw)
 	}
 	checknocurrentwbuf()
 }
@@ -377,14 +378,14 @@
 		if b == 0 {
 			return
 		}
-		scanobject(b, 0, nil, &gcw.gcWorkProducer)
+		scanobject(b, 0, nil, gcw)
 	}
 }
 
 // scanblock scans b as scanobject would.
 // If the gcphase is GCscan, scanblock performs additional checks.
 //go:nowritebarrier
-func scanblock(b0, n0 uintptr, ptrmask *uint8, gcw *gcWorkProducer) {
+func scanblock(b0, n0 uintptr, ptrmask *uint8, gcw *gcWork) {
 	// Use local copies of original parameters, so that a stack trace
 	// due to one of the throws below shows the original block
 	// base and extent.
@@ -404,26 +405,28 @@
 	}
 }
 
-// Scan the object b of size n, adding pointers to wbuf.
-// Return possibly new wbuf to use.
+// Scan the object b of size n bytes, adding pointers to wbuf.
 // If ptrmask != nil, it specifies where pointers are in b.
 // If ptrmask == nil, the GC bitmap should be consulted.
 // In this case, n may be an overestimate of the size; the GC bitmap
 // must also be used to make sure the scan stops at the end of b.
 //go:nowritebarrier
-func scanobject(b, n uintptr, ptrmask *uint8, gcw *gcWorkProducer) {
+func scanobject(b, n uintptr, ptrmask *uint8, gcw *gcWork) {
 	arena_start := mheap_.arena_start
 	arena_used := mheap_.arena_used
 
 	// Find bits of the beginning of the object.
 	var hbits heapBits
+
 	if ptrmask == nil {
-		b, hbits = heapBitsForObject(b)
+		var s *mspan
+		b, hbits, s = heapBitsForObject(b)
 		if b == 0 {
 			return
 		}
+		n = s.elemsize
 		if n == 0 {
-			n = mheap_.arena_used - b
+			throw("scanobject n == 0")
 		}
 	}
 	for i := uintptr(0); i < n; i += ptrSize {
@@ -433,15 +436,9 @@
 			// dense mask (stack or data)
 			bits = (uintptr(*(*byte)(add(unsafe.Pointer(ptrmask), (i/ptrSize)/4))) >> (((i / ptrSize) % 4) * typeBitsWidth)) & typeMask
 		} else {
-			// Check if we have reached end of span.
-			// n is an overestimate of the size of the object.
-			if (b+i)%_PageSize == 0 && h_spans[(b-arena_start)>>_PageShift] != h_spans[(b+i-arena_start)>>_PageShift] {
-				break
-			}
-
 			bits = uintptr(hbits.typeBits())
-			if i > 0 && (hbits.isBoundary() || bits == typeDead) {
-				break // reached beginning of the next object
+			if bits == typeDead {
+				break // no more pointers in this object
 			}
 			hbits = hbits.next()
 		}
@@ -468,7 +465,7 @@
 		}
 
 		// Mark the object.
-		if obj, hbits := heapBitsForObject(obj); obj != 0 {
+		if obj, hbits, _ := heapBitsForObject(obj); obj != 0 {
 			greyobject(obj, b, i, hbits, gcw)
 		}
 	}
@@ -481,7 +478,7 @@
 	if !inheap(b) {
 		throw("shade: passed an address not in the heap")
 	}
-	if obj, hbits := heapBitsForObject(b); obj != 0 {
+	if obj, hbits, _ := heapBitsForObject(b); obj != 0 {
 		// TODO: this would be a great place to put a check to see
 		// if we are harvesting and if we are then we should
 		// figure out why there is a call to shade when the
@@ -492,7 +489,7 @@
 		//	throw("shade during harvest")
 		// }
 
-		var gcw gcWorkProducer
+		var gcw gcWork
 		greyobject(obj, 0, 0, hbits, &gcw)
 		// This is part of the write barrier so put the wbuf back.
 		if gcphase == _GCmarktermination {
@@ -515,7 +512,7 @@
 // Return possibly new workbuf to use.
 // base and off are for debugging only and could be removed.
 //go:nowritebarrier
-func greyobject(obj, base, off uintptr, hbits heapBits, gcw *gcWorkProducer) {
+func greyobject(obj, base, off uintptr, hbits heapBits, gcw *gcWork) {
 	// obj should be start of allocation, and so must be at least pointer-aligned.
 	if obj&(ptrSize-1) != 0 {
 		throw("greyobject: obj not pointer-aligned")
@@ -523,45 +520,16 @@
 
 	if useCheckmark {
 		if !hbits.isMarked() {
+			printlock()
 			print("runtime:greyobject: checkmarks finds unexpected unmarked object obj=", hex(obj), "\n")
 			print("runtime: found obj at *(", hex(base), "+", hex(off), ")\n")
 
 			// Dump the source (base) object
-
-			kb := base >> _PageShift
-			xb := kb
-			xb -= mheap_.arena_start >> _PageShift
-			sb := h_spans[xb]
-			printlock()
-			print("runtime:greyobject Span: base=", hex(base), " kb=", hex(kb))
-			if sb == nil {
-				print(" sb=nil\n")
-			} else {
-				print(" sb.start*_PageSize=", hex(sb.start*_PageSize), " sb.limit=", hex(sb.limit), " sb.sizeclass=", sb.sizeclass, " sb.elemsize=", sb.elemsize, "\n")
-				// base is (a pointer to) the source object holding the reference to object. Create a pointer to each of the fields
-				// fields in base and print them out as hex values.
-				for i := 0; i < int(sb.elemsize/ptrSize); i++ {
-					print(" *(base+", i*ptrSize, ") = ", hex(*(*uintptr)(unsafe.Pointer(base + uintptr(i)*ptrSize))), "\n")
-				}
-			}
+			gcDumpObject("base", base, off)
 
 			// Dump the object
+			gcDumpObject("obj", obj, ^uintptr(0))
 
-			k := obj >> _PageShift
-			x := k
-			x -= mheap_.arena_start >> _PageShift
-			s := h_spans[x]
-			print("runtime:greyobject Span: obj=", hex(obj), " k=", hex(k))
-			if s == nil {
-				print(" s=nil\n")
-			} else {
-				print(" s.start=", hex(s.start*_PageSize), " s.limit=", hex(s.limit), " s.sizeclass=", s.sizeclass, " s.elemsize=", s.elemsize, "\n")
-				// NOTE(rsc): This code is using s.sizeclass as an approximation of the
-				// number of pointer-sized words in an object. Perhaps not what was intended.
-				for i := 0; i < int(s.sizeclass); i++ {
-					print(" *(obj+", i*ptrSize, ") = ", hex(*(*uintptr)(unsafe.Pointer(obj + uintptr(i)*ptrSize))), "\n")
-				}
-			}
 			throw("checkmark found unmarked object")
 		}
 		if !hbits.isCheckmarked() {
@@ -596,6 +564,28 @@
 	gcw.put(obj)
 }
 
+// gcDumpObject dumps the contents of obj for debugging and marks the
+// field at byte offset off in obj.
+func gcDumpObject(label string, obj, off uintptr) {
+	k := obj >> _PageShift
+	x := k
+	x -= mheap_.arena_start >> _PageShift
+	s := h_spans[x]
+	print(label, "=", hex(obj), " k=", hex(k))
+	if s == nil {
+		print(" s=nil\n")
+		return
+	}
+	print(" s.start*_PageSize=", hex(s.start*_PageSize), " s.limit=", hex(s.limit), " s.sizeclass=", s.sizeclass, " s.elemsize=", s.elemsize, "\n")
+	for i := uintptr(0); i < s.elemsize; i += ptrSize {
+		print(" *(", label, "+", i, ") = ", hex(*(*uintptr)(unsafe.Pointer(obj + uintptr(i)))))
+		if i == off {
+			print(" <==")
+		}
+		print("\n")
+	}
+}
+
 // When in GCmarkterminate phase we allocate black.
 //go:nowritebarrier
 func gcmarknewobject_m(obj uintptr) {
diff --git a/src/runtime/mgcsweep.go b/src/runtime/mgcsweep.go
index ab18d5f..d72ef3a 100644
--- a/src/runtime/mgcsweep.go
+++ b/src/runtime/mgcsweep.go
@@ -42,8 +42,14 @@
 	}
 }
 
-func bgsweep() {
+func bgsweep(c chan int) {
 	sweep.g = getg()
+
+	lock(&sweep.lock)
+	sweep.parked = true
+	c <- 1
+	goparkunlock(&sweep.lock, "GC sweep wait", traceEvGoBlock, 1)
+
 	for {
 		for gosweepone() != ^uintptr(0) {
 			sweep.nbgsweep++
@@ -58,7 +64,7 @@
 			continue
 		}
 		sweep.parked = true
-		goparkunlock(&sweep.lock, "GC sweep wait", traceEvGoBlock)
+		goparkunlock(&sweep.lock, "GC sweep wait", traceEvGoBlock, 1)
 	}
 }
 
@@ -218,7 +224,7 @@
 			if preserve {
 				throw("can't preserve large span")
 			}
-			heapBitsForSpan(p).clearSpan(s.layout())
+			heapBitsForSpan(p).initSpan(s.layout())
 			s.needzero = 1
 
 			// important to set sweepgen before returning it to heap
diff --git a/src/runtime/mgcwork.go b/src/runtime/mgcwork.go
index 5d725a5..f69d6bb6 100644
--- a/src/runtime/mgcwork.go
+++ b/src/runtime/mgcwork.go
@@ -35,36 +35,32 @@
 	return (*workbuf)(unsafe.Pointer(wp))
 }
 
-// A gcWorkProducer provides the interface to produce work for the
+// A gcWork provides the interface to produce and consume work for the
 // garbage collector.
 //
-// The usual pattern for using gcWorkProducer is:
+// The usual pattern for using gcWork is:
 //
-//     var gcw gcWorkProducer
-//     .. call gcw.put() ..
+//     var gcw gcWork
+//     disable preemption
+//     .. call gcw.put() to produce and gcw.get() to consume ..
 //     gcw.dispose()
-type gcWorkProducer struct {
+//     enable preemption
+//
+// It's important that any use of gcWork during the mark phase prevent
+// the garbage collector from transitioning to mark termination since
+// gcWork may locally hold GC work buffers. This can be done by
+// disabling preemption (systemstack or acquirem).
+type gcWork struct {
 	// Invariant: wbuf is never full or empty
 	wbuf wbufptr
 }
 
-// A gcWork provides the interface to both produce and consume work
-// for the garbage collector.
-//
-// The pattern for using gcWork is the same as gcWorkProducer.
-type gcWork struct {
-	gcWorkProducer
-}
-
-// Note that there is no need for a gcWorkConsumer because everything
-// that consumes pointers also produces them.
-
 // initFromCache fetches work from this M's currentwbuf cache.
 //go:nowritebarrier
-func (w *gcWorkProducer) initFromCache() {
-	// TODO: Instead of making gcWorkProducer pull from the
-	// currentwbuf cache, use a gcWorkProducer as the cache and
-	// make shade pass around that gcWorkProducer.
+func (w *gcWork) initFromCache() {
+	// TODO: Instead of making gcWork pull from the currentwbuf
+	// cache, use a gcWork as the cache and make shade pass around
+	// that gcWork.
 	if w.wbuf == 0 {
 		w.wbuf = wbufptr(xchguintptr(&getg().m.currentwbuf, 0))
 	}
@@ -72,8 +68,8 @@
 
 // put enqueues a pointer for the garbage collector to trace.
 //go:nowritebarrier
-func (ww *gcWorkProducer) put(obj uintptr) {
-	w := (*gcWorkProducer)(noescape(unsafe.Pointer(ww))) // TODO: remove when escape analysis is fixed
+func (ww *gcWork) put(obj uintptr) {
+	w := (*gcWork)(noescape(unsafe.Pointer(ww))) // TODO: remove when escape analysis is fixed
 
 	wbuf := w.wbuf.ptr()
 	if wbuf == nil {
@@ -90,28 +86,6 @@
 	}
 }
 
-// dispose returns any cached pointers to the global queue.
-//go:nowritebarrier
-func (w *gcWorkProducer) dispose() {
-	if wbuf := w.wbuf; wbuf != 0 {
-		putpartial(wbuf.ptr(), 58)
-		w.wbuf = 0
-	}
-}
-
-// disposeToCache returns any cached pointers to this M's currentwbuf.
-// It calls throw if currentwbuf is non-nil.
-//go:nowritebarrier
-func (w *gcWorkProducer) disposeToCache() {
-	if wbuf := w.wbuf; wbuf != 0 {
-		wbuf = wbufptr(xchguintptr(&getg().m.currentwbuf, uintptr(wbuf)))
-		if wbuf != 0 {
-			throw("m.currentwbuf non-nil in disposeToCache")
-		}
-		w.wbuf = 0
-	}
-}
-
 // tryGet dequeues a pointer for the garbage collector to trace.
 //
 // If there are no pointers remaining in this gcWork or in the global
@@ -175,11 +149,20 @@
 //go:nowritebarrier
 func (w *gcWork) dispose() {
 	if wbuf := w.wbuf; wbuf != 0 {
-		// Even though wbuf may only be partially full, we
-		// want to keep it on the consumer's queues rather
-		// than putting it back on the producer's queues.
-		// Hence, we use putfull here.
-		putfull(wbuf.ptr(), 133)
+		putpartial(wbuf.ptr(), 167)
+		w.wbuf = 0
+	}
+}
+
+// disposeToCache returns any cached pointers to this M's currentwbuf.
+// It calls throw if currentwbuf is non-nil.
+//go:nowritebarrier
+func (w *gcWork) disposeToCache() {
+	if wbuf := w.wbuf; wbuf != 0 {
+		wbuf = wbufptr(xchguintptr(&getg().m.currentwbuf, uintptr(wbuf)))
+		if wbuf != 0 {
+			throw("m.currentwbuf non-nil in disposeToCache")
+		}
 		w.wbuf = 0
 	}
 }
@@ -443,7 +426,7 @@
 
 	xadd(&work.nwait, +1)
 	for i := 0; ; i++ {
-		if work.full != 0 {
+		if work.full != 0 || work.partial != 0 {
 			xadd(&work.nwait, -1)
 			b = (*workbuf)(lfstackpop(&work.full))
 			if b == nil {
diff --git a/src/runtime/mheap.go b/src/runtime/mheap.go
index 94ef4de..e94b79fb 100644
--- a/src/runtime/mheap.go
+++ b/src/runtime/mheap.go
@@ -101,11 +101,14 @@
 	// if sweepgen == h->sweepgen, the span is swept and ready to use
 	// h->sweepgen is incremented by 2 after every GC
 	sweepgen    uint32
+	divMul      uint32   // for divide by elemsize - divMagic.mul
 	ref         uint16   // capacity - number of objects in freelist
 	sizeclass   uint8    // size class
 	incache     bool     // being used by an mcache
 	state       uint8    // mspaninuse etc
 	needzero    uint8    // needs to be zeroed before allocation
+	divShift    uint8    // for divide by elemsize - divMagic.shift
+	divShift2   uint8    // for divide by elemsize - divMagic.shift2
 	elemsize    uintptr  // computed from sizeclass or from npages
 	unusedsince int64    // first time spotted by gc in mspanfree state
 	npreleased  uintptr  // number of pages released to the os
@@ -155,7 +158,7 @@
 		if len(h_allspans) > 0 {
 			copy(new, h_allspans)
 			// Don't free the old array if it's referenced by sweep.
-			// See the comment in mgc0.c.
+			// See the comment in mgc.go.
 			if h.allspans != mheap_.gcspans {
 				sysFree(unsafe.Pointer(h.allspans), uintptr(cap(h_allspans))*ptrSize, &memstats.other_sys)
 			}
@@ -385,8 +388,15 @@
 		s.sizeclass = uint8(sizeclass)
 		if sizeclass == 0 {
 			s.elemsize = s.npages << _PageShift
+			s.divShift = 0
+			s.divMul = 0
+			s.divShift2 = 0
 		} else {
 			s.elemsize = uintptr(class_to_size[sizeclass])
+			m := &class_to_divmagic[sizeclass]
+			s.divShift = m.shift
+			s.divMul = m.mul
+			s.divShift2 = m.shift2
 		}
 
 		// update stats, sweep lists
diff --git a/src/runtime/msize.go b/src/runtime/msize.go
index 370cae6..9ba145d 100644
--- a/src/runtime/msize.go
+++ b/src/runtime/msize.go
@@ -4,7 +4,7 @@
 
 // Malloc small size classes.
 //
-// See malloc.h for overview.
+// See malloc.go for overview.
 //
 // The size classes are chosen so that rounding an allocation
 // request up to the next size class wastes at most 12.5% (1.125x).
@@ -48,6 +48,8 @@
 
 var class_to_size [_NumSizeClasses]int32
 var class_to_allocnpages [_NumSizeClasses]int32
+var class_to_divmagic [_NumSizeClasses]divMagic
+
 var size_to_class8 [1024/8 + 1]int8
 var size_to_class128 [(_MaxSmallSize-1024)/128 + 1]int8
 
@@ -144,6 +146,11 @@
 	for i := 0; i < len(class_to_size); i++ {
 		memstats.by_size[i].size = uint32(class_to_size[i])
 	}
+
+	for i := 1; i < len(class_to_size); i++ {
+		class_to_divmagic[i] = computeDivMagic(uint32(class_to_size[i]))
+	}
+
 	return
 
 dump:
@@ -182,3 +189,55 @@
 	}
 	return round(size, _PageSize)
 }
+
+// divMagic holds magic constants to implement division
+// by a particular constant as a shift, multiply, and shift.
+// That is, given
+//	m = computeMagic(d)
+// then
+//	n/d == ((n>>m.shift) * m.mul) >> m.shift2
+//
+// The magic computation picks m such that
+//	d = d₁*d₂
+//	d₂= 2^m.shift
+//	m.mul = ⌈2^m.shift2 / d₁⌉
+//
+// The magic computation here is tailored for malloc block sizes
+// and does not handle arbitrary d correctly. Malloc block sizes d are
+// always even, so the first shift implements the factors of 2 in d
+// and then the mul and second shift implement the odd factor
+// that remains. Because the first shift divides n by at least 2 (actually 8)
+// before the multiply gets involved, the huge corner cases that
+// require additional adjustment are impossible, so the usual
+// fixup is not needed.
+//
+// For more details see Hacker's Delight, Chapter 10, and
+// http://ridiculousfish.com/blog/posts/labor-of-division-episode-i.html
+// http://ridiculousfish.com/blog/posts/labor-of-division-episode-iii.html
+type divMagic struct {
+	shift  uint8
+	mul    uint32
+	shift2 uint8
+}
+
+func computeDivMagic(d uint32) divMagic {
+	var m divMagic
+
+	// Compute pre-shift by factoring power of 2 out of d.
+	for d&1 == 0 {
+		m.shift++
+		d >>= 1
+	}
+
+	// Compute largest k such that ⌈2^k / d⌉ fits in a 32-bit int.
+	// This is always a good enough approximation.
+	// We could use smaller k for some divisors but there's no point.
+	k := uint8(63)
+	d64 := uint64(d)
+	for ((1<<k)+d64-1)/d64 >= 1<<32 {
+		k--
+	}
+	m.mul = uint32(((1 << k) + d64 - 1) / d64) //  ⌈2^k / d⌉
+	m.shift2 = k
+	return m
+}
diff --git a/src/runtime/mstats.go b/src/runtime/mstats.go
index 19b6833..88cf42f 100644
--- a/src/runtime/mstats.go
+++ b/src/runtime/mstats.go
@@ -64,9 +64,6 @@
 
 var memstats mstats
 
-// Note: the MemStats struct should be kept in sync with
-// struct MStats in malloc.h
-
 // A MemStats records statistics about the memory allocator.
 type MemStats struct {
 	// General statistics.
diff --git a/src/runtime/netpoll.go b/src/runtime/netpoll.go
index 8ea0878..4791e5e 100644
--- a/src/runtime/netpoll.go
+++ b/src/runtime/netpoll.go
@@ -237,10 +237,10 @@
 	}
 	unlock(&pd.lock)
 	if rg != nil {
-		goready(rg)
+		goready(rg, 3)
 	}
 	if wg != nil {
-		goready(wg)
+		goready(wg, 3)
 	}
 }
 
@@ -266,29 +266,33 @@
 	}
 	unlock(&pd.lock)
 	if rg != nil {
-		goready(rg)
+		goready(rg, 3)
 	}
 	if wg != nil {
-		goready(wg)
+		goready(wg, 3)
 	}
 }
 
 // make pd ready, newly runnable goroutines (if any) are returned in rg/wg
+// May run during STW, so write barriers are not allowed.
+// Eliminating WB calls using setGNoWriteBarrier are safe since the gs are
+// reachable through allg.
+//go:nowritebarrier
 func netpollready(gpp **g, pd *pollDesc, mode int32) {
 	var rg, wg *g
 	if mode == 'r' || mode == 'r'+'w' {
-		rg = netpollunblock(pd, 'r', true)
+		setGNoWriteBarrier(&rg, netpollunblock(pd, 'r', true))
 	}
 	if mode == 'w' || mode == 'r'+'w' {
-		wg = netpollunblock(pd, 'w', true)
+		setGNoWriteBarrier(&wg, netpollunblock(pd, 'w', true))
 	}
 	if rg != nil {
-		rg.schedlink = *gpp
-		*gpp = rg
+		setGNoWriteBarrier(&rg.schedlink, *gpp)
+		setGNoWriteBarrier(gpp, rg)
 	}
 	if wg != nil {
-		wg.schedlink = *gpp
-		*gpp = wg
+		setGNoWriteBarrier(&wg.schedlink, *gpp)
+		setGNoWriteBarrier(gpp, wg)
 	}
 }
 
@@ -333,7 +337,7 @@
 	// this is necessary because runtime_pollUnblock/runtime_pollSetDeadline/deadlineimpl
 	// do the opposite: store to closing/rd/wd, membarrier, load of rg/wg
 	if waitio || netpollcheckerr(pd, mode) == 0 {
-		gopark(netpollblockcommit, unsafe.Pointer(gpp), "IO wait", traceEvGoBlockNet)
+		gopark(netpollblockcommit, unsafe.Pointer(gpp), "IO wait", traceEvGoBlockNet, 5)
 	}
 	// be careful to not lose concurrent READY notification
 	old := xchguintptr(gpp, 0)
@@ -401,10 +405,10 @@
 	}
 	unlock(&pd.lock)
 	if rg != nil {
-		goready(rg)
+		goready(rg, 0)
 	}
 	if wg != nil {
-		goready(wg)
+		goready(wg, 0)
 	}
 }
 
diff --git a/src/runtime/noasm.go b/src/runtime/noasm.go
index 7ffde37..ab9c744 100644
--- a/src/runtime/noasm.go
+++ b/src/runtime/noasm.go
@@ -2,9 +2,9 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// Routines that are implemented in assembly in asm_{amd64,386}.s
+// Routines that are implemented in assembly in asm_{amd64,386,arm}.s
 
-// +build arm ppc64 ppc64le
+// +build arm64 ppc64 ppc64le
 
 package runtime
 
diff --git a/src/runtime/os1_darwin.go b/src/runtime/os1_darwin.go
index 6a60314..6c79bbb 100644
--- a/src/runtime/os1_darwin.go
+++ b/src/runtime/os1_darwin.go
@@ -71,6 +71,8 @@
 	}
 }
 
+// May run with m.p==nil, so write barriers are not allowed.
+//go:nowritebarrier
 func newosproc(mp *m, stk unsafe.Pointer) {
 	mp.tls[0] = uintptr(mp.id) // so 386 asm can find it
 	if false {
diff --git a/src/runtime/os1_dragonfly.go b/src/runtime/os1_dragonfly.go
index 2a67da6..54f19ef 100644
--- a/src/runtime/os1_dragonfly.go
+++ b/src/runtime/os1_dragonfly.go
@@ -71,6 +71,8 @@
 
 func lwp_start(uintptr)
 
+// May run with m.p==nil, so write barriers are not allowed.
+//go:nowritebarrier
 func newosproc(mp *m, stk unsafe.Pointer) {
 	if false {
 		print("newosproc stk=", stk, " m=", mp, " g=", mp.g0, " lwp_start=", funcPC(lwp_start), " id=", mp.id, "/", mp.tls[0], " ostk=", &mp, "\n")
@@ -87,7 +89,7 @@
 		tid2:       nil,
 	}
 
-	mp.tls[0] = uintptr(mp.id) // so 386 asm can find it
+	mp.tls[0] = uintptr(mp.id) // XXX so 386 asm can find it
 
 	lwp_create(&params)
 	sigprocmask(&oset, nil)
diff --git a/src/runtime/os1_freebsd.go b/src/runtime/os1_freebsd.go
index f49f28e..ceaa916 100644
--- a/src/runtime/os1_freebsd.go
+++ b/src/runtime/os1_freebsd.go
@@ -28,7 +28,7 @@
 
 // FreeBSD's umtx_op syscall is effectively the same as Linux's futex, and
 // thus the code is largely similar. See Linux implementation
-// and lock_futex.c for comments.
+// and lock_futex.go for comments.
 
 //go:nosplit
 func futexsleep(addr *uint32, val uint32, ns int64) {
@@ -67,6 +67,8 @@
 
 func thr_start()
 
+// May run with m.p==nil, so write barriers are not allowed.
+//go:nowritebarrier
 func newosproc(mp *m, stk unsafe.Pointer) {
 	if false {
 		print("newosproc stk=", stk, " m=", mp, " g=", mp.g0, " thr_start=", funcPC(thr_start), " id=", mp.id, "/", mp.tls[0], " ostk=", &mp, "\n")
diff --git a/src/runtime/os1_linux.go b/src/runtime/os1_linux.go
index 44da57a..735f595 100644
--- a/src/runtime/os1_linux.go
+++ b/src/runtime/os1_linux.go
@@ -113,6 +113,8 @@
 	_CLONE_NEWIPC         = 0x8000000
 )
 
+// May run with m.p==nil, so write barriers are not allowed.
+//go:nowritebarrier
 func newosproc(mp *m, stk unsafe.Pointer) {
 	/*
 	 * note: strace gets confused if we use CLONE_PTRACE here.
diff --git a/src/runtime/os1_nacl.go b/src/runtime/os1_nacl.go
index a27a13f..dbb5dec 100644
--- a/src/runtime/os1_nacl.go
+++ b/src/runtime/os1_nacl.go
@@ -46,11 +46,8 @@
 	*(*int32)(nil) = 0
 }
 
-//go:nosplit
-func getRandomData(r []byte) {
-	// TODO: does nacl have a random source we can use?
-	extendRandom(r, 0)
-}
+//go:noescape
+func getRandomData([]byte)
 
 func goenvs() {
 	goenvs_unix()
@@ -70,11 +67,12 @@
 
 func mstart_nacl()
 
+// May run with m.p==nil, so write barriers are not allowed.
+//go:nowritebarrier
 func newosproc(mp *m, stk unsafe.Pointer) {
-	tls := (*[3]unsafe.Pointer)(unsafe.Pointer(&mp.tls))
-	tls[0] = unsafe.Pointer(mp.g0)
-	tls[1] = unsafe.Pointer(mp)
-	ret := nacl_thread_create(funcPC(mstart_nacl), stk, unsafe.Pointer(&tls[2]), nil)
+	mp.tls[0] = uintptr(unsafe.Pointer(mp.g0))
+	mp.tls[1] = uintptr(unsafe.Pointer(mp))
+	ret := nacl_thread_create(funcPC(mstart_nacl), stk, unsafe.Pointer(&mp.tls[2]), nil)
 	if ret < 0 {
 		print("nacl_thread_create: error ", -ret, "\n")
 		throw("newosproc")
diff --git a/src/runtime/os1_netbsd.go b/src/runtime/os1_netbsd.go
index f2e6ef6..85b3df3 100644
--- a/src/runtime/os1_netbsd.go
+++ b/src/runtime/os1_netbsd.go
@@ -89,6 +89,8 @@
 	}
 }
 
+// May run with m.p==nil, so write barriers are not allowed.
+//go:nowritebarrier
 func newosproc(mp *m, stk unsafe.Pointer) {
 	if false {
 		print("newosproc stk=", stk, " m=", mp, " g=", mp.g0, " id=", mp.id, "/", int32(mp.tls[0]), " ostk=", &mp, "\n")
diff --git a/src/runtime/os1_openbsd.go b/src/runtime/os1_openbsd.go
index d23d812..4f41864 100644
--- a/src/runtime/os1_openbsd.go
+++ b/src/runtime/os1_openbsd.go
@@ -19,8 +19,10 @@
 	_CLOCK_MONOTONIC = 3
 )
 
-var sigset_none = uint32(0)
-var sigset_all = ^sigset_none
+const (
+	sigset_none = uint32(0)
+	sigset_all  = ^uint32(0)
+)
 
 // From OpenBSD's <sys/sysctl.h>
 const (
@@ -96,6 +98,8 @@
 	}
 }
 
+// May run with m.p==nil, so write barriers are not allowed.
+//go:nowritebarrier
 func newosproc(mp *m, stk unsafe.Pointer) {
 	if false {
 		print("newosproc stk=", stk, " m=", mp, " g=", mp.g0, " id=", mp.id, "/", int32(mp.tls[0]), " ostk=", &mp, "\n")
@@ -115,9 +119,6 @@
 
 	if ret < 0 {
 		print("runtime: failed to create new OS thread (have ", mcount()-1, " already; errno=", -ret, ")\n")
-		if ret == -_ENOTSUP {
-			print("runtime: is kern.rthreads disabled?\n")
-		}
 		throw("runtime.newosproc")
 	}
 }
diff --git a/src/runtime/os1_plan9.go b/src/runtime/os1_plan9.go
index bba1f17..284f338 100644
--- a/src/runtime/os1_plan9.go
+++ b/src/runtime/os1_plan9.go
@@ -183,6 +183,8 @@
 	exits(&status[0])
 }
 
+// May run with m.p==nil, so write barriers are not allowed.
+//go:nowritebarrier
 func newosproc(mp *m, stk unsafe.Pointer) {
 	if false {
 		print("newosproc mp=", mp, " ostk=", &mp, "\n")
diff --git a/src/runtime/os1_windows.go b/src/runtime/os1_windows.go
index 744b1a9..9a077af 100644
--- a/src/runtime/os1_windows.go
+++ b/src/runtime/os1_windows.go
@@ -8,44 +8,43 @@
 	"unsafe"
 )
 
-//go:cgo_import_dynamic runtime._AddVectoredExceptionHandler AddVectoredExceptionHandler "kernel32.dll"
-//go:cgo_import_dynamic runtime._CloseHandle CloseHandle "kernel32.dll"
-//go:cgo_import_dynamic runtime._CreateEventA CreateEventA "kernel32.dll"
-//go:cgo_import_dynamic runtime._CreateIoCompletionPort CreateIoCompletionPort "kernel32.dll"
-//go:cgo_import_dynamic runtime._CreateThread CreateThread "kernel32.dll"
-//go:cgo_import_dynamic runtime._CreateWaitableTimerA CreateWaitableTimerA "kernel32.dll"
-//go:cgo_import_dynamic runtime._CryptAcquireContextW CryptAcquireContextW "advapi32.dll"
-//go:cgo_import_dynamic runtime._CryptGenRandom CryptGenRandom "advapi32.dll"
-//go:cgo_import_dynamic runtime._CryptReleaseContext CryptReleaseContext "advapi32.dll"
-//go:cgo_import_dynamic runtime._DuplicateHandle DuplicateHandle "kernel32.dll"
-//go:cgo_import_dynamic runtime._ExitProcess ExitProcess "kernel32.dll"
-//go:cgo_import_dynamic runtime._FreeEnvironmentStringsW FreeEnvironmentStringsW "kernel32.dll"
-//go:cgo_import_dynamic runtime._GetEnvironmentStringsW GetEnvironmentStringsW "kernel32.dll"
-//go:cgo_import_dynamic runtime._GetProcAddress GetProcAddress "kernel32.dll"
-//go:cgo_import_dynamic runtime._GetQueuedCompletionStatus GetQueuedCompletionStatus "kernel32.dll"
-//go:cgo_import_dynamic runtime._GetStdHandle GetStdHandle "kernel32.dll"
-//go:cgo_import_dynamic runtime._GetSystemInfo GetSystemInfo "kernel32.dll"
-//go:cgo_import_dynamic runtime._GetThreadContext GetThreadContext "kernel32.dll"
-//go:cgo_import_dynamic runtime._LoadLibraryW LoadLibraryW "kernel32.dll"
-//go:cgo_import_dynamic runtime._LoadLibraryA LoadLibraryA "kernel32.dll"
-//go:cgo_import_dynamic runtime._NtWaitForSingleObject NtWaitForSingleObject "ntdll.dll"
-//go:cgo_import_dynamic runtime._ResumeThread ResumeThread "kernel32.dll"
-//go:cgo_import_dynamic runtime._SetConsoleCtrlHandler SetConsoleCtrlHandler "kernel32.dll"
-//go:cgo_import_dynamic runtime._SetErrorMode SetErrorMode "kernel32.dll"
-//go:cgo_import_dynamic runtime._SetEvent SetEvent "kernel32.dll"
-//go:cgo_import_dynamic runtime._SetProcessPriorityBoost SetProcessPriorityBoost "kernel32.dll"
-//go:cgo_import_dynamic runtime._SetThreadPriority SetThreadPriority "kernel32.dll"
-//go:cgo_import_dynamic runtime._SetUnhandledExceptionFilter SetUnhandledExceptionFilter "kernel32.dll"
-//go:cgo_import_dynamic runtime._SetWaitableTimer SetWaitableTimer "kernel32.dll"
-//go:cgo_import_dynamic runtime._Sleep Sleep "kernel32.dll"
-//go:cgo_import_dynamic runtime._SuspendThread SuspendThread "kernel32.dll"
-//go:cgo_import_dynamic runtime._VirtualAlloc VirtualAlloc "kernel32.dll"
-//go:cgo_import_dynamic runtime._VirtualFree VirtualFree "kernel32.dll"
-//go:cgo_import_dynamic runtime._VirtualProtect VirtualProtect "kernel32.dll"
-//go:cgo_import_dynamic runtime._WSAGetOverlappedResult WSAGetOverlappedResult "ws2_32.dll"
-//go:cgo_import_dynamic runtime._WaitForSingleObject WaitForSingleObject "kernel32.dll"
-//go:cgo_import_dynamic runtime._WriteFile WriteFile "kernel32.dll"
-//go:cgo_import_dynamic runtime._timeBeginPeriod timeBeginPeriod "winmm.dll"
+//go:cgo_import_dynamic runtime._AddVectoredExceptionHandler AddVectoredExceptionHandler%2 "kernel32.dll"
+//go:cgo_import_dynamic runtime._CloseHandle CloseHandle%1 "kernel32.dll"
+//go:cgo_import_dynamic runtime._CreateEventA CreateEventA%4 "kernel32.dll"
+//go:cgo_import_dynamic runtime._CreateIoCompletionPort CreateIoCompletionPort%4 "kernel32.dll"
+//go:cgo_import_dynamic runtime._CreateThread CreateThread%6 "kernel32.dll"
+//go:cgo_import_dynamic runtime._CreateWaitableTimerA CreateWaitableTimerA%3 "kernel32.dll"
+//go:cgo_import_dynamic runtime._CryptAcquireContextW CryptAcquireContextW%5 "advapi32.dll"
+//go:cgo_import_dynamic runtime._CryptGenRandom CryptGenRandom%3 "advapi32.dll"
+//go:cgo_import_dynamic runtime._CryptReleaseContext CryptReleaseContext%2 "advapi32.dll"
+//go:cgo_import_dynamic runtime._DuplicateHandle DuplicateHandle%7 "kernel32.dll"
+//go:cgo_import_dynamic runtime._ExitProcess ExitProcess%1 "kernel32.dll"
+//go:cgo_import_dynamic runtime._FreeEnvironmentStringsW FreeEnvironmentStringsW%1 "kernel32.dll"
+//go:cgo_import_dynamic runtime._GetEnvironmentStringsW GetEnvironmentStringsW%0 "kernel32.dll"
+//go:cgo_import_dynamic runtime._GetProcAddress GetProcAddress%2 "kernel32.dll"
+//go:cgo_import_dynamic runtime._GetQueuedCompletionStatus GetQueuedCompletionStatus%5 "kernel32.dll"
+//go:cgo_import_dynamic runtime._GetStdHandle GetStdHandle%1 "kernel32.dll"
+//go:cgo_import_dynamic runtime._GetSystemInfo GetSystemInfo%1 "kernel32.dll"
+//go:cgo_import_dynamic runtime._GetThreadContext GetThreadContext%2 "kernel32.dll"
+//go:cgo_import_dynamic runtime._GetVersion GetVersion%0 "kernel32.dll"
+//go:cgo_import_dynamic runtime._LoadLibraryW LoadLibraryW%1 "kernel32.dll"
+//go:cgo_import_dynamic runtime._LoadLibraryA LoadLibraryA%1 "kernel32.dll"
+//go:cgo_import_dynamic runtime._NtWaitForSingleObject NtWaitForSingleObject%3 "ntdll.dll"
+//go:cgo_import_dynamic runtime._ResumeThread ResumeThread%1 "kernel32.dll"
+//go:cgo_import_dynamic runtime._SetConsoleCtrlHandler SetConsoleCtrlHandler%2 "kernel32.dll"
+//go:cgo_import_dynamic runtime._SetErrorMode SetErrorMode%1 "kernel32.dll"
+//go:cgo_import_dynamic runtime._SetEvent SetEvent%1 "kernel32.dll"
+//go:cgo_import_dynamic runtime._SetProcessPriorityBoost SetProcessPriorityBoost%2 "kernel32.dll"
+//go:cgo_import_dynamic runtime._SetThreadPriority SetThreadPriority%2 "kernel32.dll"
+//go:cgo_import_dynamic runtime._SetUnhandledExceptionFilter SetUnhandledExceptionFilter%1 "kernel32.dll"
+//go:cgo_import_dynamic runtime._SetWaitableTimer SetWaitableTimer%6 "kernel32.dll"
+//go:cgo_import_dynamic runtime._SuspendThread SuspendThread%1 "kernel32.dll"
+//go:cgo_import_dynamic runtime._VirtualAlloc VirtualAlloc%4 "kernel32.dll"
+//go:cgo_import_dynamic runtime._VirtualFree VirtualFree%3 "kernel32.dll"
+//go:cgo_import_dynamic runtime._WSAGetOverlappedResult WSAGetOverlappedResult%5 "ws2_32.dll"
+//go:cgo_import_dynamic runtime._WaitForSingleObject WaitForSingleObject%2 "kernel32.dll"
+//go:cgo_import_dynamic runtime._WriteFile WriteFile%5 "kernel32.dll"
+//go:cgo_import_dynamic runtime._timeBeginPeriod timeBeginPeriod%1 "winmm.dll"
 
 var (
 	// Following syscalls are available on every Windows PC.
@@ -69,6 +68,7 @@
 	_GetStdHandle,
 	_GetSystemInfo,
 	_GetThreadContext,
+	_GetVersion,
 	_LoadLibraryW,
 	_LoadLibraryA,
 	_NtWaitForSingleObject,
@@ -80,11 +80,9 @@
 	_SetThreadPriority,
 	_SetUnhandledExceptionFilter,
 	_SetWaitableTimer,
-	_Sleep,
 	_SuspendThread,
 	_VirtualAlloc,
 	_VirtualFree,
-	_VirtualProtect,
 	_WSAGetOverlappedResult,
 	_WaitForSingleObject,
 	_WriteFile,
@@ -152,6 +150,12 @@
 	stdcall1(_SetErrorMode, uintptr(errormode)|SEM_FAILCRITICALERRORS|SEM_NOGPFAULTERRORBOX|SEM_NOOPENFILEERRORBOX)
 }
 
+func getVersion() (major, minor byte) {
+	v := uint32(stdcall0(_GetVersion))
+	low := uint16(v)
+	return byte(low), byte(low >> 8)
+}
+
 func osinit() {
 	setBadSignalMsg()
 
@@ -161,10 +165,15 @@
 
 	externalthreadhandlerp = funcPC(externalthreadhandler)
 
+	major, _ := getVersion()
+
 	stdcall2(_AddVectoredExceptionHandler, 1, funcPC(exceptiontramp))
-	if _AddVectoredContinueHandler == nil || unsafe.Sizeof(&_AddVectoredContinueHandler) == 4 {
+	if _AddVectoredContinueHandler == nil || unsafe.Sizeof(&_AddVectoredContinueHandler) == 4 || major < 6 {
 		// use SetUnhandledExceptionFilter for windows-386 or
-		// if VectoredContinueHandler is unavailable.
+		// if VectoredContinueHandler is unavailable or
+		// if running windows-amd64 v5. V5 appears to fail to
+		// call the continue handlers if windows error reporting dialog
+		// is disabled.
 		// note: SetUnhandledExceptionFilter handler won't be called, if debugging.
 		stdcall1(_SetUnhandledExceptionFilter, funcPC(lastcontinuetramp))
 	} else {
@@ -220,7 +229,7 @@
 			n++
 		}
 	}
-	envs = makeStringSlice(n)
+	envs = make([]string, n)
 
 	for i := range envs {
 		envs[i] = gostringw(&p[0])
@@ -286,6 +295,8 @@
 	return stdcall4(_CreateEventA, 0, 0, 0, 0)
 }
 
+// May run with m.p==nil, so write barriers are not allowed.
+//go:nowritebarrier
 func newosproc(mp *m, stk unsafe.Pointer) {
 	const _STACK_SIZE_PARAM_IS_A_RESERVATION = 0x00010000
 	thandle := stdcall6(_CreateThread, 0, 0x20000,
@@ -363,6 +374,8 @@
 }
 
 // Calling stdcall on os stack.
+// May run during STW, so write barriers are not allowed.
+//go:nowritebarrier
 //go:nosplit
 func stdcall(fn stdFunction) uintptr {
 	gp := getg()
@@ -371,7 +384,8 @@
 
 	if mp.profilehz != 0 {
 		// leave pc/sp for cpu profiler
-		mp.libcallg = gp
+		// gp is on allg, so this WB can be eliminated.
+		setGNoWriteBarrier(&mp.libcallg, gp)
 		mp.libcallpc = getcallerpc(unsafe.Pointer(&fn))
 		// sp must be the last, because once async cpu profiler finds
 		// all three values to be non-zero, it will use them
diff --git a/src/runtime/os1_windows_386.go b/src/runtime/os1_windows_386.go
index f105539..e5fe748 100644
--- a/src/runtime/os1_windows_386.go
+++ b/src/runtime/os1_windows_386.go
@@ -8,8 +8,6 @@
 	"unsafe"
 )
 
-var text struct{}
-
 func dumpregs(r *context) {
 	print("eax     ", hex(r.eax), "\n")
 	print("ebx     ", hex(r.ebx), "\n")
@@ -29,7 +27,7 @@
 func isgoexception(info *exceptionrecord, r *context) bool {
 	// Only handle exception if executing instructions in Go binary
 	// (not Windows library code).
-	if r.eip < uint32(uintptr(unsafe.Pointer(&text))) || uint32(uintptr(unsafe.Pointer(&etext))) < r.eip {
+	if r.eip < uint32(themoduledata.text) || uint32(themoduledata.etext) < r.eip {
 		return false
 	}
 
diff --git a/src/runtime/os1_windows_amd64.go b/src/runtime/os1_windows_amd64.go
index 1b6b999..37a97b7 100644
--- a/src/runtime/os1_windows_amd64.go
+++ b/src/runtime/os1_windows_amd64.go
@@ -8,8 +8,6 @@
 	"unsafe"
 )
 
-var text struct{}
-
 func dumpregs(r *context) {
 	print("rax     ", hex(r.rax), "\n")
 	print("rbx     ", hex(r.rbx), "\n")
@@ -36,7 +34,7 @@
 func isgoexception(info *exceptionrecord, r *context) bool {
 	// Only handle exception if executing instructions in Go binary
 	// (not Windows library code).
-	if r.rip < uint64(uintptr(unsafe.Pointer(&text))) || uint64(uintptr(unsafe.Pointer(&etext))) < r.rip {
+	if r.rip < uint64(themoduledata.text) || uint64(themoduledata.etext) < r.rip {
 		return false
 	}
 
diff --git a/src/runtime/os3_plan9.go b/src/runtime/os3_plan9.go
index 27519de..fa49ad6 100644
--- a/src/runtime/os3_plan9.go
+++ b/src/runtime/os3_plan9.go
@@ -6,6 +6,8 @@
 
 import "unsafe"
 
+// May run during STW, so write barriers are not allowed.
+//go:nowritebarrier
 func sighandler(_ureg *ureg, note *byte, gp *g) int {
 	_g_ := getg()
 	var t sigTabT
@@ -79,7 +81,7 @@
 	}
 Throw:
 	_g_.m.throwing = 1
-	_g_.m.caughtsig = gp
+	setGNoWriteBarrier(&_g_.m.caughtsig, gp)
 	startpanic()
 	print(notestr, "\n")
 	print("PC=", hex(c.pc()), "\n")
diff --git a/src/runtime/os3_solaris.go b/src/runtime/os3_solaris.go
index 8c65567..7a4d27e 100644
--- a/src/runtime/os3_solaris.go
+++ b/src/runtime/os3_solaris.go
@@ -131,6 +131,8 @@
 
 func tstart_sysvicall()
 
+// May run with m.p==nil, so write barriers are not allowed.
+//go:nowritebarrier
 func newosproc(mp *m, _ unsafe.Pointer) {
 	var (
 		attr pthreadattr
diff --git a/src/runtime/os_linux_arm64.go b/src/runtime/os_linux_arm64.go
new file mode 100644
index 0000000..c3ad871
--- /dev/null
+++ b/src/runtime/os_linux_arm64.go
@@ -0,0 +1,19 @@
+// Copyright 2015 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 runtime
+
+const (
+	_AT_NULL   = 0
+	_AT_RANDOM = 25 // introduced in 2.6.29
+)
+
+var randomNumber uint32
+
+func cputicks() int64 {
+	// Currently cputicks() is used in blocking profiler and to seed fastrand1().
+	// nanotime() is a poor approximation of CPU ticks that is enough for the profiler.
+	// randomNumber provides better seeding of fastrand1.
+	return nanotime() + int64(randomNumber)
+}
diff --git a/src/runtime/os_nacl.go b/src/runtime/os_nacl.go
index 138b984..a6a796c 100644
--- a/src/runtime/os_nacl.go
+++ b/src/runtime/os_nacl.go
@@ -52,3 +52,8 @@
 
 func raiseproc(sig int32) {
 }
+
+// Stubs so tests can link correctly.  These should never be called.
+func open(name *byte, mode, perm int32) int32
+func close(fd int32) int32
+func read(fd int32, p unsafe.Pointer, n int32) int32
diff --git a/src/runtime/os_openbsd_arm.go b/src/runtime/os_openbsd_arm.go
new file mode 100644
index 0000000..be3f330
--- /dev/null
+++ b/src/runtime/os_openbsd_arm.go
@@ -0,0 +1,17 @@
+// Copyright 2013 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 runtime
+
+func checkgoarm() {
+	// TODO(minux)
+}
+
+//go:nosplit
+func cputicks() int64 {
+	// Currently cputicks() is used in blocking profiler and to seed runtime·fastrand1().
+	// runtime·nanotime() is a poor approximation of CPU ticks that is enough for the profiler.
+	// TODO: need more entropy to better seed fastrand1.
+	return nanotime()
+}
diff --git a/src/runtime/os_windows.go b/src/runtime/os_windows.go
index 3cce67f..744dc66 100644
--- a/src/runtime/os_windows.go
+++ b/src/runtime/os_windows.go
@@ -4,7 +4,7 @@
 
 package runtime
 
-import _ "unsafe" // for go:linkname
+import "unsafe"
 
 type stdFunction *byte
 
@@ -39,3 +39,17 @@
 	}
 	throw("fault")
 }
+
+// Stubs so tests can link correctly.  These should never be called.
+func open(name *byte, mode, perm int32) int32 {
+	throw("unimplemented")
+	return -1
+}
+func close(fd int32) int32 {
+	throw("unimplemented")
+	return -1
+}
+func read(fd int32, p unsafe.Pointer, n int32) int32 {
+	throw("unimplemented")
+	return -1
+}
diff --git a/src/runtime/panic.go b/src/runtime/panic.go
index e2a5c62..9b937f5 100644
--- a/src/runtime/panic.go
+++ b/src/runtime/panic.go
@@ -166,9 +166,20 @@
 	mp := acquirem()
 	if sc < uintptr(len(p{}.deferpool)) {
 		pp := mp.p
-		d = pp.deferpool[sc]
-		if d != nil {
-			pp.deferpool[sc] = d.link
+		if len(pp.deferpool[sc]) == 0 && sched.deferpool[sc] != nil {
+			lock(&sched.deferlock)
+			for len(pp.deferpool[sc]) < cap(pp.deferpool[sc])/2 && sched.deferpool[sc] != nil {
+				d := sched.deferpool[sc]
+				sched.deferpool[sc] = d.link
+				d.link = nil
+				pp.deferpool[sc] = append(pp.deferpool[sc], d)
+			}
+			unlock(&sched.deferlock)
+		}
+		if n := len(pp.deferpool[sc]); n > 0 {
+			d = pp.deferpool[sc][n-1]
+			pp.deferpool[sc][n-1] = nil
+			pp.deferpool[sc] = pp.deferpool[sc][:n-1]
 		}
 	}
 	if d == nil {
@@ -196,7 +207,6 @@
 
 // Free the given defer.
 // The defer cannot be used after this call.
-//go:nosplit
 func freedefer(d *_defer) {
 	if d._panic != nil {
 		freedeferpanic()
@@ -214,9 +224,28 @@
 	if sc < uintptr(len(p{}.deferpool)) {
 		mp := acquirem()
 		pp := mp.p
+		if len(pp.deferpool[sc]) == cap(pp.deferpool[sc]) {
+			// Transfer half of local cache to the central cache.
+			var first, last *_defer
+			for len(pp.deferpool[sc]) > cap(pp.deferpool[sc])/2 {
+				n := len(pp.deferpool[sc])
+				d := pp.deferpool[sc][n-1]
+				pp.deferpool[sc][n-1] = nil
+				pp.deferpool[sc] = pp.deferpool[sc][:n-1]
+				if first == nil {
+					first = d
+				} else {
+					last.link = d
+				}
+				last = d
+			}
+			lock(&sched.deferlock)
+			last.link = sched.deferpool[sc]
+			sched.deferpool[sc] = first
+			unlock(&sched.deferlock)
+		}
 		*d = _defer{}
-		d.link = pp.deferpool[sc]
-		pp.deferpool[sc] = d
+		pp.deferpool[sc] = append(pp.deferpool[sc], d)
 		releasem(mp)
 	}
 }
@@ -267,7 +296,10 @@
 	fn := d.fn
 	d.fn = nil
 	gp._defer = d.link
-	freedefer(d)
+	// Switch to systemstack merely to save nosplit stack space.
+	systemstack(func() {
+		freedefer(d)
+	})
 	releasem(mp)
 	jmpdefer(fn, uintptr(unsafe.Pointer(&arg0)))
 }
diff --git a/src/runtime/panic1.go b/src/runtime/panic1.go
index 4c0eb40..c14cf27 100644
--- a/src/runtime/panic1.go
+++ b/src/runtime/panic1.go
@@ -10,7 +10,7 @@
 //uint32 runtime·panicking;
 var paniclk mutex
 
-const hasLinkRegister = GOARCH == "arm" || GOARCH == "ppc64" || GOARCH == "ppc64le"
+const hasLinkRegister = GOARCH == "arm" || GOARCH == "arm64" || GOARCH == "ppc64" || GOARCH == "ppc64le"
 
 // Unwind the stack after a deferred function calls recover
 // after a panic.  Then arrange to continue running as though
diff --git a/src/runtime/pprof/pprof_test.go b/src/runtime/pprof/pprof_test.go
index eeb6d10..65d0a0a 100644
--- a/src/runtime/pprof/pprof_test.go
+++ b/src/runtime/pprof/pprof_test.go
@@ -143,7 +143,9 @@
 
 	// Check that profile is well formed and contains need.
 	have := make([]uintptr, len(need))
+	var samples uintptr
 	parseProfile(t, prof.Bytes(), func(count uintptr, stk []uintptr) {
+		samples += count
 		for _, pc := range stk {
 			f := runtime.FuncForPC(pc)
 			if f == nil {
@@ -156,6 +158,7 @@
 			}
 		}
 	})
+	t.Logf("total %d CPU profile samples collected", samples)
 
 	if len(need) == 0 {
 		return
@@ -200,6 +203,8 @@
 	}
 }
 
+// Fork can hang if preempted with signals frequently enough (see issue 5517).
+// Ensure that we do not do this.
 func TestCPUProfileWithFork(t *testing.T) {
 	if runtime.GOOS == "darwin" {
 		if runtime.GOARCH == "arm" {
@@ -207,9 +212,11 @@
 		}
 	}
 
-	// Fork can hang if preempted with signals frequently enough (see issue 5517).
-	// Ensure that we do not do this.
 	heap := 1 << 30
+	if runtime.GOOS == "android" {
+		// Use smaller size for Android to avoid crash.
+		heap = 100 << 20
+	}
 	if testing.Short() {
 		heap = 100 << 20
 	}
@@ -232,7 +239,7 @@
 	defer StopCPUProfile()
 
 	for i := 0; i < 10; i++ {
-		exec.Command("go").CombinedOutput()
+		exec.Command(os.Args[0], "-h").CombinedOutput()
 	}
 }
 
diff --git a/src/runtime/pprof/trace_stack_test.go b/src/runtime/pprof/trace_stack_test.go
new file mode 100644
index 0000000..984879d
--- /dev/null
+++ b/src/runtime/pprof/trace_stack_test.go
@@ -0,0 +1,285 @@
+// 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.
+
+package pprof_test
+
+import (
+	"bytes"
+	"internal/trace"
+	"net"
+	"os"
+	"runtime"
+	. "runtime/pprof"
+	"sync"
+	"testing"
+	"time"
+)
+
+// TestTraceSymbolize tests symbolization and that events has proper stacks.
+// In particular that we strip bottom uninteresting frames like goexit,
+// top uninteresting frames (runtime guts).
+func TestTraceSymbolize(t *testing.T) {
+	skipTraceTestsIfNeeded(t)
+	if runtime.GOOS == "nacl" {
+		t.Skip("skipping: nacl tests fail with 'failed to symbolize trace: failed to start addr2line'")
+	}
+	buf := new(bytes.Buffer)
+	if err := StartTrace(buf); err != nil {
+		t.Fatalf("failed to start tracing: %v", err)
+	}
+
+	// Now we will do a bunch of things for which we verify stacks later.
+	// It is impossible to ensure that a goroutine has actually blocked
+	// on a channel, in a select or otherwise. So we kick off goroutines
+	// that need to block first in the hope that while we are executing
+	// the rest of the test, they will block.
+	go func() {
+		select {}
+	}()
+	go func() {
+		var c chan int
+		c <- 0
+	}()
+	go func() {
+		var c chan int
+		<-c
+	}()
+	done1 := make(chan bool)
+	go func() {
+		<-done1
+	}()
+	done2 := make(chan bool)
+	go func() {
+		done2 <- true
+	}()
+	c1 := make(chan int)
+	c2 := make(chan int)
+	go func() {
+		select {
+		case <-c1:
+		case <-c2:
+		}
+	}()
+	var mu sync.Mutex
+	mu.Lock()
+	go func() {
+		mu.Lock()
+		mu.Unlock()
+	}()
+	var wg sync.WaitGroup
+	wg.Add(1)
+	go func() {
+		wg.Wait()
+	}()
+	cv := sync.NewCond(&sync.Mutex{})
+	go func() {
+		cv.L.Lock()
+		cv.Wait()
+		cv.L.Unlock()
+	}()
+	ln, err := net.Listen("tcp", "localhost:0")
+	if err != nil {
+		t.Fatalf("failed to listen: %v", err)
+	}
+	go func() {
+		c, err := ln.Accept()
+		if err != nil {
+			t.Fatalf("failed to accept: %v", err)
+		}
+		c.Close()
+	}()
+	rp, wp, err := os.Pipe()
+	if err != nil {
+		t.Fatalf("failed to create a pipe: %v", err)
+	}
+	defer rp.Close()
+	defer wp.Close()
+	pipeReadDone := make(chan bool)
+	go func() {
+		var data [1]byte
+		rp.Read(data[:])
+		pipeReadDone <- true
+	}()
+
+	time.Sleep(time.Millisecond)
+	runtime.GC()
+	runtime.Gosched()
+	time.Sleep(time.Millisecond) // the last chance for the goroutines above to block
+	done1 <- true
+	<-done2
+	select {
+	case c1 <- 0:
+	case c2 <- 0:
+	}
+	mu.Unlock()
+	wg.Done()
+	cv.Signal()
+	c, err := net.Dial("tcp", ln.Addr().String())
+	if err != nil {
+		t.Fatalf("failed to dial: %v", err)
+	}
+	c.Close()
+	var data [1]byte
+	wp.Write(data[:])
+	<-pipeReadDone
+
+	StopTrace()
+	events, _, err := parseTrace(buf)
+	if err != nil {
+		t.Fatalf("failed to parse trace: %v", err)
+	}
+	err = trace.Symbolize(events, os.Args[0])
+	if err != nil {
+		t.Fatalf("failed to symbolize trace: %v", err)
+	}
+
+	// Now check that the stacks are correct.
+	type frame struct {
+		Fn   string
+		Line int
+	}
+	type eventDesc struct {
+		Type byte
+		Stk  []frame
+	}
+	want := []eventDesc{
+		eventDesc{trace.EvGCStart, []frame{
+			frame{"runtime.GC", 0},
+			frame{"runtime/pprof_test.TestTraceSymbolize", 106},
+			frame{"testing.tRunner", 0},
+		}},
+		eventDesc{trace.EvGoSched, []frame{
+			frame{"runtime/pprof_test.TestTraceSymbolize", 107},
+			frame{"testing.tRunner", 0},
+		}},
+		eventDesc{trace.EvGoCreate, []frame{
+			frame{"runtime/pprof_test.TestTraceSymbolize", 39},
+			frame{"testing.tRunner", 0},
+		}},
+		eventDesc{trace.EvGoStop, []frame{
+			frame{"runtime.block", 0},
+			frame{"runtime/pprof_test.TestTraceSymbolize.func1", 38},
+		}},
+		eventDesc{trace.EvGoStop, []frame{
+			frame{"runtime.chansend1", 0},
+			frame{"runtime/pprof_test.TestTraceSymbolize.func2", 42},
+		}},
+		eventDesc{trace.EvGoStop, []frame{
+			frame{"runtime.chanrecv1", 0},
+			frame{"runtime/pprof_test.TestTraceSymbolize.func3", 46},
+		}},
+		eventDesc{trace.EvGoBlockRecv, []frame{
+			frame{"runtime.chanrecv1", 0},
+			frame{"runtime/pprof_test.TestTraceSymbolize.func4", 50},
+		}},
+		eventDesc{trace.EvGoUnblock, []frame{
+			frame{"runtime.chansend1", 0},
+			frame{"runtime/pprof_test.TestTraceSymbolize", 109},
+			frame{"testing.tRunner", 0},
+		}},
+		eventDesc{trace.EvGoBlockSend, []frame{
+			frame{"runtime.chansend1", 0},
+			frame{"runtime/pprof_test.TestTraceSymbolize.func5", 54},
+		}},
+		eventDesc{trace.EvGoUnblock, []frame{
+			frame{"runtime.chanrecv1", 0},
+			frame{"runtime/pprof_test.TestTraceSymbolize", 110},
+			frame{"testing.tRunner", 0},
+		}},
+		eventDesc{trace.EvGoBlockSelect, []frame{
+			frame{"runtime.selectgo", 0},
+			frame{"runtime/pprof_test.TestTraceSymbolize.func6", 59},
+		}},
+		eventDesc{trace.EvGoUnblock, []frame{
+			frame{"runtime.selectgo", 0},
+			frame{"runtime/pprof_test.TestTraceSymbolize", 111},
+			frame{"testing.tRunner", 0},
+		}},
+		eventDesc{trace.EvGoBlockSync, []frame{
+			frame{"sync.(*Mutex).Lock", 0},
+			frame{"runtime/pprof_test.TestTraceSymbolize.func7", 67},
+		}},
+		eventDesc{trace.EvGoUnblock, []frame{
+			frame{"sync.(*Mutex).Unlock", 0},
+			frame{"runtime/pprof_test.TestTraceSymbolize", 115},
+			frame{"testing.tRunner", 0},
+		}},
+		eventDesc{trace.EvGoBlockSync, []frame{
+			frame{"sync.(*WaitGroup).Wait", 0},
+			frame{"runtime/pprof_test.TestTraceSymbolize.func8", 73},
+		}},
+		eventDesc{trace.EvGoUnblock, []frame{
+			frame{"sync.(*WaitGroup).Add", 0},
+			frame{"sync.(*WaitGroup).Done", 0},
+			frame{"runtime/pprof_test.TestTraceSymbolize", 116},
+			frame{"testing.tRunner", 0},
+		}},
+		eventDesc{trace.EvGoBlockCond, []frame{
+			frame{"sync.(*Cond).Wait", 0},
+			frame{"runtime/pprof_test.TestTraceSymbolize.func9", 78},
+		}},
+		eventDesc{trace.EvGoUnblock, []frame{
+			frame{"sync.(*Cond).Signal", 0},
+			frame{"runtime/pprof_test.TestTraceSymbolize", 117},
+			frame{"testing.tRunner", 0},
+		}},
+		eventDesc{trace.EvGoSleep, []frame{
+			frame{"time.Sleep", 0},
+			frame{"runtime/pprof_test.TestTraceSymbolize", 108},
+			frame{"testing.tRunner", 0},
+		}},
+	}
+	// Stacks for the following events are OS-dependent due to OS-specific code in net package.
+	if runtime.GOOS != "windows" && runtime.GOOS != "plan9" {
+		want = append(want, []eventDesc{
+			eventDesc{trace.EvGoBlockNet, []frame{
+				frame{"net.(*netFD).accept", 0},
+				frame{"net.(*TCPListener).AcceptTCP", 0},
+				frame{"net.(*TCPListener).Accept", 0},
+				frame{"runtime/pprof_test.TestTraceSymbolize.func10", 86},
+			}},
+			eventDesc{trace.EvGoSysCall, []frame{
+				frame{"syscall.read", 0},
+				frame{"syscall.Read", 0},
+				frame{"os.(*File).read", 0},
+				frame{"os.(*File).Read", 0},
+				frame{"runtime/pprof_test.TestTraceSymbolize.func11", 101},
+			}},
+		}...)
+	}
+	matched := make([]bool, len(want))
+	for _, ev := range events {
+	wantLoop:
+		for i, w := range want {
+			if matched[i] || w.Type != ev.Type || len(w.Stk) != len(ev.Stk) {
+				continue
+			}
+
+			for fi, f := range ev.Stk {
+				wf := w.Stk[fi]
+				if wf.Fn != f.Fn || wf.Line != 0 && wf.Line != f.Line {
+					continue wantLoop
+				}
+			}
+			matched[i] = true
+		}
+	}
+	for i, m := range matched {
+		if m {
+			continue
+		}
+		w := want[i]
+		t.Errorf("did not match event %v at %v:%v", trace.EventDescriptions[w.Type].Name, w.Stk[0].Fn, w.Stk[0].Line)
+		t.Errorf("seen the following events of this type:")
+		for _, ev := range events {
+			if ev.Type != w.Type {
+				continue
+			}
+			for _, f := range ev.Stk {
+				t.Logf("  %v:%v", f.Fn, f.Line)
+			}
+			t.Logf("---")
+		}
+	}
+}
diff --git a/src/runtime/pprof/trace_test.go b/src/runtime/pprof/trace_test.go
index e19e695..2b85e47 100644
--- a/src/runtime/pprof/trace_test.go
+++ b/src/runtime/pprof/trace_test.go
@@ -7,11 +7,11 @@
 import (
 	"bytes"
 	"internal/trace"
+	"io"
 	"net"
 	"os"
 	"runtime"
 	. "runtime/pprof"
-	"strings"
 	"sync"
 	"testing"
 	"time"
@@ -73,6 +73,20 @@
 	}
 }
 
+func parseTrace(r io.Reader) ([]*trace.Event, map[uint64]*trace.GDesc, error) {
+	events, err := trace.Parse(r)
+	if err != nil {
+		return nil, nil, err
+	}
+	gs := trace.GoroutineStats(events)
+	for goid := range gs {
+		// We don't do any particular checks on the result at the moment.
+		// But still check that RelatedGoroutines does not crash, hang, etc.
+		_ = trace.RelatedGoroutines(events, goid)
+	}
+	return events, gs, nil
+}
+
 func TestTraceStress(t *testing.T) {
 	skipTraceTestsIfNeeded(t)
 
@@ -102,7 +116,7 @@
 		<-done
 		wg.Done()
 	}()
-	time.Sleep(time.Millisecond)
+	time.Sleep(time.Millisecond) // give the goroutine above time to block
 
 	buf := new(bytes.Buffer)
 	if err := StartTrace(buf); err != nil {
@@ -110,6 +124,7 @@
 	}
 
 	procs := runtime.GOMAXPROCS(10)
+	time.Sleep(50 * time.Millisecond) // test proc stop/start events
 
 	go func() {
 		runtime.LockOSThread()
@@ -199,7 +214,7 @@
 	runtime.GOMAXPROCS(procs)
 
 	StopTrace()
-	_, err = trace.Parse(buf)
+	_, _, err = parseTrace(buf)
 	if err != nil {
 		t.Fatalf("failed to parse trace: %v", err)
 	}
@@ -339,48 +354,97 @@
 		}
 		time.Sleep(time.Millisecond)
 		StopTrace()
-		if _, err := trace.Parse(buf); err != nil {
+		if _, _, err := parseTrace(buf); err != nil {
 			t.Fatalf("failed to parse trace: %v", err)
 		}
 	}
 	<-outerDone
 }
 
-func TestTraceSymbolize(t *testing.T) {
+func TestTraceFutileWakeup(t *testing.T) {
+	// The test generates a full-load of futile wakeups on channels,
+	// and ensures that the trace is consistent after their removal.
 	skipTraceTestsIfNeeded(t)
-	if runtime.GOOS == "nacl" {
-		t.Skip("skipping: nacl tests fail with 'failed to symbolize trace: failed to start addr2line'")
-	}
 	buf := new(bytes.Buffer)
 	if err := StartTrace(buf); err != nil {
 		t.Fatalf("failed to start tracing: %v", err)
 	}
-	runtime.GC()
+
+	defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(8))
+	c0 := make(chan int, 1)
+	c1 := make(chan int, 1)
+	c2 := make(chan int, 1)
+	const procs = 2
+	var done sync.WaitGroup
+	done.Add(4 * procs)
+	for p := 0; p < procs; p++ {
+		const iters = 1e3
+		go func() {
+			for i := 0; i < iters; i++ {
+				runtime.Gosched()
+				c0 <- 0
+			}
+			done.Done()
+		}()
+		go func() {
+			for i := 0; i < iters; i++ {
+				runtime.Gosched()
+				<-c0
+			}
+			done.Done()
+		}()
+		go func() {
+			for i := 0; i < iters; i++ {
+				runtime.Gosched()
+				select {
+				case c1 <- 0:
+				case c2 <- 0:
+				}
+			}
+			done.Done()
+		}()
+		go func() {
+			for i := 0; i < iters; i++ {
+				runtime.Gosched()
+				select {
+				case <-c1:
+				case <-c2:
+				}
+			}
+			done.Done()
+		}()
+	}
+	done.Wait()
+
 	StopTrace()
-	events, err := trace.Parse(buf)
+	events, _, err := parseTrace(buf)
 	if err != nil {
 		t.Fatalf("failed to parse trace: %v", err)
 	}
-	err = trace.Symbolize(events, os.Args[0])
-	if err != nil {
-		t.Fatalf("failed to symbolize trace: %v", err)
-	}
-	found := false
-eventLoop:
+	// Check that (1) trace does not contain EvFutileWakeup events and
+	// (2) there are no consecutive EvGoBlock/EvGCStart/EvGoBlock events
+	// (we call runtime.Gosched between all operations, so these would be futile wakeups).
+	gs := make(map[uint64]int)
 	for _, ev := range events {
-		if ev.Type != trace.EvGCStart {
-			continue
-		}
-		for _, f := range ev.Stk {
-			if strings.HasSuffix(f.File, "trace_test.go") &&
-				strings.HasSuffix(f.Fn, "pprof_test.TestTraceSymbolize") &&
-				f.Line == 358 {
-				found = true
-				break eventLoop
+		switch ev.Type {
+		case trace.EvFutileWakeup:
+			t.Fatalf("found EvFutileWakeup event")
+		case trace.EvGoBlockSend, trace.EvGoBlockRecv, trace.EvGoBlockSelect:
+			if gs[ev.G] == 2 {
+				t.Fatalf("goroutine %v blocked on %v at %v right after start",
+					ev.G, trace.EventDescriptions[ev.Type].Name, ev.Ts)
 			}
+			if gs[ev.G] == 1 {
+				t.Fatalf("goroutine %v blocked on %v at %v while blocked",
+					ev.G, trace.EventDescriptions[ev.Type].Name, ev.Ts)
+			}
+			gs[ev.G] = 1
+		case trace.EvGoStart:
+			if gs[ev.G] == 1 {
+				gs[ev.G] = 2
+			}
+		default:
+			delete(gs, ev.G)
 		}
 	}
-	if !found {
-		t.Fatalf("the trace does not contain GC event")
-	}
 }
diff --git a/src/runtime/proc.go b/src/runtime/proc.go
index d251c31..edab9bf 100644
--- a/src/runtime/proc.go
+++ b/src/runtime/proc.go
@@ -58,7 +58,7 @@
 		}
 	}()
 
-	memstats.enablegc = true // now that runtime is initialized, GC is okay
+	gcenable()
 
 	if iscgo {
 		if _cgo_thread_start == nil {
@@ -95,7 +95,7 @@
 	// let the other goroutine finish printing the panic trace.
 	// Once it does, it will exit. See issue 3934.
 	if panicking != 0 {
-		gopark(nil, nil, "panicwait", traceEvGoStop)
+		gopark(nil, nil, "panicwait", traceEvGoStop, 1)
 	}
 
 	exit(0)
@@ -105,6 +105,14 @@
 	}
 }
 
+// os_beforeExit is called from os.Exit(0).
+//go:linkname os_beforeExit os.runtime_beforeExit
+func os_beforeExit() {
+	if raceenabled {
+		racefini()
+	}
+}
+
 // start forcegc helper goroutine
 func init() {
 	go forcegchelper()
@@ -118,7 +126,7 @@
 			throw("forcegc: phase error")
 		}
 		atomicstore(&forcegc.idle, 1)
-		goparkunlock(&forcegc.lock, "force gc (idle)", traceEvGoBlock)
+		goparkunlock(&forcegc.lock, "force gc (idle)", traceEvGoBlock, 1)
 		// this goroutine is explicitly resumed by sysmon
 		if debug.gctrace > 0 {
 			println("GC forced")
@@ -137,7 +145,7 @@
 
 // Puts the current goroutine into a waiting state and calls unlockf.
 // If unlockf returns false, the goroutine is resumed.
-func gopark(unlockf func(*g, unsafe.Pointer) bool, lock unsafe.Pointer, reason string, traceEv byte) {
+func gopark(unlockf func(*g, unsafe.Pointer) bool, lock unsafe.Pointer, reason string, traceEv byte, traceskip int) {
 	mp := acquirem()
 	gp := mp.curg
 	status := readgstatus(gp)
@@ -148,6 +156,7 @@
 	mp.waitunlockf = *(*unsafe.Pointer)(unsafe.Pointer(&unlockf))
 	gp.waitreason = reason
 	mp.waittraceev = traceEv
+	mp.waittraceskip = traceskip
 	releasem(mp)
 	// can't do anything that might move the G between Ms here.
 	mcall(park_m)
@@ -155,29 +164,18 @@
 
 // Puts the current goroutine into a waiting state and unlocks the lock.
 // The goroutine can be made runnable again by calling goready(gp).
-func goparkunlock(lock *mutex, reason string, traceEv byte) {
-	gopark(parkunlock_c, unsafe.Pointer(lock), reason, traceEv)
+func goparkunlock(lock *mutex, reason string, traceEv byte, traceskip int) {
+	gopark(parkunlock_c, unsafe.Pointer(lock), reason, traceEv, traceskip)
 }
 
-func goready(gp *g) {
+func goready(gp *g, traceskip int) {
 	systemstack(func() {
-		ready(gp)
+		ready(gp, traceskip)
 	})
 }
 
 //go:nosplit
 func acquireSudog() *sudog {
-	c := gomcache()
-	s := c.sudogcache
-	if s != nil {
-		if s.elem != nil {
-			throw("acquireSudog: found s.elem != nil in cache")
-		}
-		c.sudogcache = s.next
-		s.next = nil
-		return s
-	}
-
 	// Delicate dance: the semaphore implementation calls
 	// acquireSudog, acquireSudog calls new(sudog),
 	// new calls malloc, malloc can call the garbage collector,
@@ -187,12 +185,31 @@
 	// The acquirem/releasem increments m.locks during new(sudog),
 	// which keeps the garbage collector from being invoked.
 	mp := acquirem()
-	p := new(sudog)
-	if p.elem != nil {
-		throw("acquireSudog: found p.elem != nil after new")
+	pp := mp.p
+	if len(pp.sudogcache) == 0 {
+		lock(&sched.sudoglock)
+		// First, try to grab a batch from central cache.
+		for len(pp.sudogcache) < cap(pp.sudogcache)/2 && sched.sudogcache != nil {
+			s := sched.sudogcache
+			sched.sudogcache = s.next
+			s.next = nil
+			pp.sudogcache = append(pp.sudogcache, s)
+		}
+		unlock(&sched.sudoglock)
+		// If the central cache is empty, allocate a new one.
+		if len(pp.sudogcache) == 0 {
+			pp.sudogcache = append(pp.sudogcache, new(sudog))
+		}
+	}
+	n := len(pp.sudogcache)
+	s := pp.sudogcache[n-1]
+	pp.sudogcache[n-1] = nil
+	pp.sudogcache = pp.sudogcache[:n-1]
+	if s.elem != nil {
+		throw("acquireSudog: found s.elem != nil in cache")
 	}
 	releasem(mp)
-	return p
+	return s
 }
 
 //go:nosplit
@@ -216,9 +233,30 @@
 	if gp.param != nil {
 		throw("runtime: releaseSudog with non-nil gp.param")
 	}
-	c := gomcache()
-	s.next = c.sudogcache
-	c.sudogcache = s
+	mp := acquirem() // avoid rescheduling to another P
+	pp := mp.p
+	if len(pp.sudogcache) == cap(pp.sudogcache) {
+		// Transfer half of local cache to the central cache.
+		var first, last *sudog
+		for len(pp.sudogcache) > cap(pp.sudogcache)/2 {
+			n := len(pp.sudogcache)
+			p := pp.sudogcache[n-1]
+			pp.sudogcache[n-1] = nil
+			pp.sudogcache = pp.sudogcache[:n-1]
+			if first == nil {
+				first = p
+			} else {
+				last.next = p
+			}
+			last = p
+		}
+		lock(&sched.sudoglock)
+		last.next = sched.sudogcache
+		sched.sudogcache = first
+		unlock(&sched.sudoglock)
+	}
+	pp.sudogcache = append(pp.sudogcache, s)
+	releasem(mp)
 }
 
 // funcPC returns the entry PC of the function f.
diff --git a/src/runtime/proc1.go b/src/runtime/proc1.go
index f3248a5..7fa519d 100644
--- a/src/runtime/proc1.go
+++ b/src/runtime/proc1.go
@@ -128,9 +128,9 @@
 }
 
 // Mark gp ready to run.
-func ready(gp *g) {
+func ready(gp *g, traceskip int) {
 	if trace.enabled {
-		traceGoUnpark(gp)
+		traceGoUnpark(gp, traceskip)
 	}
 
 	status := readgstatus(gp)
@@ -447,7 +447,7 @@
 			throw("processing Gscanenqueue on wrong m")
 		}
 		dropg()
-		ready(gp)
+		ready(gp, 0)
 	}
 }
 
@@ -717,10 +717,15 @@
 	// Install signal handlers; after minit so that minit can
 	// prepare the thread to be able to handle the signals.
 	if _g_.m == &m0 {
+		// Create an extra M for callbacks on threads not created by Go.
+		if iscgo && !cgoHasExtraM {
+			cgoHasExtraM = true
+			newextram()
+		}
 		initsig()
 	}
 
-	if _g_.m.mstartfn != nil {
+	if _g_.m.mstartfn != 0 {
 		fn := *(*func())(unsafe.Pointer(&_g_.m.mstartfn))
 		fn()
 	}
@@ -733,10 +738,6 @@
 		_g_.m.nextp = nil
 	}
 	schedule()
-
-	// TODO(brainman): This point is never reached, because scheduler
-	// does not release os threads at the moment. But once this path
-	// is enabled, we must remove our seh here.
 }
 
 // When running with cgo, we call _cgo_thread_start
@@ -816,7 +817,7 @@
 // put the m back on the list.
 //go:nosplit
 func needm(x byte) {
-	if needextram != 0 {
+	if iscgo && !cgoHasExtraM {
 		// Can happen if C/C++ code calls Go from a global ctor.
 		// Can not throw, because scheduler is not initialized yet.
 		write(2, unsafe.Pointer(&earlycgocallback[0]), int32(len(earlycgocallback)))
@@ -971,17 +972,22 @@
 }
 
 // Create a new m.  It will start off with a call to fn, or else the scheduler.
+// fn needs to be static and not a heap allocated closure.
+// May run with m.p==nil, so write barriers are not allowed.
+//go:nowritebarrier
 func newm(fn func(), _p_ *p) {
 	mp := allocm(_p_)
-	mp.nextp = _p_
-	mp.mstartfn = *(*unsafe.Pointer)(unsafe.Pointer(&fn))
-
+	// procresize made _p_ reachable through allp, which doesn't change during GC, so WB can be eliminated
+	setPNoWriteBarrier(&mp.nextp, _p_)
+	// Store &fn as a uintptr since it is not heap allocated so the WB can be eliminated
+	mp.mstartfn = *(*uintptr)(unsafe.Pointer(&fn))
 	if iscgo {
 		var ts cgothreadstart
 		if _cgo_thread_start == nil {
 			throw("_cgo_thread_start missing")
 		}
-		ts.g = mp.g0
+		// mp is reachable via allm and mp.g0 never changes, so WB can be eliminated.
+		setGNoWriteBarrier(&ts.g, mp.g0)
 		ts.tls = (*uint64)(unsafe.Pointer(&mp.tls[0]))
 		ts.fn = unsafe.Pointer(funcPC(mstart))
 		asmcgocall(_cgo_thread_start, unsafe.Pointer(&ts))
@@ -1029,6 +1035,8 @@
 
 // Schedules some M to run the p (creates an M if necessary).
 // If p==nil, tries to get an idle P, if no idle P's does nothing.
+// May run with m.p==nil, so write barriers are not allowed.
+//go:nowritebarrier
 func startm(_p_ *p, spinning bool) {
 	lock(&sched.lock)
 	if _p_ == nil {
@@ -1058,11 +1066,14 @@
 		throw("startm: m has p")
 	}
 	mp.spinning = spinning
-	mp.nextp = _p_
+	// procresize made _p_ reachable through allp, which doesn't change during GC, so WB can be eliminated
+	setPNoWriteBarrier(&mp.nextp, _p_)
 	notewakeup(&mp.park)
 }
 
 // Hands off P from syscall or locked M.
+// Always runs without a P, so write barriers are not allowed.
+//go:nowritebarrier
 func handoffp(_p_ *p) {
 	// if it has local work, start it straight away
 	if _p_.runqhead != _p_.runqtail || sched.runqsize != 0 {
@@ -1139,6 +1150,8 @@
 }
 
 // Schedules the locked m to run the locked gp.
+// May run during STW, so write barriers are not allowed.
+//go:nowritebarrier
 func startlockedm(gp *g) {
 	_g_ := getg()
 
@@ -1152,7 +1165,8 @@
 	// directly handoff current P to the locked m
 	incidlelocked(-1)
 	_p_ := releasep()
-	mp.nextp = _p_
+	// procresize made _p_ reachable through allp, which doesn't change during GC, so WB can be eliminated
+	setPNoWriteBarrier(&mp.nextp, _p_)
 	notewakeup(&mp.park)
 	stopm()
 }
@@ -1218,7 +1232,7 @@
 	}
 	if fingwait && fingwake {
 		if gp := wakefing(); gp != nil {
-			ready(gp)
+			ready(gp, 0)
 		}
 	}
 
@@ -1249,7 +1263,7 @@
 			injectglist(gp.schedlink)
 			casgstatus(gp, _Gwaiting, _Grunnable)
 			if trace.enabled {
-				traceGoUnpark(gp)
+				traceGoUnpark(gp, 0)
 			}
 			return gp
 		}
@@ -1336,7 +1350,7 @@
 				injectglist(gp.schedlink)
 				casgstatus(gp, _Gwaiting, _Grunnable)
 				if trace.enabled {
-					traceGoUnpark(gp)
+					traceGoUnpark(gp, 0)
 				}
 				return gp
 			}
@@ -1376,7 +1390,7 @@
 	}
 	if trace.enabled {
 		for gp := glist; gp != nil; gp = gp.schedlink {
-			traceGoUnpark(gp)
+			traceGoUnpark(gp, 0)
 		}
 	}
 	lock(&sched.lock)
@@ -1418,7 +1432,7 @@
 		gp = traceReader()
 		if gp != nil {
 			casgstatus(gp, _Gwaiting, _Grunnable)
-			traceGoUnpark(gp)
+			traceGoUnpark(gp, 0)
 			resetspinning()
 		}
 	}
@@ -1472,35 +1486,17 @@
 	}
 }
 
-// Puts the current goroutine into a waiting state and calls unlockf.
-// If unlockf returns false, the goroutine is resumed.
-func park(unlockf func(*g, unsafe.Pointer) bool, lock unsafe.Pointer, reason string, traceev byte) {
-	_g_ := getg()
-
-	_g_.m.waitlock = lock
-	_g_.m.waitunlockf = *(*unsafe.Pointer)(unsafe.Pointer(&unlockf))
-	_g_.m.waittraceev = traceev
-	_g_.waitreason = reason
-	mcall(park_m)
-}
-
 func parkunlock_c(gp *g, lock unsafe.Pointer) bool {
 	unlock((*mutex)(lock))
 	return true
 }
 
-// Puts the current goroutine into a waiting state and unlocks the lock.
-// The goroutine can be made runnable again by calling ready(gp).
-func parkunlock(lock *mutex, reason string, traceev byte) {
-	park(parkunlock_c, unsafe.Pointer(lock), reason, traceev)
-}
-
 // park continuation on g0.
 func park_m(gp *g) {
 	_g_ := getg()
 
 	if trace.enabled {
-		traceGoPark(_g_.m.waittraceev, gp)
+		traceGoPark(_g_.m.waittraceev, _g_.m.waittraceskip, gp)
 	}
 
 	casgstatus(gp, _Grunning, _Gwaiting)
@@ -1513,7 +1509,7 @@
 		_g_.m.waitlock = nil
 		if !ok {
 			if trace.enabled {
-				traceGoUnpark(gp)
+				traceGoUnpark(gp, 2)
 			}
 			casgstatus(gp, _Gwaiting, _Grunnable)
 			execute(gp) // Schedule it back, never returns.
@@ -1823,7 +1819,11 @@
 		for oldp != nil && oldp.syscalltick == _g_.m.syscalltick {
 			osyield()
 		}
-		systemstack(traceGoSysExit)
+		// This can't be done since the GC may be running and this code
+		// will invoke write barriers.
+		// TODO: Figure out how to get traceGoSysExit into the trace log or
+		// it is likely not to work as expected.
+		//		systemstack(traceGoSysExit)
 	}
 
 	_g_.m.locks--
@@ -2060,15 +2060,19 @@
 		throw("newproc1: new g is not Gdead")
 	}
 
-	sp := newg.stack.hi
-	sp -= 4 * regSize // extra space in case of reads slightly beyond frame
-	sp -= uintptr(siz)
-	memmove(unsafe.Pointer(sp), unsafe.Pointer(argp), uintptr(narg))
+	totalSize := 4*regSize + uintptr(siz) // extra space in case of reads slightly beyond frame
+	if hasLinkRegister {
+		totalSize += ptrSize
+	}
+	totalSize += -totalSize & (spAlign - 1) // align to spAlign
+	sp := newg.stack.hi - totalSize
+	spArg := sp
 	if hasLinkRegister {
 		// caller's LR
-		sp -= ptrSize
 		*(*unsafe.Pointer)(unsafe.Pointer(sp)) = nil
+		spArg += ptrSize
 	}
+	memmove(unsafe.Pointer(spArg), unsafe.Pointer(argp), uintptr(narg))
 
 	memclr(unsafe.Pointer(&newg.sched), unsafe.Sizeof(newg.sched))
 	newg.sched.sp = sp
@@ -2289,8 +2293,6 @@
 func _ExternalCode() { _ExternalCode() }
 func _GC()           { _GC() }
 
-var etext struct{}
-
 // Called if we receive a SIGPROF signal.
 func sigprof(pc, sp, lr uintptr, gp *g, mp *m) {
 	if prof.hz == 0 {
@@ -2404,7 +2406,7 @@
 			// If all of the above has failed, account it against abstract "System" or "GC".
 			n = 2
 			// "ExternalCode" is better than "etext".
-			if pc > uintptr(unsafe.Pointer(&etext)) {
+			if pc > themoduledata.etext {
 				pc = funcPC(_ExternalCode) + _PCQuantum
 			}
 			stk[0] = pc
@@ -2483,6 +2485,10 @@
 			pp = new(p)
 			pp.id = i
 			pp.status = _Pgcstop
+			pp.sudogcache = pp.sudogbuf[:0]
+			for i := range pp.deferpool {
+				pp.deferpool[i] = pp.deferpoolbuf[i][:0]
+			}
 			atomicstorep(unsafe.Pointer(&allp[i]), unsafe.Pointer(pp))
 		}
 		if pp.mcache == nil {
@@ -2521,6 +2527,16 @@
 			}
 			sched.runqsize++
 		}
+		for i := range p.sudogbuf {
+			p.sudogbuf[i] = nil
+		}
+		p.sudogcache = p.sudogbuf[:0]
+		for i := range p.deferpool {
+			for j := range p.deferpoolbuf[i] {
+				p.deferpoolbuf[i][j] = nil
+			}
+			p.deferpool[i] = p.deferpoolbuf[i][:0]
+		}
 		freemcache(p.mcache)
 		p.mcache = nil
 		gfpurge(p)
@@ -2569,6 +2585,8 @@
 }
 
 // Associate p and the current m.
+// May run during STW, so write barriers are not allowed.
+//go:nowritebarrier
 func acquirep(_p_ *p) {
 	_g_ := getg()
 
@@ -2583,9 +2601,12 @@
 		print("acquirep: p->m=", _p_.m, "(", id, ") p->status=", _p_.status, "\n")
 		throw("acquirep: invalid p state")
 	}
-	_g_.m.mcache = _p_.mcache
-	_g_.m.p = _p_
-	_p_.m = _g_.m
+	// _p_.mcache holds the mcache and _p_ is in allp, so WB can be eliminated
+	setMcacheNoWriteBarrier(&_g_.m.mcache, _p_.mcache)
+	// _p_ is in allp so WB can be eliminated
+	setPNoWriteBarrier(&_g_.m.p, _p_)
+	// m is in _g_.m and is reachable through allg, so WB can be eliminated
+	setMNoWriteBarrier(&_p_.m, _g_.m)
 	_p_.status = _Prunning
 
 	if trace.enabled {
@@ -2991,19 +3012,26 @@
 
 // Put mp on midle list.
 // Sched must be locked.
+// May run during STW, so write barriers are not allowed.
+//go:nowritebarrier
 func mput(mp *m) {
-	mp.schedlink = sched.midle
-	sched.midle = mp
+	// sched.midle is reachable via allm, so WB can be eliminated.
+	setMNoWriteBarrier(&mp.schedlink, sched.midle)
+	// mp is reachable via allm, so WB can be eliminated.
+	setMNoWriteBarrier(&sched.midle, mp)
 	sched.nmidle++
 	checkdead()
 }
 
 // Try to get an m from midle list.
 // Sched must be locked.
+// May run during STW, so write barriers are not allowed.
+//go:nowritebarrier
 func mget() *m {
 	mp := sched.midle
 	if mp != nil {
-		sched.midle = mp.schedlink
+		// mp.schedlink is reachable via mp, which is on allm, so WB can be eliminated.
+		setMNoWriteBarrier(&sched.midle, mp.schedlink)
 		sched.nmidle--
 	}
 	return mp
@@ -3011,14 +3039,17 @@
 
 // Put gp on the global runnable queue.
 // Sched must be locked.
+// May run during STW, so write barriers are not allowed.
+//go:nowritebarrier
 func globrunqput(gp *g) {
 	gp.schedlink = nil
 	if sched.runqtail != nil {
-		sched.runqtail.schedlink = gp
+		// gp is on allg, so these three WBs can be eliminated.
+		setGNoWriteBarrier(&sched.runqtail.schedlink, gp)
 	} else {
-		sched.runqhead = gp
+		setGNoWriteBarrier(&sched.runqhead, gp)
 	}
-	sched.runqtail = gp
+	setGNoWriteBarrier(&sched.runqtail, gp)
 	sched.runqsize++
 }
 
@@ -3071,18 +3102,24 @@
 
 // Put p to on _Pidle list.
 // Sched must be locked.
+// May run during STW, so write barriers are not allowed.
+//go:nowritebarrier
 func pidleput(_p_ *p) {
-	_p_.link = sched.pidle
-	sched.pidle = _p_
+	// sched.pidle, _p_.link and _p_ are reachable via allp, so WB can be eliminated.
+	setPNoWriteBarrier(&_p_.link, sched.pidle)
+	setPNoWriteBarrier(&sched.pidle, _p_)
 	xadd(&sched.npidle, 1) // TODO: fast atomic
 }
 
 // Try get a p from _Pidle list.
 // Sched must be locked.
+// May run during STW, so write barriers are not allowed.
+//go:nowritebarrier
 func pidleget() *p {
 	_p_ := sched.pidle
 	if _p_ != nil {
-		sched.pidle = _p_.link
+		// _p_.link is reachable via a _p_ in  allp, so WB can be eliminated.
+		setPNoWriteBarrier(&sched.pidle, _p_.link)
 		xadd(&sched.npidle, -1) // TODO: fast atomic
 	}
 	return _p_
diff --git a/src/runtime/race/output_test.go b/src/runtime/race/output_test.go
index d2303f7..a9f9f0f 100644
--- a/src/runtime/race/output_test.go
+++ b/src/runtime/race/output_test.go
@@ -23,7 +23,11 @@
 			t.Fatalf("failed to create temp directory: %v", err)
 		}
 		defer os.RemoveAll(dir)
-		src := filepath.Join(dir, "main.go")
+		source := "main.go"
+		if test.run == "test" {
+			source = "main_test.go"
+		}
+		src := filepath.Join(dir, source)
 		f, err := os.Create(src)
 		if err != nil {
 			t.Fatalf("failed to create file: %v", err)
@@ -37,7 +41,7 @@
 			t.Fatalf("failed to close file: %v", err)
 		}
 		// Pass -l to the compiler to test stack traces.
-		cmd := exec.Command("go", "run", "-race", "-gcflags=-l", src)
+		cmd := exec.Command("go", test.run, "-race", "-gcflags=-l", src)
 		// GODEBUG spoils program output, GOMAXPROCS makes it flaky.
 		for _, env := range os.Environ() {
 			if strings.HasPrefix(env, "GODEBUG=") ||
@@ -58,11 +62,12 @@
 
 var tests = []struct {
 	name   string
+	run    string
 	gorace string
 	source string
 	re     string
 }{
-	{"simple", "atexit_sleep_ms=0", `
+	{"simple", "run", "atexit_sleep_ms=0", `
 package main
 import "time"
 func main() {
@@ -107,7 +112,7 @@
 exit status 66
 `},
 
-	{"exitcode", "atexit_sleep_ms=0 exitcode=13", `
+	{"exitcode", "run", "atexit_sleep_ms=0 exitcode=13", `
 package main
 func main() {
 	done := make(chan bool)
@@ -121,7 +126,7 @@
 }
 `, `exit status 13`},
 
-	{"strip_path_prefix", "atexit_sleep_ms=0 strip_path_prefix=/main.", `
+	{"strip_path_prefix", "run", "atexit_sleep_ms=0 strip_path_prefix=/main.", `
 package main
 func main() {
 	done := make(chan bool)
@@ -137,7 +142,7 @@
       go:7 \+0x[0-9,a-f]+
 `},
 
-	{"halt_on_error", "atexit_sleep_ms=0 halt_on_error=1", `
+	{"halt_on_error", "run", "atexit_sleep_ms=0 halt_on_error=1", `
 package main
 func main() {
 	done := make(chan bool)
@@ -153,4 +158,23 @@
 ==================
 exit status 66
 `},
+
+	{"test_fails_on_race", "test", "atexit_sleep_ms=0", `
+package main_test
+import "testing"
+func TestFail(t *testing.T) {
+	done := make(chan bool)
+	x := 0
+	go func() {
+		x = 42
+		done <- true
+	}()
+	x = 43
+	<-done
+}
+`, `
+==================
+PASS
+Found 1 data race\(s\)
+FAIL`},
 }
diff --git a/src/runtime/race1.go b/src/runtime/race1.go
index 4c14d84..18ecc88 100644
--- a/src/runtime/race1.go
+++ b/src/runtime/race1.go
@@ -119,29 +119,29 @@
 	// Round data segment to page boundaries, because it's used in mmap().
 	start := ^uintptr(0)
 	end := uintptr(0)
-	if start > uintptr(unsafe.Pointer(&noptrdata)) {
-		start = uintptr(unsafe.Pointer(&noptrdata))
+	if start > themoduledata.noptrdata {
+		start = themoduledata.noptrdata
 	}
-	if start > uintptr(unsafe.Pointer(&data)) {
-		start = uintptr(unsafe.Pointer(&data))
+	if start > themoduledata.data {
+		start = themoduledata.data
 	}
-	if start > uintptr(unsafe.Pointer(&noptrbss)) {
-		start = uintptr(unsafe.Pointer(&noptrbss))
+	if start > themoduledata.noptrbss {
+		start = themoduledata.noptrbss
 	}
-	if start > uintptr(unsafe.Pointer(&bss)) {
-		start = uintptr(unsafe.Pointer(&bss))
+	if start > themoduledata.bss {
+		start = themoduledata.bss
 	}
-	if end < uintptr(unsafe.Pointer(&enoptrdata)) {
-		end = uintptr(unsafe.Pointer(&enoptrdata))
+	if end < themoduledata.enoptrdata {
+		end = themoduledata.enoptrdata
 	}
-	if end < uintptr(unsafe.Pointer(&edata)) {
-		end = uintptr(unsafe.Pointer(&edata))
+	if end < themoduledata.edata {
+		end = themoduledata.edata
 	}
-	if end < uintptr(unsafe.Pointer(&enoptrbss)) {
-		end = uintptr(unsafe.Pointer(&enoptrbss))
+	if end < themoduledata.enoptrbss {
+		end = themoduledata.enoptrbss
 	}
-	if end < uintptr(unsafe.Pointer(&ebss)) {
-		end = uintptr(unsafe.Pointer(&ebss))
+	if end < themoduledata.ebss {
+		end = themoduledata.ebss
 	}
 	size := round(end-start, _PageSize)
 	racecall(&__tsan_map_shadow, start, size, 0, 0)
diff --git a/src/runtime/rt0_dragonfly_386.s b/src/runtime/rt0_dragonfly_386.s
deleted file mode 100644
index 548ba79..0000000
--- a/src/runtime/rt0_dragonfly_386.s
+++ /dev/null
@@ -1,16 +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.
-
-#include "textflag.h"
-
-TEXT _rt0_386_dragonfly(SB),NOSPLIT,$8
-	MOVL	8(SP), AX
-	LEAL	12(SP), BX
-	MOVL	AX, 0(SP)
-	MOVL	BX, 4(SP)
-	CALL	main(SB)
-	INT	$3
-
-TEXT main(SB),NOSPLIT,$0
-	JMP	runtime·rt0_go(SB)
diff --git a/src/runtime/rt0_freebsd_arm.s b/src/runtime/rt0_freebsd_arm.s
index f312526..e1bb13d 100644
--- a/src/runtime/rt0_freebsd_arm.s
+++ b/src/runtime/rt0_freebsd_arm.s
@@ -4,10 +4,8 @@
 
 #include "textflag.h"
 
-// FreeBSD and Linux use the same linkage to main
-
 TEXT _rt0_arm_freebsd(SB),NOSPLIT,$-4
-	MOVW	(R13), R0	// argc
+	MOVW	(R13), R0		// argc
 	MOVW	$4(R13), R1		// argv
 	MOVM.DB.W [R0-R1], (R13)
 	B	runtime·rt0_go(SB)
@@ -15,4 +13,4 @@
 TEXT main(SB),NOSPLIT,$-4
 	MOVM.DB.W [R0-R1], (R13)
 	MOVW	$runtime·rt0_go(SB), R4
-	B		(R4)
+	B	(R4)
diff --git a/src/runtime/rt0_linux_amd64.s b/src/runtime/rt0_linux_amd64.s
index 985426a..9d9cb34 100644
--- a/src/runtime/rt0_linux_amd64.s
+++ b/src/runtime/rt0_linux_amd64.s
@@ -10,6 +10,13 @@
 	MOVQ	$main(SB), AX
 	JMP	AX
 
+// When linking with -shared, this symbol is called when the shared library
+// is loaded.
+TEXT _rt0_amd64_linux_lib(SB),NOSPLIT,$0
+	// TODO(spetrovic): Do something useful, like calling $main.  (Note that
+	// this has to be done in a separate thread, as main is expected to block.)
+	RET
+
 TEXT main(SB),NOSPLIT,$-8
 	MOVQ	$runtime·rt0_go(SB), AX
 	JMP	AX
diff --git a/src/runtime/rt0_linux_arm64.s b/src/runtime/rt0_linux_arm64.s
new file mode 100644
index 0000000..1eb0352
--- /dev/null
+++ b/src/runtime/rt0_linux_arm64.s
@@ -0,0 +1,19 @@
+// Copyright 2015 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.
+
+#include "textflag.h"
+
+TEXT _rt0_arm64_linux(SB),NOSPLIT,$-8
+	MOVD	0(RSP), R0	// argc
+	ADD	$8, RSP, R1	// argv
+	BL	main(SB)
+
+TEXT main(SB),NOSPLIT,$-8
+	MOVD	$runtime·rt0_go(SB), R2
+	BL	(R2)
+exit:
+	MOVD $0, R0
+	MOVD	$94, R8	// sys_exit
+	SVC
+	B	exit
diff --git a/src/runtime/rt0_netbsd_arm.s b/src/runtime/rt0_netbsd_arm.s
index bad66e0..2cb1182 100644
--- a/src/runtime/rt0_netbsd_arm.s
+++ b/src/runtime/rt0_netbsd_arm.s
@@ -4,10 +4,8 @@
 
 #include "textflag.h"
 
-// FreeBSD/NetBSD and Linux use the same linkage to main
-
 TEXT _rt0_arm_netbsd(SB),NOSPLIT,$-4
-	MOVW	(R13), R0	// argc
+	MOVW	(R13), R0		// argc
 	MOVW	$4(R13), R1		// argv
 	MOVM.DB.W [R0-R1], (R13)
 	B runtime·rt0_go(SB)
diff --git a/src/runtime/rt0_openbsd_arm.s b/src/runtime/rt0_openbsd_arm.s
new file mode 100644
index 0000000..6207e55
--- /dev/null
+++ b/src/runtime/rt0_openbsd_arm.s
@@ -0,0 +1,11 @@
+// Copyright 2013 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.
+
+#include "textflag.h"
+
+TEXT _rt0_arm_openbsd(SB),NOSPLIT,$-4
+	MOVW	(R13), R0		// argc
+	MOVW	$4(R13), R1		// argv
+	MOVM.DB.W [R0-R1], (R13)
+	B	runtime·rt0_go(SB)
diff --git a/src/runtime/rt0_windows_386.s b/src/runtime/rt0_windows_386.s
index 3c2deda..03f95d1 100644
--- a/src/runtime/rt0_windows_386.s
+++ b/src/runtime/rt0_windows_386.s
@@ -10,9 +10,9 @@
 	MOVL	AX, 4(SP)
 	MOVL	BX, 8(SP)
 	MOVL	$-1, 0(SP) // return PC for main
-	JMP	main(SB)
+	JMP	_main(SB)
 
-TEXT main(SB),NOSPLIT,$0
+TEXT _main(SB),NOSPLIT,$0
 	JMP	runtime·rt0_go(SB)
 
 
diff --git a/src/runtime/rune.go b/src/runtime/rune.go
index a9f6835..99c38e0 100644
--- a/src/runtime/rune.go
+++ b/src/runtime/rune.go
@@ -15,7 +15,7 @@
 
 /*
  * This code is copied, with slight editing due to type differences,
- * from a subset of ../lib9/utf/rune.c
+ * from a subset of ../lib9/utf/rune.c [which no longer exists]
  */
 
 package runtime
diff --git a/src/runtime/runtime-gdb.py b/src/runtime/runtime-gdb.py
index 9f2ba9f..c70aea7 100644
--- a/src/runtime/runtime-gdb.py
+++ b/src/runtime/runtime-gdb.py
@@ -60,7 +60,7 @@
 class StringTypePrinter:
 	"Pretty print Go strings."
 
-	pattern = re.compile(r'^struct string$')
+	pattern = re.compile(r'^struct string( \*)?$')
 
 	def __init__(self, val):
 		self.val = val
diff --git a/src/runtime/runtime-gdb_test.go b/src/runtime/runtime-gdb_test.go
index 7184120..7569d07 100644
--- a/src/runtime/runtime-gdb_test.go
+++ b/src/runtime/runtime-gdb_test.go
@@ -31,7 +31,10 @@
 	mapvar := make(map[string]string,5)
 	mapvar["abc"] = "def"
 	mapvar["ghi"] = "jkl"
-	fmt.Println("hi") // line 8
+	strvar := "abc"
+	ptrvar := &strvar
+	fmt.Println("hi") // line 10
+	_ = ptrvar
 }
 `
 
@@ -63,7 +66,7 @@
 
 	got, _ := exec.Command("gdb", "-nx", "-q", "--batch", "-iex",
 		fmt.Sprintf("add-auto-load-safe-path %s/src/runtime", runtime.GOROOT()),
-		"-ex", "br main.go:8",
+		"-ex", "br main.go:10",
 		"-ex", "run",
 		"-ex", "echo BEGIN info goroutines\n",
 		"-ex", "info goroutines",
@@ -71,6 +74,12 @@
 		"-ex", "echo BEGIN print mapvar\n",
 		"-ex", "print mapvar",
 		"-ex", "echo END\n",
+		"-ex", "echo BEGIN print strvar\n",
+		"-ex", "print strvar",
+		"-ex", "echo END\n",
+		"-ex", "echo BEGIN print ptrvar\n",
+		"-ex", "print ptrvar",
+		"-ex", "echo END\n",
 		filepath.Join(dir, "a.exe")).CombinedOutput()
 
 	firstLine := bytes.SplitN(got, []byte("\n"), 2)[0]
@@ -94,4 +103,13 @@
 	if bl := blocks["print mapvar"]; !printMapvarRe.MatchString(bl) {
 		t.Fatalf("print mapvar failed: %s", bl)
 	}
+
+	strVarRe := regexp.MustCompile(`\Q = "abc"\E$`)
+	if bl := blocks["print strvar"]; !strVarRe.MatchString(bl) {
+		t.Fatalf("print strvar failed: %s", bl)
+	}
+
+	if bl := blocks["print ptrvar"]; !strVarRe.MatchString(bl) {
+		t.Fatalf("print ptrvar failed: %s", bl)
+	}
 }
diff --git a/src/runtime/runtime.go b/src/runtime/runtime.go
index 0f66003..5f0ca02 100644
--- a/src/runtime/runtime.go
+++ b/src/runtime/runtime.go
@@ -43,15 +43,11 @@
 	return r
 }
 
-func makeStringSlice(n int) []string {
-	return make([]string, n)
-}
-
 var envs []string
 var argslice []string
 
 //go:linkname syscall_runtime_envs syscall.runtime_envs
-func syscall_runtime_envs() []string { return envs }
+func syscall_runtime_envs() []string { return append([]string{}, envs...) }
 
 //go:linkname os_runtime_args os.runtime_args
-func os_runtime_args() []string { return argslice }
+func os_runtime_args() []string { return append([]string{}, argslice...) }
diff --git a/src/runtime/runtime1.go b/src/runtime/runtime1.go
index f0d26c8..072a585 100644
--- a/src/runtime/runtime1.go
+++ b/src/runtime/runtime1.go
@@ -80,7 +80,7 @@
 
 	envs = make([]string, n)
 	for i := int32(0); i < n; i++ {
-		envs[i] = gostringnocopy(argv_index(argv, argc+1+i))
+		envs[i] = gostring(argv_index(argv, argc+1+i))
 	}
 }
 
@@ -316,6 +316,7 @@
 	schedtrace     int32
 	wbshadow       int32
 	gccheckmark    int32
+	sbrk           int32
 }
 
 var dbgvars = []dbgVar{
@@ -329,6 +330,7 @@
 	{"schedtrace", &debug.schedtrace},
 	{"wbshadow", &debug.wbshadow},
 	{"gccheckmark", &debug.gccheckmark},
+	{"sbrk", &debug.sbrk},
 }
 
 func parsedebugvars() {
@@ -422,20 +424,18 @@
 	return getg().m.mcache
 }
 
-var typelink, etypelink [0]byte
-
 //go:linkname reflect_typelinks reflect.typelinks
 //go:nosplit
 func reflect_typelinks() []*_type {
 	var ret []*_type
 	sp := (*slice)(unsafe.Pointer(&ret))
-	sp.array = (*byte)(unsafe.Pointer(&typelink))
-	sp.len = uint((uintptr(unsafe.Pointer(&etypelink)) - uintptr(unsafe.Pointer(&typelink))) / unsafe.Sizeof(ret[0]))
+	sp.array = (*byte)(unsafe.Pointer(themoduledata.typelink))
+	sp.len = uint((themoduledata.etypelink - themoduledata.typelink) / unsafe.Sizeof(ret[0]))
 	sp.cap = sp.len
 	return ret
 }
 
-// TODO: move back into mgc0.c when converted to Go
+// TODO: move back into mgc.go
 func readgogc() int32 {
 	p := gogetenv("GOGC")
 	if p == "" {
diff --git a/src/runtime/runtime2.go b/src/runtime/runtime2.go
index ea2d55d..0d3e542 100644
--- a/src/runtime/runtime2.go
+++ b/src/runtime/runtime2.go
@@ -14,7 +14,7 @@
 	//
 	// If you add to this list, add to the list
 	// of "okay during garbage collection" status
-	// in mgc0.c too.
+	// in mgcmark.go too.
 	_Gidle            = iota // 0
 	_Grunnable               // 1 runnable and on a run queue
 	_Grunning                // 2
@@ -117,6 +117,38 @@
 	return (*g)(unsafe.Pointer(gp))
 }
 
+// ps, ms, gs, and mcache are structures that must be manipulated at a level
+// lower than that of the normal Go language. For example the routine that
+// stops the world removes the p from the m structure informing the GC that
+// this P is stopped and then it moves the g to the global runnable queue.
+// If write barriers were allowed to happen at this point not only does
+// the GC think the thread is stopped but the underlying structures
+// like a p or m are not in a state that is not coherent enough to
+// support the write barrier actions.
+// This is particularly painful since a partially executed write barrier
+// may mark the object but be delinquent in informing the GC that the
+// object needs to be scanned.
+
+// setGNoWriteBarriers does *gdst = gval without a write barrier.
+func setGNoWriteBarrier(gdst **g, gval *g) {
+	*(*uintptr)(unsafe.Pointer(gdst)) = uintptr(unsafe.Pointer(gval))
+}
+
+// setMNoWriteBarriers does *mdst = mval without a write barrier.
+func setMNoWriteBarrier(mdst **m, mval *m) {
+	*(*uintptr)(unsafe.Pointer(mdst)) = uintptr(unsafe.Pointer(mval))
+}
+
+// setPNoWriteBarriers does *pdst = pval without a write barrier.
+func setPNoWriteBarrier(pdst **p, pval *p) {
+	*(*uintptr)(unsafe.Pointer(pdst)) = uintptr(unsafe.Pointer(pval))
+}
+
+// setMcacheNoWriteBarriers does *mcachedst = mcacheval without a write barrier.
+func setMcacheNoWriteBarrier(mcachedst **mcache, mcacheval *mcache) {
+	*(*uintptr)(unsafe.Pointer(mcachedst)) = uintptr(unsafe.Pointer(mcacheval))
+}
+
 type gobuf struct {
 	// The offsets of sp, pc, and g are known to (hard-coded in) libmach.
 	sp   uintptr
@@ -129,7 +161,7 @@
 }
 
 // Known to compiler.
-// Changes here must also be made in src/cmd/gc/select.c's selecttype.
+// Changes here must also be made in src/cmd/internal/gc/select.go's selecttype.
 type sudog struct {
 	g           *g
 	selectdone  *uint32
@@ -233,13 +265,13 @@
 	morebuf gobuf // gobuf arg to morestack
 
 	// Fields not known to debuggers.
-	procid        uint64         // for debuggers, but offset not hard-coded
-	gsignal       *g             // signal-handling g
-	tls           [4]uintptr     // thread-local storage (for x86 extern register)
-	mstartfn      unsafe.Pointer // todo go func()
-	curg          *g             // current running goroutine
-	caughtsig     *g             // goroutine running during fatal signal
-	p             *p             // attached p for executing go code (nil if not executing go code)
+	procid        uint64     // for debuggers, but offset not hard-coded
+	gsignal       *g         // signal-handling g
+	tls           [4]uintptr // thread-local storage (for x86 extern register)
+	mstartfn      uintptr    // TODO: type as func(); note: this is a non-heap allocated func()
+	curg          *g         // current running goroutine
+	caughtsig     *g         // goroutine running during fatal signal
+	p             *p         // attached p for executing go code (nil if not executing go code)
 	nextp         *p
 	id            int32
 	mallocing     int32
@@ -269,7 +301,7 @@
 	freghi        [16]uint32  // d[i] msb and f[i+16]
 	fflag         uint32      // floating point compare flags
 	locked        uint32      // tracking for lockosthread
-	nextwaitm     *m          // next m waiting for lock
+	nextwaitm     uintptr     // next m waiting for lock
 	waitsema      uintptr     // semaphore for parking on locks
 	waitsemacount uint32
 	waitsemalock  uint32
@@ -280,6 +312,7 @@
 	waitunlockf   unsafe.Pointer // todo go func(*g, unsafe.pointer) bool
 	waitlock      unsafe.Pointer
 	waittraceev   byte
+	waittraceskip int
 	syscalltick   uint32
 	//#ifdef GOOS_windows
 	thread uintptr // thread handle
@@ -314,7 +347,9 @@
 	syscalltick uint32 // incremented on every system call
 	m           *m     // back-link to associated m (nil if idle)
 	mcache      *mcache
-	deferpool   [5]*_defer // pool of available defer structs of different sizes (see panic.c)
+
+	deferpool    [5][]*_defer // pool of available defer structs of different sizes (see panic.go)
+	deferpoolbuf [5][32]*_defer
 
 	// Cache of goroutine ids, amortizes accesses to runtime·sched.goidgen.
 	goidcache    uint64
@@ -329,8 +364,13 @@
 	gfree    *g
 	gfreecnt int32
 
+	sudogcache []*sudog
+	sudogbuf   [128]*sudog
+
 	tracebuf *traceBuf
 
+	palloc persistentAlloc // per-P to avoid mutex
+
 	pad [64]byte
 }
 
@@ -365,6 +405,14 @@
 	gfree  *g
 	ngfree int32
 
+	// Central cache of sudog structs.
+	sudoglock  mutex
+	sudogcache *sudog
+
+	// Central pool of available defer structs of different sizes.
+	deferlock mutex
+	deferpool [5]*_defer
+
 	gcwaiting  uint32 // gc is waiting to run
 	stopwait   int32
 	stopnote   note
@@ -406,7 +454,7 @@
 
 // Layout of in-memory per-function information prepared by linker
 // See http://golang.org/s/go12symtab.
-// Keep in sync with linker and with ../../libmach/sym.c
+// Keep in sync with linker
 // and with package debug/gosym and with symtab.go in package runtime.
 type _func struct {
 	entry   uintptr // start pc
@@ -557,11 +605,9 @@
 	allm        *m
 	allp        [_MaxGomaxprocs + 1]*p
 	gomaxprocs  int32
-	needextram  uint32
 	panicking   uint32
 	goos        *int8
 	ncpu        int32
-	iscgo       bool
 	signote     note
 	forcegc     forcegcstate
 	sched       schedt
diff --git a/src/runtime/runtime_test.go b/src/runtime/runtime_test.go
index 0988420..782b936 100644
--- a/src/runtime/runtime_test.go
+++ b/src/runtime/runtime_test.go
@@ -177,12 +177,6 @@
 }
 
 func TestSetPanicOnFault(t *testing.T) {
-	// This currently results in a fault in the signal trampoline on
-	// dragonfly/386 - see issue 7421.
-	if GOOS == "dragonfly" && GOARCH == "386" {
-		t.Skip("skipping test on dragonfly/386")
-	}
-
 	old := debug.SetPanicOnFault(true)
 	defer debug.SetPanicOnFault(old)
 
@@ -292,3 +286,29 @@
 		t.Errorf("sizeof(%#v)==%d, want 0", T5{}, unsafe.Sizeof(T5{}))
 	}
 }
+
+func TestBadOpen(t *testing.T) {
+	if GOOS == "windows" || GOOS == "nacl" {
+		t.Skip("skipping OS that doesn't have open/read/write/close")
+	}
+	// make sure we get the correct error code if open fails.  Same for
+	// read/write/close on the resulting -1 fd.  See issue 10052.
+	nonfile := []byte("/notreallyafile")
+	fd := Open(&nonfile[0], 0, 0)
+	if fd != -1 {
+		t.Errorf("open(\"%s\")=%d, want -1", string(nonfile), fd)
+	}
+	var buf [32]byte
+	r := Read(-1, unsafe.Pointer(&buf[0]), int32(len(buf)))
+	if r != -1 {
+		t.Errorf("read()=%d, want -1", r)
+	}
+	w := Write(^uintptr(0), unsafe.Pointer(&buf[0]), int32(len(buf)))
+	if w != -1 {
+		t.Errorf("write()=%d, want -1", w)
+	}
+	c := Close(-1)
+	if c != -1 {
+		t.Errorf("close()=%d, want -1", c)
+	}
+}
diff --git a/src/runtime/select.go b/src/runtime/select.go
index 34fda16..98ac5a3 100644
--- a/src/runtime/select.go
+++ b/src/runtime/select.go
@@ -10,30 +10,59 @@
 
 const (
 	debugSelect = false
+
+	// scase.kind
+	caseRecv = iota
+	caseSend
+	caseDefault
 )
 
+// Select statement header.
+// Known to compiler.
+// Changes here must also be made in src/cmd/internal/gc/select.go's selecttype.
+type hselect struct {
+	tcase     uint16   // total count of scase[]
+	ncase     uint16   // currently filled scase[]
+	pollorder *uint16  // case poll order
+	lockorder **hchan  // channel lock order
+	scase     [1]scase // one per case (in order of appearance)
+}
+
+// Select case descriptor.
+// Known to compiler.
+// Changes here must also be made in src/cmd/internal/gc/select.go's selecttype.
+type scase struct {
+	elem        unsafe.Pointer // data element
+	c           *hchan         // chan
+	pc          uintptr        // return pc
+	kind        uint16
+	so          uint16 // vararg of selected bool
+	receivedp   *bool  // pointer to received bool (recv2)
+	releasetime int64
+}
+
 var (
 	chansendpc = funcPC(chansend)
 	chanrecvpc = funcPC(chanrecv)
 )
 
 func selectsize(size uintptr) uintptr {
-	selsize := unsafe.Sizeof(_select{}) +
-		(size-1)*unsafe.Sizeof(_select{}.scase[0]) +
-		size*unsafe.Sizeof(*_select{}.lockorder) +
-		size*unsafe.Sizeof(*_select{}.pollorder)
+	selsize := unsafe.Sizeof(hselect{}) +
+		(size-1)*unsafe.Sizeof(hselect{}.scase[0]) +
+		size*unsafe.Sizeof(*hselect{}.lockorder) +
+		size*unsafe.Sizeof(*hselect{}.pollorder)
 	return round(selsize, _Int64Align)
 }
 
-func newselect(sel *_select, selsize int64, size int32) {
+func newselect(sel *hselect, selsize int64, size int32) {
 	if selsize != int64(selectsize(uintptr(size))) {
 		print("runtime: bad select size ", selsize, ", want ", selectsize(uintptr(size)), "\n")
 		throw("bad select size")
 	}
 	sel.tcase = uint16(size)
 	sel.ncase = 0
-	sel.lockorder = (**hchan)(add(unsafe.Pointer(&sel.scase), uintptr(size)*unsafe.Sizeof(_select{}.scase[0])))
-	sel.pollorder = (*uint16)(add(unsafe.Pointer(sel.lockorder), uintptr(size)*unsafe.Sizeof(*_select{}.lockorder)))
+	sel.lockorder = (**hchan)(add(unsafe.Pointer(&sel.scase), uintptr(size)*unsafe.Sizeof(hselect{}.scase[0])))
+	sel.pollorder = (*uint16)(add(unsafe.Pointer(sel.lockorder), uintptr(size)*unsafe.Sizeof(*hselect{}.lockorder)))
 
 	if debugSelect {
 		print("newselect s=", sel, " size=", size, "\n")
@@ -41,7 +70,7 @@
 }
 
 //go:nosplit
-func selectsend(sel *_select, c *hchan, elem unsafe.Pointer) (selected bool) {
+func selectsend(sel *hselect, c *hchan, elem unsafe.Pointer) (selected bool) {
 	// nil cases do not compete
 	if c != nil {
 		selectsendImpl(sel, c, getcallerpc(unsafe.Pointer(&sel)), elem, uintptr(unsafe.Pointer(&selected))-uintptr(unsafe.Pointer(&sel)))
@@ -50,7 +79,7 @@
 }
 
 // cut in half to give stack a chance to split
-func selectsendImpl(sel *_select, c *hchan, pc uintptr, elem unsafe.Pointer, so uintptr) {
+func selectsendImpl(sel *hselect, c *hchan, pc uintptr, elem unsafe.Pointer, so uintptr) {
 	i := sel.ncase
 	if i >= sel.tcase {
 		throw("selectsend: too many cases")
@@ -59,18 +88,18 @@
 	cas := (*scase)(add(unsafe.Pointer(&sel.scase), uintptr(i)*unsafe.Sizeof(sel.scase[0])))
 
 	cas.pc = pc
-	cas._chan = c
+	cas.c = c
 	cas.so = uint16(so)
-	cas.kind = _CaseSend
+	cas.kind = caseSend
 	cas.elem = elem
 
 	if debugSelect {
-		print("selectsend s=", sel, " pc=", hex(cas.pc), " chan=", cas._chan, " so=", cas.so, "\n")
+		print("selectsend s=", sel, " pc=", hex(cas.pc), " chan=", cas.c, " so=", cas.so, "\n")
 	}
 }
 
 //go:nosplit
-func selectrecv(sel *_select, c *hchan, elem unsafe.Pointer) (selected bool) {
+func selectrecv(sel *hselect, c *hchan, elem unsafe.Pointer) (selected bool) {
 	// nil cases do not compete
 	if c != nil {
 		selectrecvImpl(sel, c, getcallerpc(unsafe.Pointer(&sel)), elem, nil, uintptr(unsafe.Pointer(&selected))-uintptr(unsafe.Pointer(&sel)))
@@ -79,7 +108,7 @@
 }
 
 //go:nosplit
-func selectrecv2(sel *_select, c *hchan, elem unsafe.Pointer, received *bool) (selected bool) {
+func selectrecv2(sel *hselect, c *hchan, elem unsafe.Pointer, received *bool) (selected bool) {
 	// nil cases do not compete
 	if c != nil {
 		selectrecvImpl(sel, c, getcallerpc(unsafe.Pointer(&sel)), elem, received, uintptr(unsafe.Pointer(&selected))-uintptr(unsafe.Pointer(&sel)))
@@ -87,7 +116,7 @@
 	return
 }
 
-func selectrecvImpl(sel *_select, c *hchan, pc uintptr, elem unsafe.Pointer, received *bool, so uintptr) {
+func selectrecvImpl(sel *hselect, c *hchan, pc uintptr, elem unsafe.Pointer, received *bool, so uintptr) {
 	i := sel.ncase
 	if i >= sel.tcase {
 		throw("selectrecv: too many cases")
@@ -95,24 +124,24 @@
 	sel.ncase = i + 1
 	cas := (*scase)(add(unsafe.Pointer(&sel.scase), uintptr(i)*unsafe.Sizeof(sel.scase[0])))
 	cas.pc = pc
-	cas._chan = c
+	cas.c = c
 	cas.so = uint16(so)
-	cas.kind = _CaseRecv
+	cas.kind = caseRecv
 	cas.elem = elem
 	cas.receivedp = received
 
 	if debugSelect {
-		print("selectrecv s=", sel, " pc=", hex(cas.pc), " chan=", cas._chan, " so=", cas.so, "\n")
+		print("selectrecv s=", sel, " pc=", hex(cas.pc), " chan=", cas.c, " so=", cas.so, "\n")
 	}
 }
 
 //go:nosplit
-func selectdefault(sel *_select) (selected bool) {
+func selectdefault(sel *hselect) (selected bool) {
 	selectdefaultImpl(sel, getcallerpc(unsafe.Pointer(&sel)), uintptr(unsafe.Pointer(&selected))-uintptr(unsafe.Pointer(&sel)))
 	return
 }
 
-func selectdefaultImpl(sel *_select, callerpc uintptr, so uintptr) {
+func selectdefaultImpl(sel *hselect, callerpc uintptr, so uintptr) {
 	i := sel.ncase
 	if i >= sel.tcase {
 		throw("selectdefault: too many cases")
@@ -120,16 +149,16 @@
 	sel.ncase = i + 1
 	cas := (*scase)(add(unsafe.Pointer(&sel.scase), uintptr(i)*unsafe.Sizeof(sel.scase[0])))
 	cas.pc = callerpc
-	cas._chan = nil
+	cas.c = nil
 	cas.so = uint16(so)
-	cas.kind = _CaseDefault
+	cas.kind = caseDefault
 
 	if debugSelect {
 		print("selectdefault s=", sel, " pc=", hex(cas.pc), " so=", cas.so, "\n")
 	}
 }
 
-func sellock(sel *_select) {
+func sellock(sel *hselect) {
 	lockslice := sliceStruct{unsafe.Pointer(sel.lockorder), int(sel.ncase), int(sel.ncase)}
 	lockorder := *(*[]*hchan)(unsafe.Pointer(&lockslice))
 	var c *hchan
@@ -141,7 +170,7 @@
 	}
 }
 
-func selunlock(sel *_select) {
+func selunlock(sel *hselect) {
 	// We must be very careful here to not touch sel after we have unlocked
 	// the last lock, because sel can be freed right after the last unlock.
 	// Consider the following situation.
@@ -168,18 +197,18 @@
 }
 
 func selparkcommit(gp *g, sel unsafe.Pointer) bool {
-	selunlock((*_select)(sel))
+	selunlock((*hselect)(sel))
 	return true
 }
 
 func block() {
-	gopark(nil, nil, "select (no cases)", traceEvGoStop) // forever
+	gopark(nil, nil, "select (no cases)", traceEvGoStop, 1) // forever
 }
 
 // overwrites return pc on stack to signal which case of the select
 // to run, so cannot appear at the top of a split stack.
 //go:nosplit
-func selectgo(sel *_select) {
+func selectgo(sel *hselect) {
 	pc, offset := selectgoImpl(sel)
 	*(*bool)(add(unsafe.Pointer(&sel), uintptr(offset))) = true
 	setcallerpc(unsafe.Pointer(&sel), pc)
@@ -187,7 +216,7 @@
 
 // selectgoImpl returns scase.pc and scase.so for the select
 // case which fired.
-func selectgoImpl(sel *_select) (uintptr, uint16) {
+func selectgoImpl(sel *hselect) (uintptr, uint16) {
 	if debugSelect {
 		print("select: sel=", sel, "\n")
 	}
@@ -230,7 +259,7 @@
 	lockorder := *(*[]*hchan)(unsafe.Pointer(&lockslice))
 	for i := 0; i < int(sel.ncase); i++ {
 		j := i
-		c := scases[j]._chan
+		c := scases[j].c
 		for j > 0 && lockorder[(j-1)/2].sortkey() < c.sortkey() {
 			k := (j - 1) / 2
 			lockorder[j] = lockorder[k]
@@ -279,6 +308,7 @@
 		k      *scase
 		sglist *sudog
 		sgnext *sudog
+		futile byte
 	)
 
 loop:
@@ -287,10 +317,10 @@
 	var cas *scase
 	for i := 0; i < int(sel.ncase); i++ {
 		cas = &scases[pollorder[i]]
-		c = cas._chan
+		c = cas.c
 
 		switch cas.kind {
-		case _CaseRecv:
+		case caseRecv:
 			if c.dataqsiz > 0 {
 				if c.qcount > 0 {
 					goto asyncrecv
@@ -305,7 +335,7 @@
 				goto rclose
 			}
 
-		case _CaseSend:
+		case caseSend:
 			if raceenabled {
 				racereadpc(unsafe.Pointer(c), cas.pc, chansendpc)
 			}
@@ -323,7 +353,7 @@
 				}
 			}
 
-		case _CaseDefault:
+		case caseDefault:
 			dfl = cas
 		}
 	}
@@ -339,10 +369,10 @@
 	done = 0
 	for i := 0; i < int(sel.ncase); i++ {
 		cas = &scases[pollorder[i]]
-		c = cas._chan
+		c = cas.c
 		sg := acquireSudog()
 		sg.g = gp
-		// Note: selectdone is adjusted for stack copies in stack.c:adjustsudogs
+		// Note: selectdone is adjusted for stack copies in stack1.go:adjustsudogs
 		sg.selectdone = (*uint32)(noescape(unsafe.Pointer(&done)))
 		sg.elem = cas.elem
 		sg.releasetime = 0
@@ -353,17 +383,17 @@
 		gp.waiting = sg
 
 		switch cas.kind {
-		case _CaseRecv:
+		case caseRecv:
 			c.recvq.enqueue(sg)
 
-		case _CaseSend:
+		case caseSend:
 			c.sendq.enqueue(sg)
 		}
 	}
 
 	// wait for someone to wake us up
 	gp.param = nil
-	gopark(selparkcommit, unsafe.Pointer(sel), "select", traceEvGoBlockSelect)
+	gopark(selparkcommit, unsafe.Pointer(sel), "select", traceEvGoBlockSelect|futile, 2)
 
 	// someone woke us up
 	sellock(sel)
@@ -392,8 +422,8 @@
 			// sg has already been dequeued by the G that woke us up.
 			cas = k
 		} else {
-			c = k._chan
-			if k.kind == _CaseSend {
+			c = k.c
+			if k.kind == caseSend {
 				c.sendq.dequeueSudoG(sglist)
 			} else {
 				c.recvq.dequeueSudoG(sglist)
@@ -406,10 +436,11 @@
 	}
 
 	if cas == nil {
+		futile = traceFutileWakeup
 		goto loop
 	}
 
-	c = cas._chan
+	c = cas.c
 
 	if c.dataqsiz > 0 {
 		throw("selectgo: shouldn't happen")
@@ -419,16 +450,16 @@
 		print("wait-return: sel=", sel, " c=", c, " cas=", cas, " kind=", cas.kind, "\n")
 	}
 
-	if cas.kind == _CaseRecv {
+	if cas.kind == caseRecv {
 		if cas.receivedp != nil {
 			*cas.receivedp = true
 		}
 	}
 
 	if raceenabled {
-		if cas.kind == _CaseRecv && cas.elem != nil {
+		if cas.kind == caseRecv && cas.elem != nil {
 			raceWriteObjectPC(c.elemtype, cas.elem, cas.pc, chanrecvpc)
-		} else if cas.kind == _CaseSend {
+		} else if cas.kind == caseSend {
 			raceReadObjectPC(c.elemtype, cas.elem, cas.pc, chansendpc)
 		}
 	}
@@ -464,7 +495,7 @@
 		if sg.releasetime != 0 {
 			sg.releasetime = cputicks()
 		}
-		goready(gp)
+		goready(gp, 3)
 	} else {
 		selunlock(sel)
 	}
@@ -490,7 +521,7 @@
 		if sg.releasetime != 0 {
 			sg.releasetime = cputicks()
 		}
-		goready(gp)
+		goready(gp, 3)
 	} else {
 		selunlock(sel)
 	}
@@ -520,7 +551,7 @@
 	if sg.releasetime != 0 {
 		sg.releasetime = cputicks()
 	}
-	goready(gp)
+	goready(gp, 3)
 	goto retc
 
 rclose:
@@ -556,7 +587,7 @@
 	if sg.releasetime != 0 {
 		sg.releasetime = cputicks()
 	}
-	goready(gp)
+	goready(gp, 3)
 
 retc:
 	if cas.releasetime > 0 {
@@ -599,7 +630,7 @@
 func reflect_rselect(cases []runtimeSelect) (chosen int, recvOK bool) {
 	// flagNoScan is safe here, because all objects are also referenced from cases.
 	size := selectsize(uintptr(len(cases)))
-	sel := (*_select)(mallocgc(size, nil, flagNoScan))
+	sel := (*hselect)(mallocgc(size, nil, flagNoScan))
 	newselect(sel, int64(size), int32(len(cases)))
 	r := new(bool)
 	for i := range cases {
diff --git a/src/runtime/sema.go b/src/runtime/sema.go
index 34852ea..8ae51b4 100644
--- a/src/runtime/sema.go
+++ b/src/runtime/sema.go
@@ -97,7 +97,7 @@
 		// Any semrelease after the cansemacquire knows we're waiting
 		// (we set nwait above), so go to sleep.
 		root.queue(addr, s)
-		goparkunlock(&root.lock, "semacquire", traceEvGoBlockSync)
+		goparkunlock(&root.lock, "semacquire", traceEvGoBlockSync, 4)
 		if cansemacquire(addr) {
 			break
 		}
@@ -140,7 +140,7 @@
 		if s.releasetime != 0 {
 			s.releasetime = cputicks()
 		}
-		goready(s.g)
+		goready(s.g, 4)
 	}
 }
 
@@ -214,7 +214,7 @@
 		unlock(&s.lock)
 		if wake != nil {
 			wake.next = nil
-			goready(wake.g)
+			goready(wake.g, 4)
 		}
 	} else {
 		// Enqueue itself.
@@ -234,7 +234,7 @@
 			s.tail.next = w
 		}
 		s.tail = w
-		goparkunlock(&s.lock, "semacquire", traceEvGoBlockCond)
+		goparkunlock(&s.lock, "semacquire", traceEvGoBlockCond, 3)
 		if t0 != 0 {
 			blockevent(int64(w.releasetime)-t0, 2)
 		}
@@ -257,7 +257,7 @@
 			wake.releasetime = cputicks()
 		}
 		wake.next = nil
-		goready(wake.g)
+		goready(wake.g, 4)
 		n--
 	}
 	if n > 0 {
@@ -273,7 +273,7 @@
 			s.tail.next = w
 		}
 		s.tail = w
-		goparkunlock(&s.lock, "semarelease", traceEvGoBlockCond)
+		goparkunlock(&s.lock, "semarelease", traceEvGoBlockCond, 3)
 		releaseSudog(w)
 	} else {
 		unlock(&s.lock)
diff --git a/src/runtime/signal_386.go b/src/runtime/signal_386.go
index 0ca593d..b632995 100644
--- a/src/runtime/signal_386.go
+++ b/src/runtime/signal_386.go
@@ -24,6 +24,8 @@
 	print("gs     ", hex(c.gs()), "\n")
 }
 
+// May run during STW, so write barriers are not allowed.
+//go:nowritebarrier
 func sighandler(sig uint32, info *siginfo, ctxt unsafe.Pointer, gp *g) {
 	_g_ := getg()
 	c := &sigctxt{info, ctxt}
@@ -98,7 +100,7 @@
 	}
 
 	_g_.m.throwing = 1
-	_g_.m.caughtsig = gp
+	setGNoWriteBarrier(&_g_.m.caughtsig, gp)
 	startpanic()
 
 	if sig < uint32(len(sigtable)) {
diff --git a/src/runtime/signal_amd64x.go b/src/runtime/signal_amd64x.go
index cd87d76..5dc9d80 100644
--- a/src/runtime/signal_amd64x.go
+++ b/src/runtime/signal_amd64x.go
@@ -37,6 +37,8 @@
 
 var crashing int32
 
+// May run during STW, so write barriers are not allowed.
+//go:nowritebarrier
 func sighandler(sig uint32, info *siginfo, ctxt unsafe.Pointer, gp *g) {
 	_g_ := getg()
 	c := &sigctxt{info, ctxt}
@@ -134,7 +136,7 @@
 	}
 
 	_g_.m.throwing = 1
-	_g_.m.caughtsig = gp
+	setGNoWriteBarrier(&_g_.m.caughtsig, gp)
 
 	if crashing == 0 {
 		startpanic()
diff --git a/src/runtime/signal_arm.go b/src/runtime/signal_arm.go
index c07b45e..7d417fa 100644
--- a/src/runtime/signal_arm.go
+++ b/src/runtime/signal_arm.go
@@ -32,6 +32,8 @@
 	print("fault   ", hex(c.fault()), "\n")
 }
 
+// May run during STW, so write barriers are not allowed.
+//go:nowritebarrier
 func sighandler(sig uint32, info *siginfo, ctxt unsafe.Pointer, gp *g) {
 	_g_ := getg()
 	c := &sigctxt{info, ctxt}
@@ -93,7 +95,7 @@
 	}
 
 	_g_.m.throwing = 1
-	_g_.m.caughtsig = gp
+	setGNoWriteBarrier(&_g_.m.caughtsig, gp)
 	startpanic()
 
 	if sig < uint32(len(sigtable)) {
diff --git a/src/runtime/signal_arm64.go b/src/runtime/signal_arm64.go
new file mode 100644
index 0000000..efb8402
--- /dev/null
+++ b/src/runtime/signal_arm64.go
@@ -0,0 +1,141 @@
+// 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.
+
+// +build linux
+
+package runtime
+
+import "unsafe"
+
+func dumpregs(c *sigctxt) {
+	print("r0      ", hex(c.r0()), "\n")
+	print("r1      ", hex(c.r1()), "\n")
+	print("r2      ", hex(c.r2()), "\n")
+	print("r3      ", hex(c.r3()), "\n")
+	print("r4      ", hex(c.r4()), "\n")
+	print("r5      ", hex(c.r5()), "\n")
+	print("r6      ", hex(c.r6()), "\n")
+	print("r7      ", hex(c.r7()), "\n")
+	print("r8      ", hex(c.r8()), "\n")
+	print("r9      ", hex(c.r9()), "\n")
+	print("r10     ", hex(c.r10()), "\n")
+	print("r11     ", hex(c.r11()), "\n")
+	print("r12     ", hex(c.r12()), "\n")
+	print("r13     ", hex(c.r13()), "\n")
+	print("r14     ", hex(c.r14()), "\n")
+	print("r15     ", hex(c.r15()), "\n")
+	print("r16     ", hex(c.r16()), "\n")
+	print("r17     ", hex(c.r17()), "\n")
+	print("r18     ", hex(c.r18()), "\n")
+	print("r19     ", hex(c.r19()), "\n")
+	print("r20     ", hex(c.r20()), "\n")
+	print("r21     ", hex(c.r21()), "\n")
+	print("r22     ", hex(c.r22()), "\n")
+	print("r23     ", hex(c.r23()), "\n")
+	print("r24     ", hex(c.r24()), "\n")
+	print("r25     ", hex(c.r25()), "\n")
+	print("r26     ", hex(c.r26()), "\n")
+	print("r27     ", hex(c.r27()), "\n")
+	print("r28     ", hex(c.r28()), "\n")
+	print("r29     ", hex(c.r29()), "\n")
+	print("lr      ", hex(c.lr()), "\n")
+	print("sp      ", hex(c.sp()), "\n")
+	print("pc      ", hex(c.pc()), "\n")
+	print("fault   ", hex(c.fault()), "\n")
+}
+
+// May run during STW, so write barriers are not allowed.
+//go:nowritebarrier
+func sighandler(sig uint32, info *siginfo, ctxt unsafe.Pointer, gp *g) {
+	_g_ := getg()
+	c := &sigctxt{info, ctxt}
+
+	if sig == _SIGPROF {
+		sigprof(uintptr(c.pc()), uintptr(c.sp()), uintptr(c.lr()), gp, _g_.m)
+		return
+	}
+
+	flags := int32(_SigThrow)
+	if sig < uint32(len(sigtable)) {
+		flags = sigtable[sig].flags
+	}
+	if c.sigcode() != _SI_USER && flags&_SigPanic != 0 {
+		// Make it look like a call to the signal func.
+		// Have to pass arguments out of band since
+		// augmenting the stack frame would break
+		// the unwinding code.
+		gp.sig = sig
+		gp.sigcode0 = uintptr(c.sigcode())
+		gp.sigcode1 = uintptr(c.fault())
+		gp.sigpc = uintptr(c.pc())
+
+		// We arrange lr, and pc to pretend the panicking
+		// function calls sigpanic directly.
+		// Always save LR to stack so that panics in leaf
+		// functions are correctly handled. This smashes
+		// the stack frame but we're not going back there
+		// anyway.
+		sp := c.sp() - spAlign // needs only sizeof uint64, but must align the stack
+		c.set_sp(sp)
+		*(*uint64)(unsafe.Pointer(uintptr(sp))) = c.lr()
+
+		// Don't bother saving PC if it's zero, which is
+		// probably a call to a nil func: the old link register
+		// is more useful in the stack trace.
+		if gp.sigpc != 0 {
+			c.set_lr(uint64(gp.sigpc))
+		}
+
+		// In case we are panicking from external C code
+		c.set_r28(uint64(uintptr(unsafe.Pointer(gp))))
+		c.set_pc(uint64(funcPC(sigpanic)))
+		return
+	}
+
+	if c.sigcode() == _SI_USER || flags&_SigNotify != 0 {
+		if sigsend(sig) {
+			return
+		}
+	}
+
+	if flags&_SigKill != 0 {
+		exit(2)
+	}
+
+	if flags&_SigThrow == 0 {
+		return
+	}
+
+	_g_.m.throwing = 1
+	setGNoWriteBarrier(&_g_.m.caughtsig, gp)
+	startpanic()
+
+	if sig < uint32(len(sigtable)) {
+		print(sigtable[sig].name, "\n")
+	} else {
+		print("Signal ", sig, "\n")
+	}
+
+	print("PC=", hex(c.pc()), "\n")
+	if _g_.m.lockedg != nil && _g_.m.ncgo > 0 && gp == _g_.m.g0 {
+		print("signal arrived during cgo execution\n")
+		gp = _g_.m.lockedg
+	}
+	print("\n")
+
+	var docrash bool
+	if gotraceback(&docrash) > 0 {
+		goroutineheader(gp)
+		tracebacktrap(uintptr(c.pc()), uintptr(c.sp()), uintptr(c.lr()), gp)
+		tracebackothers(gp)
+		print("\n")
+		dumpregs(c)
+	}
+
+	if docrash {
+		crash()
+	}
+
+	exit(2)
+}
diff --git a/src/runtime/signal_darwin_386.go b/src/runtime/signal_darwin_386.go
index ccf30ef..302b3aa 100644
--- a/src/runtime/signal_darwin_386.go
+++ b/src/runtime/signal_darwin_386.go
@@ -26,9 +26,9 @@
 func (c *sigctxt) fs() uint32      { return c.regs().fs }
 func (c *sigctxt) gs() uint32      { return c.regs().gs }
 func (c *sigctxt) sigcode() uint32 { return uint32(c.info.si_code) }
-func (c *sigctxt) sigaddr() uint32 { return uint32(uintptr(unsafe.Pointer(c.info.si_addr))) }
+func (c *sigctxt) sigaddr() uint32 { return c.info.si_addr }
 
 func (c *sigctxt) set_eip(x uint32)     { c.regs().eip = x }
 func (c *sigctxt) set_esp(x uint32)     { c.regs().esp = x }
 func (c *sigctxt) set_sigcode(x uint32) { c.info.si_code = int32(x) }
-func (c *sigctxt) set_sigaddr(x uint32) { c.info.si_addr = (*byte)(unsafe.Pointer(uintptr(x))) }
+func (c *sigctxt) set_sigaddr(x uint32) { c.info.si_addr = x }
diff --git a/src/runtime/signal_darwin_amd64.go b/src/runtime/signal_darwin_amd64.go
index 409bc6d..dbf0448 100644
--- a/src/runtime/signal_darwin_amd64.go
+++ b/src/runtime/signal_darwin_amd64.go
@@ -34,9 +34,9 @@
 func (c *sigctxt) fs() uint64      { return c.regs().fs }
 func (c *sigctxt) gs() uint64      { return c.regs().gs }
 func (c *sigctxt) sigcode() uint64 { return uint64(c.info.si_code) }
-func (c *sigctxt) sigaddr() uint64 { return uint64(uintptr(unsafe.Pointer(c.info.si_addr))) }
+func (c *sigctxt) sigaddr() uint64 { return c.info.si_addr }
 
 func (c *sigctxt) set_rip(x uint64)     { c.regs().rip = x }
 func (c *sigctxt) set_rsp(x uint64)     { c.regs().rsp = x }
 func (c *sigctxt) set_sigcode(x uint64) { c.info.si_code = int32(x) }
-func (c *sigctxt) set_sigaddr(x uint64) { c.info.si_addr = (*byte)(unsafe.Pointer(uintptr(x))) }
+func (c *sigctxt) set_sigaddr(x uint64) { c.info.si_addr = x }
diff --git a/src/runtime/signal_darwin_arm.go b/src/runtime/signal_darwin_arm.go
index 1441a65..0f10971 100644
--- a/src/runtime/signal_darwin_arm.go
+++ b/src/runtime/signal_darwin_arm.go
@@ -29,7 +29,7 @@
 func (c *sigctxt) lr() uint32      { return c.regs().lr }
 func (c *sigctxt) pc() uint32      { return c.regs().pc }
 func (c *sigctxt) cpsr() uint32    { return c.regs().cpsr }
-func (c *sigctxt) fault() uint32   { return uint32(uintptr(unsafe.Pointer(c.info.si_addr))) }
+func (c *sigctxt) fault() uint32   { return c.info.si_addr }
 func (c *sigctxt) sigcode() uint32 { return uint32(c.info.si_code) }
 func (c *sigctxt) trap() uint32    { return 0 }
 func (c *sigctxt) error() uint32   { return 0 }
@@ -41,4 +41,4 @@
 func (c *sigctxt) set_r10(x uint32) { c.regs().r[10] = x }
 
 func (c *sigctxt) set_sigcode(x uint32) { c.info.si_code = int32(x) }
-func (c *sigctxt) set_sigaddr(x uint32) { c.info.si_addr = (*byte)(unsafe.Pointer(uintptr(x))) }
+func (c *sigctxt) set_sigaddr(x uint32) { c.info.si_addr = x }
diff --git a/src/runtime/signal_dragonfly_386.go b/src/runtime/signal_dragonfly_386.go
deleted file mode 100644
index a0fec13..0000000
--- a/src/runtime/signal_dragonfly_386.go
+++ /dev/null
@@ -1,34 +0,0 @@
-// Copyright 2013 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 runtime
-
-import "unsafe"
-
-type sigctxt struct {
-	info *siginfo
-	ctxt unsafe.Pointer
-}
-
-func (c *sigctxt) regs() *mcontext { return &(*ucontext)(c.ctxt).uc_mcontext }
-func (c *sigctxt) eax() uint32     { return c.regs().mc_eax }
-func (c *sigctxt) ebx() uint32     { return c.regs().mc_ebx }
-func (c *sigctxt) ecx() uint32     { return c.regs().mc_ecx }
-func (c *sigctxt) edx() uint32     { return c.regs().mc_edx }
-func (c *sigctxt) edi() uint32     { return c.regs().mc_edi }
-func (c *sigctxt) esi() uint32     { return c.regs().mc_esi }
-func (c *sigctxt) ebp() uint32     { return c.regs().mc_ebp }
-func (c *sigctxt) esp() uint32     { return c.regs().mc_esp }
-func (c *sigctxt) eip() uint32     { return c.regs().mc_eip }
-func (c *sigctxt) eflags() uint32  { return c.regs().mc_eflags }
-func (c *sigctxt) cs() uint32      { return uint32(c.regs().mc_cs) }
-func (c *sigctxt) fs() uint32      { return uint32(c.regs().mc_fs) }
-func (c *sigctxt) gs() uint32      { return uint32(c.regs().mc_gs) }
-func (c *sigctxt) sigcode() uint32 { return uint32(c.info.si_code) }
-func (c *sigctxt) sigaddr() uint32 { return uint32(c.info.si_addr) }
-
-func (c *sigctxt) set_eip(x uint32)     { c.regs().mc_eip = x }
-func (c *sigctxt) set_esp(x uint32)     { c.regs().mc_esp = x }
-func (c *sigctxt) set_sigcode(x uint32) { c.info.si_code = int32(x) }
-func (c *sigctxt) set_sigaddr(x uint32) { c.info.si_addr = uintptr(x) }
diff --git a/src/runtime/signal_linux_arm64.go b/src/runtime/signal_linux_arm64.go
new file mode 100644
index 0000000..7d8b0104
--- /dev/null
+++ b/src/runtime/signal_linux_arm64.go
@@ -0,0 +1,61 @@
+// Copyright 2015 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 runtime
+
+import "unsafe"
+
+type sigctxt struct {
+	info *siginfo
+	ctxt unsafe.Pointer
+}
+
+func (c *sigctxt) regs() *sigcontext { return &(*ucontext)(c.ctxt).uc_mcontext }
+func (c *sigctxt) r0() uint64        { return c.regs().regs[0] }
+func (c *sigctxt) r1() uint64        { return c.regs().regs[1] }
+func (c *sigctxt) r2() uint64        { return c.regs().regs[2] }
+func (c *sigctxt) r3() uint64        { return c.regs().regs[3] }
+func (c *sigctxt) r4() uint64        { return c.regs().regs[4] }
+func (c *sigctxt) r5() uint64        { return c.regs().regs[5] }
+func (c *sigctxt) r6() uint64        { return c.regs().regs[6] }
+func (c *sigctxt) r7() uint64        { return c.regs().regs[7] }
+func (c *sigctxt) r8() uint64        { return c.regs().regs[8] }
+func (c *sigctxt) r9() uint64        { return c.regs().regs[9] }
+func (c *sigctxt) r10() uint64       { return c.regs().regs[10] }
+func (c *sigctxt) r11() uint64       { return c.regs().regs[11] }
+func (c *sigctxt) r12() uint64       { return c.regs().regs[12] }
+func (c *sigctxt) r13() uint64       { return c.regs().regs[13] }
+func (c *sigctxt) r14() uint64       { return c.regs().regs[14] }
+func (c *sigctxt) r15() uint64       { return c.regs().regs[15] }
+func (c *sigctxt) r16() uint64       { return c.regs().regs[16] }
+func (c *sigctxt) r17() uint64       { return c.regs().regs[17] }
+func (c *sigctxt) r18() uint64       { return c.regs().regs[18] }
+func (c *sigctxt) r19() uint64       { return c.regs().regs[19] }
+func (c *sigctxt) r20() uint64       { return c.regs().regs[20] }
+func (c *sigctxt) r21() uint64       { return c.regs().regs[21] }
+func (c *sigctxt) r22() uint64       { return c.regs().regs[22] }
+func (c *sigctxt) r23() uint64       { return c.regs().regs[23] }
+func (c *sigctxt) r24() uint64       { return c.regs().regs[24] }
+func (c *sigctxt) r25() uint64       { return c.regs().regs[25] }
+func (c *sigctxt) r26() uint64       { return c.regs().regs[26] }
+func (c *sigctxt) r27() uint64       { return c.regs().regs[27] }
+func (c *sigctxt) r28() uint64       { return c.regs().regs[28] }
+func (c *sigctxt) r29() uint64       { return c.regs().regs[29] }
+func (c *sigctxt) lr() uint64        { return c.regs().regs[30] }
+func (c *sigctxt) sp() uint64        { return c.regs().sp }
+func (c *sigctxt) pc() uint64        { return c.regs().pc }
+func (c *sigctxt) pstate() uint64    { return c.regs().pstate }
+func (c *sigctxt) fault() uint64     { return c.regs().fault_address }
+
+func (c *sigctxt) sigcode() uint64 { return uint64(c.info.si_code) }
+func (c *sigctxt) sigaddr() uint64 { return c.info.si_addr }
+
+func (c *sigctxt) set_pc(x uint64)  { c.regs().pc = x }
+func (c *sigctxt) set_sp(x uint64)  { c.regs().sp = x }
+func (c *sigctxt) set_lr(x uint64)  { c.regs().regs[30] = x }
+func (c *sigctxt) set_r28(x uint64) { c.regs().regs[28] = x }
+
+func (c *sigctxt) set_sigaddr(x uint64) {
+	*(*uintptr)(add(unsafe.Pointer(c.info), 2*ptrSize)) = uintptr(x)
+}
diff --git a/src/runtime/signal_openbsd_arm.go b/src/runtime/signal_openbsd_arm.go
new file mode 100644
index 0000000..8ee255c
--- /dev/null
+++ b/src/runtime/signal_openbsd_arm.go
@@ -0,0 +1,53 @@
+// Copyright 2013 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 runtime
+
+import "unsafe"
+
+type sigctxt struct {
+	info *siginfo
+	ctxt unsafe.Pointer
+}
+
+func (c *sigctxt) regs() *sigcontext {
+	return (*sigcontext)(c.ctxt)
+}
+
+func (c *sigctxt) r0() uint32      { return c.regs().sc_r0 }
+func (c *sigctxt) r1() uint32      { return c.regs().sc_r1 }
+func (c *sigctxt) r2() uint32      { return c.regs().sc_r2 }
+func (c *sigctxt) r3() uint32      { return c.regs().sc_r3 }
+func (c *sigctxt) r4() uint32      { return c.regs().sc_r4 }
+func (c *sigctxt) r5() uint32      { return c.regs().sc_r5 }
+func (c *sigctxt) r6() uint32      { return c.regs().sc_r6 }
+func (c *sigctxt) r7() uint32      { return c.regs().sc_r7 }
+func (c *sigctxt) r8() uint32      { return c.regs().sc_r8 }
+func (c *sigctxt) r9() uint32      { return c.regs().sc_r9 }
+func (c *sigctxt) r10() uint32     { return c.regs().sc_r10 }
+func (c *sigctxt) fp() uint32      { return c.regs().sc_r11 }
+func (c *sigctxt) ip() uint32      { return c.regs().sc_r12 }
+func (c *sigctxt) sp() uint32      { return c.regs().sc_usr_sp }
+func (c *sigctxt) lr() uint32      { return c.regs().sc_usr_lr }
+func (c *sigctxt) pc() uint32      { return c.regs().sc_pc }
+func (c *sigctxt) cpsr() uint32    { return c.regs().sc_spsr }
+func (c *sigctxt) fault() uint32   { return c.sigaddr() }
+func (c *sigctxt) trap() uint32    { return 0 }
+func (c *sigctxt) error() uint32   { return 0 }
+func (c *sigctxt) oldmask() uint32 { return 0 }
+
+func (c *sigctxt) sigcode() uint32 { return uint32(c.info.si_code) }
+func (c *sigctxt) sigaddr() uint32 {
+	return *(*uint32)(add(unsafe.Pointer(c.info), 12))
+}
+
+func (c *sigctxt) set_pc(x uint32)  { c.regs().sc_pc = x }
+func (c *sigctxt) set_sp(x uint32)  { c.regs().sc_usr_sp = x }
+func (c *sigctxt) set_lr(x uint32)  { c.regs().sc_usr_lr = x }
+func (c *sigctxt) set_r10(x uint32) { c.regs().sc_r10 = x }
+
+func (c *sigctxt) set_sigcode(x uint32) { c.info.si_code = int32(x) }
+func (c *sigctxt) set_sigaddr(x uint32) {
+	*(*uint32)(add(unsafe.Pointer(c.info), 12)) = x
+}
diff --git a/src/runtime/signal_ppc64x.go b/src/runtime/signal_ppc64x.go
index 94b4708..018d7d6 100644
--- a/src/runtime/signal_ppc64x.go
+++ b/src/runtime/signal_ppc64x.go
@@ -50,6 +50,8 @@
 	print("trap ", hex(c.trap()), "\n")
 }
 
+// May run during STW, so write barriers are not allowed.
+//go:nowritebarrier
 func sighandler(sig uint32, info *siginfo, ctxt unsafe.Pointer, gp *g) {
 	_g_ := getg()
 	c := &sigctxt{info, ctxt}
@@ -111,7 +113,7 @@
 	}
 
 	_g_.m.throwing = 1
-	_g_.m.caughtsig = gp
+	setGNoWriteBarrier(&_g_.m.caughtsig, gp)
 	startpanic()
 
 	if sig < uint32(len(sigtable)) {
diff --git a/src/runtime/sigpanic_unix.go b/src/runtime/sigpanic_unix.go
index f1205dc..1ce6223 100644
--- a/src/runtime/sigpanic_unix.go
+++ b/src/runtime/sigpanic_unix.go
@@ -41,3 +41,13 @@
 	}
 	panic(errorString(sigtable[g.sig].name))
 }
+
+// setsigsegv is used on darwin/arm{,64} to fake a segmentation fault.
+//go:nosplit
+func setsigsegv(pc uintptr) {
+	g := getg()
+	g.sig = _SIGSEGV
+	g.sigpc = pc
+	g.sigcode0 = _SEGV_MAPERR
+	g.sigcode1 = 0 // TODO: emulate si_addr
+}
diff --git a/src/runtime/sigqueue.go b/src/runtime/sigqueue.go
index df3c9c0..9cfe259 100644
--- a/src/runtime/sigqueue.go
+++ b/src/runtime/sigqueue.go
@@ -165,14 +165,5 @@
 // This runs on a foreign stack, without an m or a g.  No stack split.
 //go:nosplit
 func badsignal(sig uintptr) {
-	// Some external libraries, for example, OpenBLAS, create worker threads in
-	// a global constructor. If we're doing cpu profiling, and the SIGPROF signal
-	// comes to one of the foreign threads before we make our first cgo call, the
-	// call to cgocallback below will bring down the whole process.
-	// It's better to miss a few SIGPROF signals than to abort in this case.
-	// See http://golang.org/issue/9456.
-	if _SIGPROF != 0 && sig == _SIGPROF && needextram != 0 {
-		return
-	}
 	cgocallback(unsafe.Pointer(funcPC(sigsend)), noescape(unsafe.Pointer(&sig)), unsafe.Sizeof(sig))
 }
diff --git a/src/runtime/slice.go b/src/runtime/slice.go
index 62d6b7c..ae46d9c 100644
--- a/src/runtime/slice.go
+++ b/src/runtime/slice.go
@@ -33,16 +33,13 @@
 	return sliceStruct{p, len, cap}
 }
 
-// TODO: take uintptr instead of int64?
-func growslice(t *slicetype, old sliceStruct, n int64) sliceStruct {
+func growslice(t *slicetype, old sliceStruct, n int) sliceStruct {
 	if n < 1 {
 		panic(errorString("growslice: invalid n"))
 	}
 
-	cap64 := int64(old.cap) + n
-	cap := int(cap64)
-
-	if int64(cap) != cap64 || cap < old.cap || t.elem.size > 0 && uintptr(cap) > _MaxMem/uintptr(t.elem.size) {
+	cap := old.cap + n
+	if cap < old.cap || t.elem.size > 0 && uintptr(cap) > _MaxMem/uintptr(t.elem.size) {
 		panic(errorString("growslice: cap out of range"))
 	}
 
@@ -53,7 +50,9 @@
 
 	et := t.elem
 	if et.size == 0 {
-		return sliceStruct{old.array, old.len, cap}
+		// append should not create a slice with nil pointer but non-zero len.
+		// We assume that append doesn't need to preserve old.array in this case.
+		return sliceStruct{unsafe.Pointer(&zerobase), old.len, cap}
 	}
 
 	newcap := old.cap
diff --git a/src/runtime/stack.h b/src/runtime/stack.h
deleted file mode 100644
index b64123e..0000000
--- a/src/runtime/stack.h
+++ /dev/null
@@ -1,43 +0,0 @@
-// Copyright 2011 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.
-
-// For the linkers. Must match Go definitions.
-// TODO(rsc): Share Go definitions with linkers directly.
-
-enum {
-#ifdef GOOS_windows
-#define STACKSYSTEM (512 * sizeof(uintptr))
-#endif // GOOS_windows
-#ifdef GOOS_plan9
-#define STACKSYSTEM	512
-#endif // GOOS_plan9
-#ifdef GOOS_darwin
-#ifdef GOARCH_arm
-#define STACKSYSTEM 1024
-#endif // GOARCH_arm
-#endif // GOOS_darwin
-
-#ifndef STACKSYSTEM
-#define STACKSYSTEM 0
-#endif
-
-	/*c2go
-	STACKSYSTEM = 0,
-	*/
-
-	StackSystem = STACKSYSTEM,
-
-	StackBig = 4096,
-	StackGuard = 640 + StackSystem,
-	StackSmall = 128,
-	StackLimit = StackGuard - StackSystem - StackSmall,
-};
-
-#define StackPreempt ((uint64)-1314)
-/*c2go
-enum
-{
-	StackPreempt = 1, // TODO: Change to (uint64)-1314 in Go translation
-};
-*/
diff --git a/src/runtime/stack1.go b/src/runtime/stack1.go
index 3f89bb1..5f28d28 100644
--- a/src/runtime/stack1.go
+++ b/src/runtime/stack1.go
@@ -439,10 +439,13 @@
 	// Adjust local variables if stack frame has been allocated.
 	size := frame.varp - frame.sp
 	var minsize uintptr
-	if thechar != '6' && thechar != '8' {
-		minsize = ptrSize
-	} else {
+	switch thechar {
+	case '6', '8':
 		minsize = 0
+	case '7':
+		minsize = spAlign
+	default:
+		minsize = ptrSize
 	}
 	if size > minsize {
 		var bv bitvector
diff --git a/src/runtime/stubs.go b/src/runtime/stubs.go
index 00f74f8..99d8dd4 100644
--- a/src/runtime/stubs.go
+++ b/src/runtime/stubs.go
@@ -8,8 +8,9 @@
 
 // Declarations for runtime services implemented in C or assembly.
 
-const ptrSize = 4 << (^uintptr(0) >> 63) // unsafe.Sizeof(uintptr(0)) but an ideal const
-const regSize = 4 << (^uintreg(0) >> 63) // unsafe.Sizeof(uintreg(0)) but an ideal const
+const ptrSize = 4 << (^uintptr(0) >> 63)             // unsafe.Sizeof(uintptr(0)) but an ideal const
+const regSize = 4 << (^uintreg(0) >> 63)             // unsafe.Sizeof(uintreg(0)) but an ideal const
+const spAlign = 1*(1-goarch_arm64) + 16*goarch_arm64 // SP alignment: 1 normally, 16 for ARM64
 
 // Should be a built-in for unsafe.Pointer?
 //go:nosplit
diff --git a/src/runtime/symtab.go b/src/runtime/symtab.go
index 4f3111d..689a336 100644
--- a/src/runtime/symtab.go
+++ b/src/runtime/symtab.go
@@ -29,15 +29,27 @@
 	_ArgsSizeUnknown            = -0x80000000
 )
 
-var (
-	pclntable []byte
-	ftab      []functab
-	filetab   []uint32
+// moduledata records information about the layout of the executable
+// image. It is written by the linker. Any changes here must be
+// matched changes to the code in cmd/internal/ld/symtab.go:symtab.
+type moduledata struct {
+	pclntable                      []byte
+	ftab                           []functab
+	filetab                        []uint32
+	pclntab, epclntab, findfunctab uintptr
+	minpc, maxpc                   uintptr
 
-	pclntab, epclntab, findfunctab struct{} // linker symbols
+	text, etext           uintptr
+	noptrdata, enoptrdata uintptr
+	data, edata           uintptr
+	bss, ebss             uintptr
+	noptrbss, enoptrbss   uintptr
+	end, gcdata, gcbss    uintptr
 
-	minpc, maxpc uintptr
-)
+	typelink, etypelink uintptr
+}
+
+var themoduledata moduledata // linker symbol
 
 type functab struct {
 	entry   uintptr
@@ -64,38 +76,38 @@
 	// See golang.org/s/go12symtab for header: 0xfffffffb,
 	// two zero bytes, a byte giving the PC quantum,
 	// and a byte giving the pointer width in bytes.
-	pcln := (*[8]byte)(unsafe.Pointer(&pclntab))
-	pcln32 := (*[2]uint32)(unsafe.Pointer(&pclntab))
+	pcln := (*[8]byte)(unsafe.Pointer(themoduledata.pclntab))
+	pcln32 := (*[2]uint32)(unsafe.Pointer(themoduledata.pclntab))
 	if pcln32[0] != 0xfffffffb || pcln[4] != 0 || pcln[5] != 0 || pcln[6] != _PCQuantum || pcln[7] != ptrSize {
 		println("runtime: function symbol table header:", hex(pcln32[0]), hex(pcln[4]), hex(pcln[5]), hex(pcln[6]), hex(pcln[7]))
 		throw("invalid function symbol table\n")
 	}
 
 	// pclntable is all bytes of pclntab symbol.
-	sp := (*sliceStruct)(unsafe.Pointer(&pclntable))
-	sp.array = unsafe.Pointer(&pclntab)
-	sp.len = int(uintptr(unsafe.Pointer(&epclntab)) - uintptr(unsafe.Pointer(&pclntab)))
+	sp := (*sliceStruct)(unsafe.Pointer(&themoduledata.pclntable))
+	sp.array = unsafe.Pointer(themoduledata.pclntab)
+	sp.len = int(uintptr(unsafe.Pointer(themoduledata.epclntab)) - uintptr(unsafe.Pointer(themoduledata.pclntab)))
 	sp.cap = sp.len
 
 	// ftab is lookup table for function by program counter.
 	nftab := int(*(*uintptr)(add(unsafe.Pointer(pcln), 8)))
 	p := add(unsafe.Pointer(pcln), 8+ptrSize)
-	sp = (*sliceStruct)(unsafe.Pointer(&ftab))
+	sp = (*sliceStruct)(unsafe.Pointer(&themoduledata.ftab))
 	sp.array = p
 	sp.len = nftab + 1
 	sp.cap = sp.len
 	for i := 0; i < nftab; i++ {
 		// NOTE: ftab[nftab].entry is legal; it is the address beyond the final function.
-		if ftab[i].entry > ftab[i+1].entry {
-			f1 := (*_func)(unsafe.Pointer(&pclntable[ftab[i].funcoff]))
-			f2 := (*_func)(unsafe.Pointer(&pclntable[ftab[i+1].funcoff]))
+		if themoduledata.ftab[i].entry > themoduledata.ftab[i+1].entry {
+			f1 := (*_func)(unsafe.Pointer(&themoduledata.pclntable[themoduledata.ftab[i].funcoff]))
+			f2 := (*_func)(unsafe.Pointer(&themoduledata.pclntable[themoduledata.ftab[i+1].funcoff]))
 			f2name := "end"
 			if i+1 < nftab {
 				f2name = funcname(f2)
 			}
-			println("function symbol table not sorted by program counter:", hex(ftab[i].entry), funcname(f1), ">", hex(ftab[i+1].entry), f2name)
+			println("function symbol table not sorted by program counter:", hex(themoduledata.ftab[i].entry), funcname(f1), ">", hex(themoduledata.ftab[i+1].entry), f2name)
 			for j := 0; j <= i; j++ {
-				print("\t", hex(ftab[j].entry), " ", funcname((*_func)(unsafe.Pointer(&pclntable[ftab[j].funcoff]))), "\n")
+				print("\t", hex(themoduledata.ftab[j].entry), " ", funcname((*_func)(unsafe.Pointer(&themoduledata.pclntable[themoduledata.ftab[j].funcoff]))), "\n")
 			}
 			throw("invalid runtime symbol table")
 		}
@@ -104,19 +116,19 @@
 	// The ftab ends with a half functab consisting only of
 	// 'entry', followed by a uint32 giving the pcln-relative
 	// offset of the file table.
-	sp = (*sliceStruct)(unsafe.Pointer(&filetab))
-	end := unsafe.Pointer(&ftab[nftab].funcoff) // just beyond ftab
+	sp = (*sliceStruct)(unsafe.Pointer(&themoduledata.filetab))
+	end := unsafe.Pointer(&themoduledata.ftab[nftab].funcoff) // just beyond ftab
 	fileoffset := *(*uint32)(end)
-	sp.array = unsafe.Pointer(&pclntable[fileoffset])
+	sp.array = unsafe.Pointer(&themoduledata.pclntable[fileoffset])
 	// length is in first element of array.
 	// set len to 1 so we can get first element.
 	sp.len = 1
 	sp.cap = 1
-	sp.len = int(filetab[0])
+	sp.len = int(themoduledata.filetab[0])
 	sp.cap = sp.len
 
-	minpc = ftab[0].entry
-	maxpc = ftab[nftab].entry
+	themoduledata.minpc = themoduledata.ftab[0].entry
+	themoduledata.maxpc = themoduledata.ftab[nftab].entry
 }
 
 // FuncForPC returns a *Func describing the function that contains the
@@ -147,33 +159,33 @@
 }
 
 func findfunc(pc uintptr) *_func {
-	if pc < minpc || pc >= maxpc {
+	if pc < themoduledata.minpc || pc >= themoduledata.maxpc {
 		return nil
 	}
 	const nsub = uintptr(len(findfuncbucket{}.subbuckets))
 
-	x := pc - minpc
+	x := pc - themoduledata.minpc
 	b := x / pcbucketsize
 	i := x % pcbucketsize / (pcbucketsize / nsub)
 
-	ffb := (*findfuncbucket)(add(unsafe.Pointer(&findfunctab), b*unsafe.Sizeof(findfuncbucket{})))
+	ffb := (*findfuncbucket)(add(unsafe.Pointer(themoduledata.findfunctab), b*unsafe.Sizeof(findfuncbucket{})))
 	idx := ffb.idx + uint32(ffb.subbuckets[i])
-	if pc < ftab[idx].entry {
+	if pc < themoduledata.ftab[idx].entry {
 		throw("findfunc: bad findfunctab entry")
 	}
 
 	// linear search to find func with pc >= entry.
-	for ftab[idx+1].entry <= pc {
+	for themoduledata.ftab[idx+1].entry <= pc {
 		idx++
 	}
-	return (*_func)(unsafe.Pointer(&pclntable[ftab[idx].funcoff]))
+	return (*_func)(unsafe.Pointer(&themoduledata.pclntable[themoduledata.ftab[idx].funcoff]))
 }
 
 func pcvalue(f *_func, off int32, targetpc uintptr, strict bool) int32 {
 	if off == 0 {
 		return -1
 	}
-	p := pclntable[off:]
+	p := themoduledata.pclntable[off:]
 	pc := f.entry
 	val := int32(-1)
 	for {
@@ -195,7 +207,7 @@
 
 	print("runtime: invalid pc-encoded table f=", funcname(f), " pc=", hex(pc), " targetpc=", hex(targetpc), " tab=", p, "\n")
 
-	p = pclntable[off:]
+	p = themoduledata.pclntable[off:]
 	pc = f.entry
 	val = -1
 	for {
@@ -215,7 +227,7 @@
 	if f == nil || f.nameoff == 0 {
 		return nil
 	}
-	return (*byte)(unsafe.Pointer(&pclntable[f.nameoff]))
+	return (*byte)(unsafe.Pointer(&themoduledata.pclntable[f.nameoff]))
 }
 
 func funcname(f *_func) string {
@@ -225,11 +237,11 @@
 func funcline1(f *_func, targetpc uintptr, strict bool) (file string, line int32) {
 	fileno := int(pcvalue(f, f.pcfile, targetpc, strict))
 	line = pcvalue(f, f.pcln, targetpc, strict)
-	if fileno == -1 || line == -1 || fileno >= len(filetab) {
+	if fileno == -1 || line == -1 || fileno >= len(themoduledata.filetab) {
 		// print("looking for ", hex(targetpc), " in ", funcname(f), " got file=", fileno, " line=", lineno, "\n")
 		return "?", 0
 	}
-	file = gostringnocopy(&pclntable[filetab[fileno]])
+	file = gostringnocopy(&themoduledata.pclntable[themoduledata.filetab[fileno]])
 	return
 }
 
diff --git a/src/runtime/sys_arm64.go b/src/runtime/sys_arm64.go
new file mode 100644
index 0000000..dee23ef
--- /dev/null
+++ b/src/runtime/sys_arm64.go
@@ -0,0 +1,36 @@
+// Copyright 2013 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 runtime
+
+import "unsafe"
+
+// adjust Gobuf as if it executed a call to fn with context ctxt
+// and then did an immediate Gosave.
+func gostartcall(buf *gobuf, fn, ctxt unsafe.Pointer) {
+	if buf.lr != 0 {
+		throw("invalid use of gostartcall")
+	}
+	buf.lr = buf.pc
+	buf.pc = uintptr(fn)
+	buf.ctxt = ctxt
+}
+
+// Called to rewind context saved during morestack back to beginning of function.
+// To help us, the linker emits a jmp back to the beginning right after the
+// call to morestack. We just have to decode and apply that jump.
+func rewindmorestack(buf *gobuf) {
+	var inst uint32
+	if buf.pc&3 == 0 && buf.pc != 0 {
+		inst = *(*uint32)(unsafe.Pointer(buf.pc))
+		// section C3.2.6 Unconditional branch (immediate)
+		if inst>>26 == 0x05 {
+			buf.pc += uintptr(int32(inst<<6) >> 4)
+			return
+		}
+	}
+
+	print("runtime: pc=", hex(buf.pc), " ", hex(inst), "\n")
+	throw("runtime: misuse of rewindmorestack")
+}
diff --git a/src/runtime/sys_darwin_386.s b/src/runtime/sys_darwin_386.s
index 46857a6..20d6b72 100644
--- a/src/runtime/sys_darwin_386.s
+++ b/src/runtime/sys_darwin_386.s
@@ -29,24 +29,32 @@
 TEXT runtime·open(SB),NOSPLIT,$0
 	MOVL	$5, AX
 	INT	$0x80
+	JAE	2(PC)
+	MOVL	$-1, AX
 	MOVL	AX, ret+12(FP)
 	RET
 
 TEXT runtime·close(SB),NOSPLIT,$0
 	MOVL	$6, AX
 	INT	$0x80
+	JAE	2(PC)
+	MOVL	$-1, AX
 	MOVL	AX, ret+4(FP)
 	RET
 
 TEXT runtime·read(SB),NOSPLIT,$0
 	MOVL	$3, AX
 	INT	$0x80
+	JAE	2(PC)
+	MOVL	$-1, AX
 	MOVL	AX, ret+12(FP)
 	RET
 
 TEXT runtime·write(SB),NOSPLIT,$0
 	MOVL	$4, AX
 	INT	$0x80
+	JAE	2(PC)
+	MOVL	$-1, AX
 	MOVL	AX, ret+12(FP)
 	RET
 
diff --git a/src/runtime/sys_darwin_amd64.s b/src/runtime/sys_darwin_amd64.s
index a6ab6bc..f856e95 100644
--- a/src/runtime/sys_darwin_amd64.s
+++ b/src/runtime/sys_darwin_amd64.s
@@ -38,6 +38,8 @@
 	MOVL	perm+12(FP), DX		// arg 3 mode
 	MOVL	$(0x2000000+5), AX	// syscall entry
 	SYSCALL
+	JCC	2(PC)
+	MOVL	$-1, AX
 	MOVL	AX, ret+16(FP)
 	RET
 
@@ -45,6 +47,8 @@
 	MOVL	fd+0(FP), DI		// arg 1 fd
 	MOVL	$(0x2000000+6), AX	// syscall entry
 	SYSCALL
+	JCC	2(PC)
+	MOVL	$-1, AX
 	MOVL	AX, ret+8(FP)
 	RET
 
@@ -54,6 +58,8 @@
 	MOVL	n+16(FP), DX		// arg 3 count
 	MOVL	$(0x2000000+3), AX	// syscall entry
 	SYSCALL
+	JCC	2(PC)
+	MOVL	$-1, AX
 	MOVL	AX, ret+24(FP)
 	RET
 
@@ -63,6 +69,8 @@
 	MOVL	n+16(FP), DX		// arg 3 count
 	MOVL	$(0x2000000+4), AX	// syscall entry
 	SYSCALL
+	JCC	2(PC)
+	MOVL	$-1, AX
 	MOVL	AX, ret+24(FP)
 	RET
 
diff --git a/src/runtime/sys_darwin_arm.s b/src/runtime/sys_darwin_arm.s
index 0ca4262..5cb8601 100644
--- a/src/runtime/sys_darwin_arm.s
+++ b/src/runtime/sys_darwin_arm.s
@@ -48,6 +48,7 @@
 	MOVW	perm+8(FP), R2
 	MOVW	$SYS_open, R12
 	SWI	$0x80
+	MOVW.CS	$-1, R0
 	MOVW	R0, ret+12(FP)
 	RET
 
@@ -55,6 +56,7 @@
 	MOVW	fd+0(FP), R0
 	MOVW	$SYS_close, R12
 	SWI	$0x80
+	MOVW.CS	$-1, R0
 	MOVW	R0, ret+4(FP)
 	RET
 
@@ -64,6 +66,7 @@
 	MOVW	n+8(FP), R2
 	MOVW	$SYS_write, R12
 	SWI	$0x80
+	MOVW.CS	$-1, R0
 	MOVW	R0, ret+12(FP)
 	RET
 
@@ -73,6 +76,7 @@
 	MOVW	n+8(FP), R2
 	MOVW	$SYS_read, R12
 	SWI	$0x80
+	MOVW.CS	$-1, R0
 	MOVW	R0, ret+12(FP)
 	RET
 
diff --git a/src/runtime/sys_dragonfly_386.s b/src/runtime/sys_dragonfly_386.s
deleted file mode 100644
index bb4903e..0000000
--- a/src/runtime/sys_dragonfly_386.s
+++ /dev/null
@@ -1,382 +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.
-//
-// System calls and other sys.stuff for 386, FreeBSD
-// /usr/src/sys/kern/syscalls.master for syscall numbers.
-//
-
-#include "go_asm.h"
-#include "go_tls.h"
-#include "textflag.h"
-	
-TEXT runtime·sys_umtx_sleep(SB),NOSPLIT,$-4
-	MOVL	$469, AX		// umtx_sleep
-	INT	$0x80
-	JAE	2(PC)
-	NEGL	AX
-	MOVL	AX, ret+12(FP)
-	RET
-
-TEXT runtime·sys_umtx_wakeup(SB),NOSPLIT,$-4
-	MOVL	$470, AX		// umtx_wakeup
-	INT	$0x80
-	JAE	2(PC)
-	NEGL	AX
-	MOVL	AX, ret+8(FP)
-	RET
-
-TEXT runtime·lwp_create(SB),NOSPLIT,$-4
-	MOVL	$495, AX		// lwp_create
-	INT	$0x80
-	MOVL	AX, ret+4(FP)
-	RET
-
-TEXT runtime·lwp_start(SB),NOSPLIT,$0
-
-	// Set GS to point at m->tls.
-	MOVL	mm+0(FP), BX
-	MOVL	m_g0(BX), DX
-	LEAL	m_tls(BX), BP
-	PUSHAL
-	PUSHL	BP
-	CALL	runtime·settls(SB)
-	POPL	AX
-	POPAL
-	
-	// Now segment is established.  Initialize m, g.
-	get_tls(CX)
-	MOVL	BX, g_m(DX)
-	MOVL	DX, g(CX)
-
-	CALL	runtime·stackcheck(SB)	// smashes AX, CX
-	MOVL	0(DX), DX		// paranoia; check they are not nil
-	MOVL	0(BX), BX
-
-	// More paranoia; check that stack splitting code works.
-	PUSHAL
-	CALL	runtime·emptyfunc(SB)
-	POPAL
-
-	CALL	runtime·mstart(SB)
-
-	CALL	runtime·exit1(SB)
-	MOVL	$0x1234, 0x1005
-	RET
-
-// Exit the entire program (like C exit)
-TEXT runtime·exit(SB),NOSPLIT,$-4
-	MOVL	$1, AX
-	INT	$0x80
-	MOVL	$0xf1, 0xf1  // crash
-	RET
-
-TEXT runtime·exit1(SB),NOSPLIT,$16
-	MOVL	$0, 0(SP)		// syscall gap
-	MOVL	$0x10000, 4(SP)		// arg 1 - how (EXTEXIT_LWP)
-	MOVL	$0, 8(SP)		// arg 2 - status
-	MOVL	$0, 12(SP)		// arg 3 - addr
-	MOVL	$494, AX
-	INT	$0x80
-	JAE	2(PC)
-	MOVL	$0xf1, 0xf1  // crash
-	RET
-
-TEXT runtime·open(SB),NOSPLIT,$-4
-	MOVL	$5, AX
-	INT	$0x80
-	MOVL	AX, ret+12(FP)
-	RET
-
-TEXT runtime·close(SB),NOSPLIT,$-4
-	MOVL	$6, AX
-	INT	$0x80
-	MOVL	AX, ret+4(FP)
-	RET
-
-TEXT runtime·read(SB),NOSPLIT,$-4
-	MOVL	$3, AX
-	INT	$0x80
-	MOVL	AX, ret+12(FP)
-	RET
-
-TEXT runtime·write(SB),NOSPLIT,$-4
-	MOVL	$4, AX
-	INT	$0x80
-	MOVL	AX, ret+12(FP)
-	RET
-
-TEXT runtime·getrlimit(SB),NOSPLIT,$-4
-	MOVL	$194, AX
-	INT	$0x80
-	MOVL	AX, ret+8(FP)
-	RET
-
-TEXT runtime·raise(SB),NOSPLIT,$16
-	MOVL	$496, AX		// lwp_gettid
-	INT	$0x80
-	MOVL	$0, 0(SP)
-	MOVL	$-1, 4(SP)		// arg 1 - pid
-	MOVL	AX, 8(SP)		// arg 2 - tid
-	MOVL	sig+0(FP), AX
-	MOVL	AX, 8(SP)		// arg 3 - signum
-	MOVL	$497, AX		// lwp_kill
-	INT	$0x80
-	RET
-
-TEXT runtime·mmap(SB),NOSPLIT,$36
-	LEAL	addr+0(FP), SI
-	LEAL	4(SP), DI
-	CLD
-	MOVSL				// arg 1 - addr
-	MOVSL				// arg 2 - len
-	MOVSL				// arg 3 - prot
-	MOVSL				// arg 4 - flags
-	MOVSL				// arg 5 - fd
-	MOVL	$0, AX
-	STOSL				// arg 6 - pad
-	MOVSL				// arg 7 - offset
-	MOVL	$0, AX			// top 32 bits of file offset
-	STOSL
-	MOVL	$197, AX		// sys_mmap
-	INT	$0x80
-	MOVL	AX, ret+24(FP)
-	RET
-
-TEXT runtime·munmap(SB),NOSPLIT,$-4
-	MOVL	$73, AX
-	INT	$0x80
-	JAE	2(PC)
-	MOVL	$0xf1, 0xf1  // crash
-	RET
-
-TEXT runtime·madvise(SB),NOSPLIT,$-4
-	MOVL	$75, AX	// madvise
-	INT	$0x80
-	// ignore failure - maybe pages are locked
-	RET
-
-TEXT runtime·setitimer(SB), NOSPLIT, $-4
-	MOVL	$83, AX
-	INT	$0x80
-	RET
-
-// func now() (sec int64, nsec int32)
-TEXT time·now(SB), NOSPLIT, $32
-	MOVL	$232, AX
-	LEAL	12(SP), BX
-	MOVL	$0, 4(SP)	// CLOCK_REALTIME
-	MOVL	BX, 8(SP)
-	INT	$0x80
-	MOVL	12(SP), AX	// sec
-	MOVL	16(SP), BX	// nsec
-
-	// sec is in AX, nsec in BX
-	MOVL	AX, sec+0(FP)
-	MOVL	$0, sec+4(FP)
-	MOVL	BX, nsec+8(FP)
-	RET
-
-// int64 nanotime(void) so really
-// void nanotime(int64 *nsec)
-TEXT runtime·nanotime(SB), NOSPLIT, $32
-	MOVL	$232, AX
-	LEAL	12(SP), BX
-	MOVL	$4, 4(SP)	// CLOCK_MONOTONIC
-	MOVL	BX, 8(SP)
-	INT	$0x80
-	MOVL	12(SP), AX	// sec
-	MOVL	16(SP), BX	// nsec
-
-	// sec is in AX, nsec in BX
-	// convert to DX:AX nsec
-	MOVL	$1000000000, CX
-	MULL	CX
-	ADDL	BX, AX
-	ADCL	$0, DX
-
-	MOVL	AX, ret_lo+0(FP)
-	MOVL	DX, ret_hi+4(FP)
-	RET
-
-
-TEXT runtime·sigaction(SB),NOSPLIT,$-4
-	MOVL	$342, AX
-	INT	$0x80
-	JAE	2(PC)
-	MOVL	$0xf1, 0xf1  // crash
-	RET
-
-TEXT runtime·sigtramp(SB),NOSPLIT,$44
-	get_tls(CX)
-
-	// check that g exists
-	MOVL	g(CX), DI
-	CMPL	DI, $0
-	JNE	6(PC)
-	MOVL	signo+0(FP), BX
-	MOVL	BX, 0(SP)
-	MOVL	$runtime·badsignal(SB), AX
-	CALL	AX
-	JMP 	ret
-
-	// save g
-	MOVL	DI, 20(SP)
-	
-	// g = m->gsignal
-	MOVL	g_m(DI), BX
-	MOVL	m_gsignal(BX), BX
-	MOVL	BX, g(CX)
-
-	// copy arguments for call to sighandler
-	MOVL	signo+0(FP), BX
-	MOVL	BX, 0(SP)
-	MOVL	info+4(FP), BX
-	MOVL	BX, 4(SP)
-	MOVL	context+8(FP), BX
-	MOVL	BX, 8(SP)
-	MOVL	DI, 12(SP)
-
-	CALL	runtime·sighandler(SB)
-
-	// restore g
-	get_tls(CX)
-	MOVL	20(SP), BX
-	MOVL	BX, g(CX)
-
-ret:
-	// call sigreturn
-	MOVL	context+8(FP), AX
-	MOVL	$0, 0(SP)	// syscall gap
-	MOVL	AX, 4(SP)
-	MOVL	$344, AX	// sigreturn(ucontext)
-	INT	$0x80
-	MOVL	$0xf1, 0xf1  // crash
-	RET
-
-TEXT runtime·sigaltstack(SB),NOSPLIT,$0
-	MOVL	$53, AX
-	INT	$0x80
-	JAE	2(PC)
-	MOVL	$0xf1, 0xf1  // crash
-	RET
-
-TEXT runtime·usleep(SB),NOSPLIT,$20
-	MOVL	$0, DX
-	MOVL	usec+0(FP), AX
-	MOVL	$1000000, CX
-	DIVL	CX
-	MOVL	AX, 12(SP)		// tv_sec
-	MOVL	$1000, AX
-	MULL	DX
-	MOVL	AX, 16(SP)		// tv_nsec
-
-	MOVL	$0, 0(SP)
-	LEAL	12(SP), AX
-	MOVL	AX, 4(SP)		// arg 1 - rqtp
-	MOVL	$0, 8(SP)		// arg 2 - rmtp
-	MOVL	$240, AX		// sys_nanosleep
-	INT	$0x80
-	RET
-
-TEXT runtime·setldt(SB),NOSPLIT,$4
-	// Under DragonFly we set the GS base instead of messing with the LDT.
-	MOVL	tls0+4(FP), AX
-	MOVL	AX, 0(SP)
-	CALL	runtime·settls(SB)
-	RET
-
-TEXT runtime·settls(SB),NOSPLIT,$24
-	// adjust for ELF: wants to use -8(GS) and -4(GS) for g and m
-	MOVL	tlsbase+0(FP), CX
-	ADDL	$8, CX
-
-	// Set up a struct tls_info - a size of -1 maps the whole address
-	// space and is required for direct-tls access of variable data
-	// via negative offsets.
-	LEAL	16(SP), BX
-	MOVL	CX, 16(SP)		// base
-	MOVL	$-1, 20(SP)		// size
-
-	// set_tls_area returns the descriptor that needs to be loaded into GS.
-	MOVL	$0, 0(SP)		// syscall gap
-	MOVL	$0, 4(SP)		// arg 1 - which
-	MOVL	BX, 8(SP)		// arg 2 - tls_info
-	MOVL	$8, 12(SP)		// arg 3 - infosize
-	MOVL    $472, AX                // set_tls_area
-	INT     $0x80
-	JCC     2(PC)
-	MOVL    $0xf1, 0xf1             // crash
-	MOVW	AX, GS
-	RET
-
-TEXT runtime·sysctl(SB),NOSPLIT,$28
-	LEAL	mib+0(FP), SI
-	LEAL	4(SP), DI
-	CLD
-	MOVSL				// arg 1 - name
-	MOVSL				// arg 2 - namelen
-	MOVSL				// arg 3 - oldp
-	MOVSL				// arg 4 - oldlenp
-	MOVSL				// arg 5 - newp
-	MOVSL				// arg 6 - newlen
-	MOVL	$202, AX		// sys___sysctl
-	INT	$0x80
-	JCC	4(PC)
-	NEGL	AX
-	MOVL	AX, ret+24(FP)
-	RET
-	MOVL	$0, AX
-	MOVL	AX, ret+24(FP)
-	RET
-
-TEXT runtime·osyield(SB),NOSPLIT,$-4
-	MOVL	$331, AX		// sys_sched_yield
-	INT	$0x80
-	RET
-
-TEXT runtime·sigprocmask(SB),NOSPLIT,$16
-	MOVL	$0, 0(SP)		// syscall gap
-	MOVL	$3, 4(SP)		// arg 1 - how (SIG_SETMASK)
-	MOVL	new+0(FP), AX
-	MOVL	AX, 8(SP)		// arg 2 - set
-	MOVL	old+4(FP), AX
-	MOVL	AX, 12(SP)		// arg 3 - oset
-	MOVL	$340, AX		// sys_sigprocmask
-	INT	$0x80
-	JAE	2(PC)
-	MOVL	$0xf1, 0xf1  // crash
-	RET
-
-// int32 runtime·kqueue(void);
-TEXT runtime·kqueue(SB),NOSPLIT,$0
-	MOVL	$362, AX
-	INT	$0x80
-	JAE	2(PC)
-	NEGL	AX
-	MOVL	AX, ret+0(FP)
-	RET
-
-// int32 runtime·kevent(int kq, Kevent *changelist, int nchanges, Kevent *eventlist, int nevents, Timespec *timeout);
-TEXT runtime·kevent(SB),NOSPLIT,$0
-	MOVL	$363, AX
-	INT	$0x80
-	JAE	2(PC)
-	NEGL	AX
-	MOVL	AX, ret+24(FP)
-	RET
-
-// int32 runtime·closeonexec(int32 fd);
-TEXT runtime·closeonexec(SB),NOSPLIT,$32
-	MOVL	$92, AX		// fcntl
-	// 0(SP) is where the caller PC would be; kernel skips it
-	MOVL	fd+0(FP), BX
-	MOVL	BX, 4(SP)	// fd
-	MOVL	$2, 8(SP)	// F_SETFD
-	MOVL	$1, 12(SP)	// FD_CLOEXEC
-	INT	$0x80
-	JAE	2(PC)
-	NEGL	AX
-	RET
-
-GLOBL runtime·tlsoffset(SB),NOPTR,$4
diff --git a/src/runtime/sys_dragonfly_amd64.s b/src/runtime/sys_dragonfly_amd64.s
index 2f2942a..1227196 100644
--- a/src/runtime/sys_dragonfly_amd64.s
+++ b/src/runtime/sys_dragonfly_amd64.s
@@ -77,6 +77,8 @@
 	MOVL	perm+12(FP), DX		// arg 3 mode
 	MOVL	$5, AX
 	SYSCALL
+	JCC	2(PC)
+	MOVL	$-1, AX
 	MOVL	AX, ret+16(FP)
 	RET
 
@@ -84,6 +86,8 @@
 	MOVL	fd+0(FP), DI		// arg 1 fd
 	MOVL	$6, AX
 	SYSCALL
+	JCC	2(PC)
+	MOVL	$-1, AX
 	MOVL	AX, ret+8(FP)
 	RET
 
@@ -93,6 +97,8 @@
 	MOVL	n+16(FP), DX		// arg 3 count
 	MOVL	$3, AX
 	SYSCALL
+	JCC	2(PC)
+	MOVL	$-1, AX
 	MOVL	AX, ret+24(FP)
 	RET
 
@@ -102,6 +108,8 @@
 	MOVL	n+16(FP), DX		// arg 3 count
 	MOVL	$4, AX
 	SYSCALL
+	JCC	2(PC)
+	MOVL	$-1, AX
 	MOVL	AX, ret+24(FP)
 	RET
 
@@ -264,7 +272,7 @@
 
 // set tls base to DI
 TEXT runtime·settls(SB),NOSPLIT,$16
-	ADDQ	$16, DI	// adjust for ELF: wants to use -16(FS) and -8(FS) for g and m
+	ADDQ	$8, DI	// adjust for ELF: wants to use -8(FS) for g
 	MOVQ	DI, 0(SP)
 	MOVQ	$16, 8(SP)
 	MOVQ	$0, DI			// arg 1 - which
diff --git a/src/runtime/sys_freebsd_386.s b/src/runtime/sys_freebsd_386.s
index d1f67c3..eed6b8d 100644
--- a/src/runtime/sys_freebsd_386.s
+++ b/src/runtime/sys_freebsd_386.s
@@ -62,24 +62,32 @@
 TEXT runtime·open(SB),NOSPLIT,$-4
 	MOVL	$5, AX
 	INT	$0x80
+	JAE	2(PC)
+	MOVL	$-1, AX
 	MOVL	AX, ret+12(FP)
 	RET
 
 TEXT runtime·close(SB),NOSPLIT,$-4
 	MOVL	$6, AX
 	INT	$0x80
+	JAE	2(PC)
+	MOVL	$-1, AX
 	MOVL	AX, ret+4(FP)
 	RET
 
 TEXT runtime·read(SB),NOSPLIT,$-4
 	MOVL	$3, AX
 	INT	$0x80
+	JAE	2(PC)
+	MOVL	$-1, AX
 	MOVL	AX, ret+12(FP)
 	RET
 
 TEXT runtime·write(SB),NOSPLIT,$-4
 	MOVL	$4, AX
 	INT	$0x80
+	JAE	2(PC)
+	MOVL	$-1, AX
 	MOVL	AX, ret+12(FP)
 	RET
 
@@ -279,7 +287,7 @@
 TEXT runtime·setldt(SB),NOSPLIT,$32
 	MOVL	address+4(FP), BX	// aka base
 	// see comment in sys_linux_386.s; freebsd is similar
-	ADDL	$0x8, BX
+	ADDL	$0x4, BX
 
 	// set up data_desc
 	LEAL	16(SP), AX	// struct data_desc
diff --git a/src/runtime/sys_freebsd_amd64.s b/src/runtime/sys_freebsd_amd64.s
index eac0319..ecc40e3 100644
--- a/src/runtime/sys_freebsd_amd64.s
+++ b/src/runtime/sys_freebsd_amd64.s
@@ -67,6 +67,8 @@
 	MOVL	perm+12(FP), DX		// arg 3 mode
 	MOVL	$5, AX
 	SYSCALL
+	JCC	2(PC)
+	MOVL	$-1, AX
 	MOVL	AX, ret+16(FP)
 	RET
 
@@ -74,6 +76,8 @@
 	MOVL	fd+0(FP), DI		// arg 1 fd
 	MOVL	$6, AX
 	SYSCALL
+	JCC	2(PC)
+	MOVL	$-1, AX
 	MOVL	AX, ret+8(FP)
 	RET
 
@@ -83,6 +87,8 @@
 	MOVL	n+16(FP), DX		// arg 3 count
 	MOVL	$3, AX
 	SYSCALL
+	JCC	2(PC)
+	MOVL	$-1, AX
 	MOVL	AX, ret+24(FP)
 	RET
 
@@ -92,6 +98,8 @@
 	MOVL	n+16(FP), DX		// arg 3 count
 	MOVL	$4, AX
 	SYSCALL
+	JCC	2(PC)
+	MOVL	$-1, AX
 	MOVL	AX, ret+24(FP)
 	RET
 
@@ -254,7 +262,7 @@
 
 // set tls base to DI
 TEXT runtime·settls(SB),NOSPLIT,$8
-	ADDQ	$16, DI	// adjust for ELF: wants to use -16(FS) and -8(FS) for g and m
+	ADDQ	$8, DI	// adjust for ELF: wants to use -8(FS) for g and m
 	MOVQ	DI, 0(SP)
 	MOVQ	SP, SI
 	MOVQ	$129, DI	// AMD64_SET_FSBASE
diff --git a/src/runtime/sys_freebsd_arm.s b/src/runtime/sys_freebsd_arm.s
index 6568738..613c1dc 100644
--- a/src/runtime/sys_freebsd_arm.s
+++ b/src/runtime/sys_freebsd_arm.s
@@ -93,6 +93,7 @@
 	MOVW perm+8(FP), R2	// arg 3 perm
 	MOVW $SYS_open, R7
 	SWI $0
+	MOVW.CS	$-1, R0
 	MOVW	R0, ret+12(FP)
 	RET
 
@@ -102,6 +103,7 @@
 	MOVW n+8(FP), R2	// arg 3 count
 	MOVW $SYS_read, R7
 	SWI $0
+	MOVW.CS	$-1, R0
 	MOVW	R0, ret+12(FP)
 	RET
 
@@ -111,6 +113,7 @@
 	MOVW n+8(FP), R2	// arg 3 count
 	MOVW $SYS_write, R7
 	SWI $0
+	MOVW.CS	$-1, R0
 	MOVW	R0, ret+12(FP)
 	RET
 
@@ -118,6 +121,7 @@
 	MOVW fd+0(FP), R0	// arg 1 fd
 	MOVW $SYS_close, R7
 	SWI $0
+	MOVW.CS	$-1, R0
 	MOVW	R0, ret+4(FP)
 	RET
 
diff --git a/src/runtime/sys_linux_386.s b/src/runtime/sys_linux_386.s
index 2acce48..d4bd142 100644
--- a/src/runtime/sys_linux_386.s
+++ b/src/runtime/sys_linux_386.s
@@ -30,6 +30,9 @@
 	MOVL	mode+4(FP), CX
 	MOVL	perm+8(FP), DX
 	CALL	*runtime·_vdso(SB)
+	CMPL	AX, $0xfffff001
+	JLS	2(PC)
+	MOVL	$-1, AX
 	MOVL	AX, ret+12(FP)
 	RET
 
@@ -37,6 +40,9 @@
 	MOVL	$6, AX		// syscall - close
 	MOVL	fd+0(FP), BX
 	CALL	*runtime·_vdso(SB)
+	CMPL	AX, $0xfffff001
+	JLS	2(PC)
+	MOVL	$-1, AX
 	MOVL	AX, ret+4(FP)
 	RET
 
@@ -46,6 +52,9 @@
 	MOVL	p+4(FP), CX
 	MOVL	n+8(FP), DX
 	CALL	*runtime·_vdso(SB)
+	CMPL	AX, $0xfffff001
+	JLS	2(PC)
+	MOVL	$-1, AX
 	MOVL	AX, ret+12(FP)
 	RET
 
@@ -55,6 +64,9 @@
 	MOVL	p+4(FP), CX
 	MOVL	n+8(FP), DX
 	CALL	*runtime·_vdso(SB)
+	CMPL	AX, $0xfffff001
+	JLS	2(PC)
+	MOVL	$-1, AX
 	MOVL	AX, ret+12(FP)
 	RET
 
@@ -398,16 +410,16 @@
 	 * When linking against the system libraries,
 	 * we use its pthread_create and let it set up %gs
 	 * for us.  When we do that, the private storage
-	 * we get is not at 0(GS), 4(GS), but -8(GS), -4(GS).
+	 * we get is not at 0(GS), but -4(GS).
 	 * To insulate the rest of the tool chain from this
-	 * ugliness, 8l rewrites 0(TLS) into -8(GS) for us.
+	 * ugliness, 8l rewrites 0(TLS) into -4(GS) for us.
 	 * To accommodate that rewrite, we translate
 	 * the address here and bump the limit to 0xffffffff (no limit)
-	 * so that -8(GS) maps to 0(address).
-	 * Also, the final 0(GS) (current 8(CX)) has to point
+	 * so that -4(GS) maps to 0(address).
+	 * Also, the final 0(GS) (current 4(CX)) has to point
 	 * to itself, to mimic ELF.
 	 */
-	ADDL	$0x8, CX	// address
+	ADDL	$0x4, CX	// address
 	MOVL	CX, 0(CX)
 
 	// set up user_desc
diff --git a/src/runtime/sys_linux_amd64.s b/src/runtime/sys_linux_amd64.s
index aac741b..75e1c42 100644
--- a/src/runtime/sys_linux_amd64.s
+++ b/src/runtime/sys_linux_amd64.s
@@ -28,6 +28,9 @@
 	MOVL	perm+12(FP), DX
 	MOVL	$2, AX			// syscall entry
 	SYSCALL
+	CMPQ	AX, $0xfffffffffffff001
+	JLS	2(PC)
+	MOVL	$-1, AX
 	MOVL	AX, ret+16(FP)
 	RET
 
@@ -35,6 +38,9 @@
 	MOVL	fd+0(FP), DI
 	MOVL	$3, AX			// syscall entry
 	SYSCALL
+	CMPQ	AX, $0xfffffffffffff001
+	JLS	2(PC)
+	MOVL	$-1, AX
 	MOVL	AX, ret+8(FP)
 	RET
 
@@ -44,6 +50,9 @@
 	MOVL	n+16(FP), DX
 	MOVL	$1, AX			// syscall entry
 	SYSCALL
+	CMPQ	AX, $0xfffffffffffff001
+	JLS	2(PC)
+	MOVL	$-1, AX
 	MOVL	AX, ret+24(FP)
 	RET
 
@@ -53,6 +62,9 @@
 	MOVL	n+16(FP), DX
 	MOVL	$0, AX			// syscall entry
 	SYSCALL
+	CMPQ	AX, $0xfffffffffffff001
+	JLS	2(PC)
+	MOVL	$-1, AX
 	MOVL	AX, ret+24(FP)
 	RET
 
@@ -347,7 +359,7 @@
 
 // set tls base to DI
 TEXT runtime·settls(SB),NOSPLIT,$32
-	ADDQ	$16, DI	// ELF wants to use -16(FS), -8(FS)
+	ADDQ	$8, DI	// ELF wants to use -8(FS)
 
 	MOVQ	DI, SI
 	MOVQ	$0x1002, DI	// ARCH_SET_FS
diff --git a/src/runtime/sys_linux_arm.s b/src/runtime/sys_linux_arm.s
index 844a02a..fa07ef8 100644
--- a/src/runtime/sys_linux_arm.s
+++ b/src/runtime/sys_linux_arm.s
@@ -57,6 +57,9 @@
 	MOVW	perm+8(FP), R2
 	MOVW	$SYS_open, R7
 	SWI	$0
+	MOVW	$0xfffff001, R1
+	CMP	R1, R0
+	MOVW.HI	$-1, R0
 	MOVW	R0, ret+12(FP)
 	RET
 
@@ -64,6 +67,9 @@
 	MOVW	fd+0(FP), R0
 	MOVW	$SYS_close, R7
 	SWI	$0
+	MOVW	$0xfffff001, R1
+	CMP	R1, R0
+	MOVW.HI	$-1, R0
 	MOVW	R0, ret+4(FP)
 	RET
 
@@ -73,6 +79,9 @@
 	MOVW	n+8(FP), R2
 	MOVW	$SYS_write, R7
 	SWI	$0
+	MOVW	$0xfffff001, R1
+	CMP	R1, R0
+	MOVW.HI	$-1, R0
 	MOVW	R0, ret+12(FP)
 	RET
 
@@ -82,6 +91,9 @@
 	MOVW	n+8(FP), R2
 	MOVW	$SYS_read, R7
 	SWI	$0
+	MOVW	$0xfffff001, R1
+	CMP	R1, R0
+	MOVW.HI	$-1, R0
 	MOVW	R0, ret+12(FP)
 	RET
 
diff --git a/src/runtime/sys_linux_arm64.s b/src/runtime/sys_linux_arm64.s
new file mode 100644
index 0000000..0d0131b8
--- /dev/null
+++ b/src/runtime/sys_linux_arm64.s
@@ -0,0 +1,431 @@
+// 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.
+
+//
+// System calls and other sys.stuff for arm64, Linux
+//
+
+#include "go_asm.h"
+#include "go_tls.h"
+#include "textflag.h"
+
+#define AT_FDCWD -100
+
+#define SYS_exit		93
+#define SYS_read		63
+#define SYS_write		64
+#define SYS_openat		56
+#define SYS_close		57
+#define SYS_fcntl		25
+#define SYS_gettimeofday	169
+#define SYS_pselect6		72
+#define SYS_mmap		222
+#define SYS_munmap		215
+#define SYS_setitimer		103
+#define SYS_clone		220
+#define SYS_sched_yield		124
+#define SYS_rt_sigreturn	139
+#define SYS_rt_sigaction	134
+#define SYS_rt_sigprocmask	135
+#define SYS_sigaltstack		132
+#define SYS_getrlimit		163
+#define SYS_madvise		233
+#define SYS_mincore		232
+#define SYS_gettid		178
+#define SYS_tkill		130
+#define SYS_futex		98
+#define SYS_sched_getaffinity	123
+#define SYS_exit_group		94
+#define SYS_epoll_create1	20
+#define SYS_epoll_ctl		21
+#define SYS_epoll_pwait		22
+#define SYS_clock_gettime	113
+
+TEXT runtime·exit(SB),NOSPLIT,$-8-4
+	MOVW	code+0(FP), R0
+	MOVD	$SYS_exit_group, R8
+	SVC
+	RET
+
+TEXT runtime·exit1(SB),NOSPLIT,$-8-4
+	MOVW	code+0(FP), R0
+	MOVD	$SYS_exit, R8
+	SVC
+	RET
+
+TEXT runtime·open(SB),NOSPLIT,$-8-20
+	MOVD	$AT_FDCWD, R0
+	MOVD	name+0(FP), R1
+	MOVW	mode+8(FP), R2
+	MOVW	perm+12(FP), R3
+	MOVD	$SYS_openat, R8
+	SVC
+	CMN	$4095, R0
+	BCC	done
+	MOVW	$-1, R0
+done:
+	MOVW	R0, ret+16(FP)
+	RET
+
+TEXT runtime·close(SB),NOSPLIT,$-8-12
+	MOVW	fd+0(FP), R0
+	MOVD	$SYS_close, R8
+	SVC
+	BCC	done
+	MOVW	$-1, R0
+done:
+	MOVW	R0, ret+8(FP)
+	RET
+
+TEXT runtime·write(SB),NOSPLIT,$-8-28
+	MOVD	fd+0(FP), R0
+	MOVD	p+8(FP), R1
+	MOVW	n+16(FP), R2
+	MOVD	$SYS_write, R8
+	SVC
+	BCC	done
+	MOVW	$-1, R0
+done:
+	MOVW	R0, ret+24(FP)
+	RET
+
+TEXT runtime·read(SB),NOSPLIT,$-8-28
+	MOVW	fd+0(FP), R0
+	MOVD	p+8(FP), R1
+	MOVW	n+16(FP), R2
+	MOVD	$SYS_read, R8
+	SVC
+	BCC	done
+	MOVW	$-1, R0
+done:
+	MOVW	R0, ret+24(FP)
+	RET
+
+TEXT runtime·getrlimit(SB),NOSPLIT,$-8-20
+	MOVW	kind+0(FP), R0
+	MOVD	limit+8(FP), R1
+	MOVD	$SYS_getrlimit, R8
+	SVC
+	MOVW	R0, ret+16(FP)
+	RET
+
+TEXT runtime·usleep(SB),NOSPLIT,$16-4
+	MOVWU	usec+0(FP), R3
+	MOVD	R3, R5
+	MOVW	$1000000, R4
+	UDIV	R4, R3
+	MOVD	R3, 8(RSP)
+	MUL	R3, R4
+	SUB	R4, R5
+	MOVW	$1000, R4
+	MUL	R4, R5
+	MOVD	R5, 16(RSP)
+
+	// pselect6(0, 0, 0, 0, &ts, 0)
+	MOVD	$0, R0
+	MOVD	R0, R1
+	MOVD	R0, R2
+	MOVD	R0, R3
+	ADD	$8, RSP, R4
+	MOVD	R0, R5
+	MOVD	$SYS_pselect6, R8
+	SVC
+	RET
+
+TEXT runtime·raise(SB),NOSPLIT,$-8
+	MOVD	$SYS_gettid, R8
+	SVC
+	MOVW	R0, R0	// arg 1 tid
+	MOVW	sig+0(FP), R1	// arg 2
+	MOVD	$SYS_tkill, R8
+	SVC
+	RET
+
+TEXT runtime·setitimer(SB),NOSPLIT,$-8-24
+	MOVW	mode+0(FP), R0
+	MOVD	new+8(FP), R1
+	MOVD	old+16(FP), R2
+	MOVD	$SYS_setitimer, R8
+	SVC
+	RET
+
+TEXT runtime·mincore(SB),NOSPLIT,$-8-28
+	MOVD	addr+0(FP), R0
+	MOVD	n+8(FP), R1
+	MOVD	dst+16(FP), R2
+	MOVD	$SYS_mincore, R8
+	SVC
+	MOVW	R0, ret+24(FP)
+	RET
+
+// func now() (sec int64, nsec int32)
+TEXT time·now(SB),NOSPLIT,$16-12
+	MOVD	RSP, R0
+	MOVD	$0, R1
+	MOVD	$SYS_gettimeofday, R8
+	SVC
+	MOVD	0(RSP), R3	// sec
+	MOVD	8(RSP), R5	// usec
+	MOVD	$1000, R4
+	MUL	R4, R5
+	MOVD	R3, sec+0(FP)
+	MOVW	R5, nsec+8(FP)
+	RET
+
+TEXT runtime·nanotime(SB),NOSPLIT,$16-8
+	MOVW	$1, R0 // CLOCK_MONOTONIC
+	MOVD	RSP, R1
+	MOVD	$SYS_clock_gettime, R8
+	SVC
+	MOVD	0(RSP), R3	// sec
+	MOVD	8(RSP), R5	// nsec
+	// sec is in R3, nsec in R5
+	// return nsec in R3
+	MOVD	$1000000000, R4
+	MUL	R4, R3
+	ADD	R5, R3
+	MOVD	R3, ret+0(FP)
+	RET
+
+TEXT runtime·rtsigprocmask(SB),NOSPLIT,$-8-28
+	MOVW	sig+0(FP), R0
+	MOVD	new+8(FP), R1
+	MOVD	old+16(FP), R2
+	MOVW	size+24(FP), R3
+	MOVD	$SYS_rt_sigprocmask, R8
+	SVC
+	CMN	$4095, R0
+	BCC	done
+	MOVD	$0, R0
+	MOVD	R0, (R0)	// crash
+done:
+	RET
+
+TEXT runtime·rt_sigaction(SB),NOSPLIT,$-8-36
+	MOVD	sig+0(FP), R0
+	MOVD	new+8(FP), R1
+	MOVD	old+16(FP), R2
+	MOVD	size+24(FP), R3
+	MOVD	$SYS_rt_sigaction, R8
+	SVC
+	MOVW	R0, ret+32(FP)
+	RET
+
+TEXT runtime·sigtramp(SB),NOSPLIT,$64
+	// this might be called in external code context,
+	// where g is not set.
+	// first save R0, because runtime·load_g will clobber it
+	MOVW	R0, 8(RSP)
+	// TODO(minux): iscgo & load_g
+
+	// check that g exists
+	CMP	g, ZR
+	BNE	ok
+	MOVD	$runtime·badsignal(SB), R0
+	BL	(R0)
+	RET
+
+ok:
+	// save g
+	MOVD	g, 40(RSP)
+	MOVD	g, R6
+
+	// g = m->gsignal
+	MOVD	g_m(g), R7
+	MOVD	m_gsignal(R7), g
+
+	// R0 is already saved above
+	MOVD	R1, 16(RSP)
+	MOVD	R2, 24(RSP)
+	MOVD	R6, 32(RSP)
+
+	BL	runtime·sighandler(SB)
+
+	// restore g
+	MOVD	40(RSP), g
+	RET
+
+TEXT runtime·mmap(SB),NOSPLIT,$-8
+	MOVD	addr+0(FP), R0
+	MOVD	n+8(FP), R1
+	MOVW	prot+16(FP), R2
+	MOVW	flags+20(FP), R3
+	MOVW	fd+24(FP), R4
+	MOVW	off+28(FP), R5
+
+	MOVD	$SYS_mmap, R8
+	SVC
+	MOVD	R0, ret+32(FP)
+	RET
+
+TEXT runtime·munmap(SB),NOSPLIT,$-8
+	MOVD	addr+0(FP), R0
+	MOVD	n+8(FP), R1
+	MOVD	$SYS_munmap, R8
+	SVC
+	CMN	$4095, R0
+	BCC	cool
+	MOVD	R0, 0xf0(R0)
+cool:
+	RET
+
+TEXT runtime·madvise(SB),NOSPLIT,$-8
+	MOVD	addr+0(FP), R0
+	MOVD	n+8(FP), R1
+	MOVW	flags+16(FP), R2
+	MOVD	$SYS_madvise, R8
+	SVC
+	// ignore failure - maybe pages are locked
+	RET
+
+// int64 futex(int32 *uaddr, int32 op, int32 val,
+//	struct timespec *timeout, int32 *uaddr2, int32 val2);
+TEXT runtime·futex(SB),NOSPLIT,$-8
+	MOVD	addr+0(FP), R0
+	MOVW	op+8(FP), R1
+	MOVW	val+12(FP), R2
+	MOVD	ts+16(FP), R3
+	MOVD	addr2+24(FP), R4
+	MOVW	val3+32(FP), R5
+	MOVD	$SYS_futex, R8
+	SVC
+	MOVW	R0, ret+40(FP)
+	RET
+
+// int64 clone(int32 flags, void *stk, M *mp, G *gp, void (*fn)(void));
+TEXT runtime·clone(SB),NOSPLIT,$-8
+	MOVW	flags+0(FP), R0
+	MOVD	stk+8(FP), R1
+
+	// Copy mp, gp, fn off parent stack for use by child.
+	MOVD	mm+16(FP), R10
+	MOVD	gg+24(FP), R11
+	MOVD	fn+32(FP), R12
+
+	MOVD	R10, -8(R1)
+	MOVD	R11, -16(R1)
+	MOVD	R12, -24(R1)
+	MOVD	$1234, R10
+	MOVD	R10, -32(R1)
+
+	MOVD	$SYS_clone, R8
+	SVC
+
+	// In parent, return.
+	CMP	ZR, R0
+	BEQ	child
+	MOVW	R0, ret+40(FP)
+	RET
+child:
+
+	// In child, on new stack.
+	MOVD	-32(RSP), R10
+	MOVD	$1234, R0
+	CMP	R0, R10
+	BEQ	good
+	MOVD	$0, R0
+	MOVD	R0, (R0)	// crash
+
+	// Initialize m->procid to Linux tid
+good:
+	MOVD	$SYS_gettid, R8
+	SVC
+
+	MOVD	-24(RSP), R12
+	MOVD	-16(RSP), R11
+	MOVD	-8(RSP), R10
+
+	MOVD	R0, m_procid(R10)
+
+	// TODO: setup TLS.
+
+	// In child, set up new stack
+	MOVD	R10, g_m(R11)
+	MOVD	R11, g
+	//CALL	runtime·stackcheck(SB)
+
+	// Call fn
+	MOVD	R12, R0
+	BL	(R0)
+
+	// It shouldn't return.	 If it does, exit
+	MOVW	$111, R0
+again:
+	MOVD	$SYS_exit_group, R8
+	SVC
+	B	again	// keep exiting
+
+TEXT runtime·sigaltstack(SB),NOSPLIT,$-8
+	MOVD	new+0(FP), R0
+	MOVD	old+8(FP), R1
+	MOVD	$SYS_sigaltstack, R8
+	SVC
+	CMN	$4095, R0
+	BCC	ok
+	MOVD	$0, R0
+	MOVD	R0, (R0)	// crash
+ok:
+	RET
+
+TEXT runtime·osyield(SB),NOSPLIT,$-8
+	MOVD	$SYS_sched_yield, R8
+	SVC
+	RET
+
+TEXT runtime·sched_getaffinity(SB),NOSPLIT,$-8
+	MOVD	pid+0(FP), R0
+	MOVD	len+8(FP), R1
+	MOVD	buf+16(FP), R2
+	MOVD	$SYS_sched_getaffinity, R8
+	SVC
+	MOVW	R0, ret+24(FP)
+	RET
+
+// int32 runtime·epollcreate(int32 size);
+TEXT runtime·epollcreate(SB),NOSPLIT,$-8
+	MOVW	$0, R0
+	MOVD	$SYS_epoll_create1, R8
+	SVC
+	MOVW	R0, ret+8(FP)
+	RET
+
+// int32 runtime·epollcreate1(int32 flags);
+TEXT runtime·epollcreate1(SB),NOSPLIT,$-8
+	MOVW	flags+0(FP), R0
+	MOVD	$SYS_epoll_create1, R8
+	SVC
+	MOVW	R0, ret+8(FP)
+	RET
+
+// func epollctl(epfd, op, fd int32, ev *epollEvent) int
+TEXT runtime·epollctl(SB),NOSPLIT,$-8
+	MOVW	epfd+0(FP), R0
+	MOVW	op+4(FP), R1
+	MOVW	fd+8(FP), R2
+	MOVD	ev+16(FP), R3
+	MOVD	$SYS_epoll_ctl, R8
+	SVC
+	MOVW	R0, ret+24(FP)
+	RET
+
+// int32 runtime·epollwait(int32 epfd, EpollEvent *ev, int32 nev, int32 timeout);
+TEXT runtime·epollwait(SB),NOSPLIT,$-8
+	MOVW	epfd+0(FP), R0
+	MOVD	ev+8(FP), R1
+	MOVW	nev+16(FP), R2
+	MOVW	timeout+20(FP), R3
+	MOVD	$0, R4
+	MOVD	$SYS_epoll_pwait, R8
+	SVC
+	MOVW	R0, ret+24(FP)
+	RET
+
+// void runtime·closeonexec(int32 fd);
+TEXT runtime·closeonexec(SB),NOSPLIT,$-8
+	MOVW	fd+0(FP), R0  // fd
+	MOVD	$2, R1	// F_SETFD
+	MOVD	$1, R2	// FD_CLOEXEC
+	MOVD	$SYS_fcntl, R8
+	SVC
+	RET
diff --git a/src/runtime/sys_linux_ppc64x.s b/src/runtime/sys_linux_ppc64x.s
index 1f2a5af..3070893 100644
--- a/src/runtime/sys_linux_ppc64x.s
+++ b/src/runtime/sys_linux_ppc64x.s
@@ -62,12 +62,16 @@
 	MOVW	mode+8(FP), R4
 	MOVW	perm+12(FP), R5
 	SYSCALL	$SYS_open
+	BVC	2(PC)
+	MOVW	$-1, R3
 	MOVW	R3, ret+16(FP)
 	RETURN
 
 TEXT runtime·close(SB),NOSPLIT,$-8-12
 	MOVW	fd+0(FP), R3
 	SYSCALL	$SYS_close
+	BVC	2(PC)
+	MOVW	$-1, R3
 	MOVW	R3, ret+8(FP)
 	RETURN
 
@@ -76,6 +80,8 @@
 	MOVD	p+8(FP), R4
 	MOVW	n+16(FP), R5
 	SYSCALL	$SYS_write
+	BVC	2(PC)
+	MOVW	$-1, R3
 	MOVW	R3, ret+24(FP)
 	RETURN
 
@@ -84,6 +90,8 @@
 	MOVD	p+8(FP), R4
 	MOVW	n+16(FP), R5
 	SYSCALL	$SYS_read
+	BVC	2(PC)
+	MOVW	$-1, R3
 	MOVW	R3, ret+24(FP)
 	RETURN
 
diff --git a/src/runtime/sys_nacl_386.s b/src/runtime/sys_nacl_386.s
index 85c8175..242040d 100644
--- a/src/runtime/sys_nacl_386.s
+++ b/src/runtime/sys_nacl_386.s
@@ -362,3 +362,12 @@
 	// 36(BP) is saved EFLAGS, never to be seen again
 	MOVL	32(BP), BP // saved PC
 	JMP	BP
+
+// func getRandomData([]byte)
+TEXT runtime·getRandomData(SB),NOSPLIT,$8-12
+	MOVL buf+0(FP), AX
+	MOVL AX, 0(SP)
+	MOVL len+4(FP), AX
+	MOVL AX, 4(SP)
+	NACL_SYSCALL(SYS_get_random_bytes)
+	RET
diff --git a/src/runtime/sys_nacl_amd64p32.s b/src/runtime/sys_nacl_amd64p32.s
index 7657482..821610b 100644
--- a/src/runtime/sys_nacl_amd64p32.s
+++ b/src/runtime/sys_nacl_amd64p32.s
@@ -412,6 +412,13 @@
 // cannot do real signal handling yet, because gsignal has not been allocated.
 MOVL $1, DI; NACL_SYSCALL(SYS_exit)
 
+// func getRandomData([]byte)
+TEXT runtime·getRandomData(SB),NOSPLIT,$0-12
+	MOVL buf+0(FP), DI
+	MOVL len+4(FP), SI
+	NACL_SYSCALL(SYS_get_random_bytes)
+	RET
+
 TEXT runtime·nacl_sysinfo(SB),NOSPLIT,$16
 /*
 	MOVL	di+0(FP), DI
diff --git a/src/runtime/sys_nacl_arm.s b/src/runtime/sys_nacl_arm.s
index ded95a8..1bae0b3 100644
--- a/src/runtime/sys_nacl_arm.s
+++ b/src/runtime/sys_nacl_arm.s
@@ -301,6 +301,13 @@
 TEXT runtime·nacl_sysinfo(SB),NOSPLIT,$16
 	RET
 
+// func getRandomData([]byte)
+TEXT runtime·getRandomData(SB),NOSPLIT,$0-12
+	MOVW buf+0(FP), R0
+	MOVW len+4(FP), R1
+	NACL_SYSCALL(SYS_get_random_bytes)
+	RET
+
 TEXT runtime·casp1(SB),NOSPLIT,$0
 	B	runtime·cas(SB)
 
diff --git a/src/runtime/sys_netbsd_386.s b/src/runtime/sys_netbsd_386.s
index 509d6d4..bfa7928 100644
--- a/src/runtime/sys_netbsd_386.s
+++ b/src/runtime/sys_netbsd_386.s
@@ -27,24 +27,32 @@
 TEXT runtime·open(SB),NOSPLIT,$-4
 	MOVL	$5, AX
 	INT	$0x80
+	JAE	2(PC)
+	MOVL	$-1, AX
 	MOVL	AX, ret+12(FP)
 	RET
 
 TEXT runtime·close(SB),NOSPLIT,$-4
 	MOVL	$6, AX
 	INT	$0x80
+	JAE	2(PC)
+	MOVL	$-1, AX
 	MOVL	AX, ret+4(FP)
 	RET
 
 TEXT runtime·read(SB),NOSPLIT,$-4
 	MOVL	$3, AX
 	INT	$0x80
+	JAE	2(PC)
+	MOVL	$-1, AX
 	MOVL	AX, ret+12(FP)
 	RET
 
 TEXT runtime·write(SB),NOSPLIT,$-4
 	MOVL	$4, AX			// sys_write
 	INT	$0x80
+	JAE	2(PC)
+	MOVL	$-1, AX
 	MOVL	AX, ret+12(FP)
 	RET
 
@@ -299,9 +307,9 @@
 	RET
 
 TEXT runtime·settls(SB),NOSPLIT,$16
-	// adjust for ELF: wants to use -8(GS) and -4(GS) for g and m
+	// adjust for ELF: wants to use -4(GS) for g
 	MOVL	base+0(FP), CX
-	ADDL	$8, CX
+	ADDL	$4, CX
 	MOVL	$0, 0(SP)		// syscall gap
 	MOVL	CX, 4(SP)		// arg 1 - ptr
 	MOVL	$317, AX		// sys__lwp_setprivate
diff --git a/src/runtime/sys_netbsd_amd64.s b/src/runtime/sys_netbsd_amd64.s
index 83de911..a138286 100644
--- a/src/runtime/sys_netbsd_amd64.s
+++ b/src/runtime/sys_netbsd_amd64.s
@@ -91,6 +91,8 @@
 	MOVL	perm+12(FP), DX		// arg 3 mode
 	MOVL	$5, AX
 	SYSCALL
+	JCC	2(PC)
+	MOVL	$-1, AX
 	MOVL	AX, ret+16(FP)
 	RET
 
@@ -98,6 +100,8 @@
 	MOVL	fd+0(FP), DI		// arg 1 fd
 	MOVL	$6, AX
 	SYSCALL
+	JCC	2(PC)
+	MOVL	$-1, AX
 	MOVL	AX, ret+8(FP)
 	RET
 
@@ -107,6 +111,8 @@
 	MOVL	n+16(FP), DX		// arg 3 count
 	MOVL	$3, AX
 	SYSCALL
+	JCC	2(PC)
+	MOVL	$-1, AX
 	MOVL	AX, ret+24(FP)
 	RET
 
@@ -116,6 +122,8 @@
 	MOVL	n+16(FP), DX		// arg 3 - nbyte
 	MOVL	$4, AX			// sys_write
 	SYSCALL
+	JCC	2(PC)
+	MOVL	$-1, AX
 	MOVL	AX, ret+24(FP)
 	RET
 
@@ -299,8 +307,8 @@
 
 // set tls base to DI
 TEXT runtime·settls(SB),NOSPLIT,$8
-	// adjust for ELF: wants to use -16(FS) and -8(FS) for g and m
-	ADDQ	$16, DI			// arg 1 - ptr
+	// adjust for ELF: wants to use -8(FS) for g
+	ADDQ	$8, DI			// arg 1 - ptr
 	MOVQ	$317, AX		// sys__lwp_setprivate
 	SYSCALL
 	JCC	2(PC)
diff --git a/src/runtime/sys_netbsd_arm.s b/src/runtime/sys_netbsd_arm.s
index 5628967..b421022 100644
--- a/src/runtime/sys_netbsd_arm.s
+++ b/src/runtime/sys_netbsd_arm.s
@@ -29,12 +29,14 @@
 	MOVW mode+4(FP), R1
 	MOVW perm+8(FP), R2
 	SWI $0xa00005
+	MOVW.CS	$-1, R0
 	MOVW	R0, ret+12(FP)
 	RET
 
 TEXT runtime·close(SB),NOSPLIT,$-8
 	MOVW fd+0(FP), R0
 	SWI $0xa00006
+	MOVW.CS	$-1, R0
 	MOVW	R0, ret+4(FP)
 	RET
 
@@ -43,6 +45,7 @@
 	MOVW p+4(FP), R1
 	MOVW n+8(FP), R2
 	SWI $0xa00003
+	MOVW.CS	$-1, R0
 	MOVW	R0, ret+12(FP)
 	RET
 
@@ -51,6 +54,7 @@
 	MOVW	p+4(FP), R1	// arg 2 - buf
 	MOVW	n+8(FP), R2	// arg 3 - nbyte
 	SWI $0xa00004	// sys_write
+	MOVW.CS	$-1, R0
 	MOVW	R0, ret+12(FP)
 	RET
 
diff --git a/src/runtime/sys_openbsd_386.s b/src/runtime/sys_openbsd_386.s
index 9390757..1087709 100644
--- a/src/runtime/sys_openbsd_386.s
+++ b/src/runtime/sys_openbsd_386.s
@@ -31,24 +31,32 @@
 TEXT runtime·open(SB),NOSPLIT,$-4
 	MOVL	$5, AX
 	INT	$0x80
+	JAE	2(PC)
+	MOVL	$-1, AX
 	MOVL	AX, ret+12(FP)
 	RET
 
 TEXT runtime·close(SB),NOSPLIT,$-4
 	MOVL	$6, AX
 	INT	$0x80
+	JAE	2(PC)
+	MOVL	$-1, AX
 	MOVL	AX, ret+4(FP)
 	RET
 
 TEXT runtime·read(SB),NOSPLIT,$-4
 	MOVL	$3, AX
 	INT	$0x80
+	JAE	2(PC)
+	MOVL	$-1, AX
 	MOVL	AX, ret+12(FP)
 	RET
 
 TEXT runtime·write(SB),NOSPLIT,$-4
 	MOVL	$4, AX			// sys_write
 	INT	$0x80
+	JAE	2(PC)
+	MOVL	$-1, AX
 	MOVL	AX, ret+12(FP)
 	RET
 
@@ -317,9 +325,9 @@
 	RET
 
 TEXT runtime·settls(SB),NOSPLIT,$8
-	// adjust for ELF: wants to use -8(GS) and -4(GS) for g and m
+	// adjust for ELF: wants to use -4(GS) for g
 	MOVL	tlsbase+0(FP), CX
-	ADDL	$8, CX
+	ADDL	$4, CX
 	MOVL	$0, 0(SP)		// syscall gap
 	MOVL	CX, 4(SP)		// arg 1 - tcb
 	MOVL	$329, AX		// sys___set_tcb
diff --git a/src/runtime/sys_openbsd_amd64.s b/src/runtime/sys_openbsd_amd64.s
index f1ee4a9..d05782c 100644
--- a/src/runtime/sys_openbsd_amd64.s
+++ b/src/runtime/sys_openbsd_amd64.s
@@ -101,6 +101,8 @@
 	MOVL	perm+12(FP), DX		// arg 3 mode
 	MOVL	$5, AX
 	SYSCALL
+	JCC	2(PC)
+	MOVL	$-1, AX
 	MOVL	AX, ret+16(FP)
 	RET
 
@@ -108,6 +110,8 @@
 	MOVL	fd+0(FP), DI		// arg 1 fd
 	MOVL	$6, AX
 	SYSCALL
+	JCC	2(PC)
+	MOVL	$-1, AX
 	MOVL	AX, ret+8(FP)
 	RET
 
@@ -117,6 +121,8 @@
 	MOVL	n+16(FP), DX		// arg 3 count
 	MOVL	$3, AX
 	SYSCALL
+	JCC	2(PC)
+	MOVL	$-1, AX
 	MOVL	AX, ret+24(FP)
 	RET
 
@@ -126,6 +132,8 @@
 	MOVL	n+16(FP), DX		// arg 3 - nbyte
 	MOVL	$4, AX			// sys_write
 	SYSCALL
+	JCC	2(PC)
+	MOVL	$-1, AX
 	MOVL	AX, ret+24(FP)
 	RET
 
@@ -290,7 +298,7 @@
 // set tls base to DI
 TEXT runtime·settls(SB),NOSPLIT,$0
 	// adjust for ELF: wants to use -16(FS) and -8(FS) for g and m
-	ADDQ	$16, DI
+	ADDQ	$8, DI
 	MOVQ	$329, AX		// sys___settcb
 	SYSCALL
 	JCC	2(PC)
diff --git a/src/runtime/sys_openbsd_arm.s b/src/runtime/sys_openbsd_arm.s
new file mode 100644
index 0000000..f1be775
--- /dev/null
+++ b/src/runtime/sys_openbsd_arm.s
@@ -0,0 +1,381 @@
+// 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.
+//
+// System calls and other sys.stuff for ARM, OpenBSD
+// /usr/src/sys/kern/syscalls.master for syscall numbers.
+//
+
+#include "go_asm.h"
+#include "go_tls.h"
+#include "textflag.h"
+
+#define CLOCK_REALTIME	$0
+#define	CLOCK_MONOTONIC	$3
+
+// Exit the entire program (like C exit)
+TEXT runtime·exit(SB),NOSPLIT,$-4
+	MOVW	status+0(FP), R0	// arg 1 - status
+	MOVW	$1, R12			// sys_exit
+	SWI	$0
+	MOVW.CS	$0, R8			// crash on syscall failure
+	MOVW.CS	R8, (R8)
+	RET
+
+TEXT runtime·exit1(SB),NOSPLIT,$-4
+	MOVW	$0, R0			// arg 1 - notdead
+	MOVW	$302, R12		// sys___threxit
+	SWI	$0
+	MOVW.CS	$1, R8			// crash on syscall failure
+	MOVW.CS	R8, (R8)
+	RET
+
+TEXT runtime·open(SB),NOSPLIT,$-4
+	MOVW	path+0(FP), R0		// arg 1 - path
+	MOVW	flags+4(FP), R1		// arg 2 - flags
+	MOVW	mode+8(FP), R2		// arg 3 - mode
+	MOVW	$5, R12			// sys_open
+	SWI	$0
+	MOVW.CS	$-1, R0
+	MOVW	R0, ret+12(FP)
+	RET
+
+TEXT runtime·close(SB),NOSPLIT,$-4
+	MOVW	path+0(FP), R0		// arg 1 - path
+	MOVW	$6, R12			// sys_close
+	SWI	$0
+	MOVW.CS	$-1, R0
+	MOVW	R0, ret+4(FP)
+	RET
+
+TEXT runtime·read(SB),NOSPLIT,$-4
+	MOVW	fd+0(FP), R0		// arg 1 - fd
+	MOVW	buf+4(FP), R1		// arg 2 - buf
+	MOVW	nbyte+8(FP), R2		// arg 3 - nbyte
+	MOVW	$3, R12			// sys_read
+	SWI	$0
+	MOVW.CS	$-1, R0
+	MOVW	R0, ret+12(FP)
+	RET
+
+TEXT runtime·write(SB),NOSPLIT,$-4
+	MOVW	fd+0(FP), R0		// arg 1 - fd
+	MOVW	buf+4(FP), R1		// arg 2 - buf
+	MOVW	nbyte+8(FP), R2		// arg 3 - nbyte
+	MOVW	$4, R12			// sys_write
+	SWI	$0
+	MOVW.CS	$-1, R0
+	MOVW	R0, ret+12(FP)
+	RET
+
+TEXT runtime·usleep(SB),NOSPLIT,$16
+	MOVW	usec+0(FP), R0
+	MOVW	R0, R2
+	MOVW	$1000000, R1
+	DIV	R1, R0
+	MOVW	R0, 4(R13)		// tv_sec - l32
+	MOVW	$0, R0
+	MOVW	R0, 8(R13)		// tv_sec - h32
+	MOD	R1, R2
+	MOVW	$1000, R1
+	MUL	R1, R2
+	MOVW	R2, 12(R13)		// tv_nsec
+
+	MOVW	$4(R13), R0		// arg 1 - rqtp
+	MOVW	$0, R1			// arg 2 - rmtp
+	MOVW	$91, R12		// sys_nanosleep
+	SWI	$0
+	RET
+
+TEXT runtime·raise(SB),NOSPLIT,$12
+	MOVW	$0x12B, R12
+	SWI	$0			// sys_getthrid
+					// arg 1 - pid, already in R0
+	MOVW	sig+0(FP), R1		// arg 2 - signum
+	MOVW	$37, R12		// sys_kill
+	SWI	$0
+	RET
+
+TEXT runtime·mmap(SB),NOSPLIT,$16
+	MOVW	addr+0(FP), R0		// arg 1 - addr
+	MOVW	len+4(FP), R1		// arg 2 - len
+	MOVW	prot+8(FP), R2		// arg 3 - prot
+	MOVW	flags+12(FP), R3	// arg 4 - flags
+	MOVW	fd+16(FP), R4		// arg 5 - fd (on stack)
+	MOVW	R4, 4(R13)
+	MOVW	$0, R5			// arg 6 - pad (on stack)
+	MOVW	R5, 8(R13)
+	MOVW	offset+20(FP), R6	// arg 7 - offset (on stack)
+	MOVW	R6, 12(R13)		// lower 32 bits (from Go runtime)
+	MOVW	$0, R7
+	MOVW	R7, 16(R13)		// high 32 bits
+	ADD	$4, R13
+	MOVW	$197, R12		// sys_mmap
+	SWI	$0
+	SUB	$4, R13
+	MOVW	R0, ret+24(FP)
+	RET
+
+TEXT runtime·munmap(SB),NOSPLIT,$0
+	MOVW	addr+0(FP), R0		// arg 1 - addr
+	MOVW	len+4(FP), R1		// arg 2 - len
+	MOVW	$73, R12		// sys_munmap
+	SWI	$0
+	MOVW.CS	$0, R8			// crash on syscall failure
+	MOVW.CS	R8, (R8)
+	RET
+
+TEXT runtime·madvise(SB),NOSPLIT,$0
+	MOVW	addr+0(FP), R0		// arg 1 - addr
+	MOVW	len+4(FP), R1		// arg 2 - len
+	MOVW	behav+8(FP), R2		// arg 2 - behav
+	MOVW	$75, R12		// sys_madvise
+	SWI	$0
+	MOVW.CS	$0, R8			// crash on syscall failure
+	MOVW.CS	R8, (R8)
+	RET
+
+TEXT runtime·setitimer(SB),NOSPLIT,$0
+	MOVW	which+0(FP), R0		// arg 1 - which
+	MOVW	value+4(FP), R1		// arg 2 - value
+	MOVW	ovalue+8(FP), R2	// arg 3 - ovalue
+	MOVW	$69, R12		// sys_setitimer
+	SWI	$0
+	RET
+
+// func now() (sec int64, nsec int32)
+TEXT time·now(SB), NOSPLIT, $32
+	MOVW	CLOCK_REALTIME, R0	// arg 1 - clock_id
+	MOVW	$8(R13), R1		// arg 2 - tp
+	MOVW	$87, R12		// sys_clock_gettime
+	SWI	$0
+
+	MOVW	8(R13), R0		// sec - l32
+	MOVW	12(R13), R1		// sec - h32
+	MOVW	16(R13), R2		// nsec
+
+	MOVW	R0, sec_lo+0(FP)
+	MOVW	R1, sec_hi+4(FP)
+	MOVW	R2, nsec+8(FP)
+
+	RET
+
+// int64 nanotime(void) so really
+// void nanotime(int64 *nsec)
+TEXT runtime·nanotime(SB),NOSPLIT,$32
+	MOVW	CLOCK_MONOTONIC, R0	// arg 1 - clock_id
+	MOVW	$8(R13), R1		// arg 2 - tp
+	MOVW	$87, R12		// sys_clock_gettime
+	SWI	$0
+
+	MOVW	8(R13), R0		// sec - l32
+	MOVW	12(R13), R4		// sec - h32
+	MOVW	16(R13), R2		// nsec
+
+	MOVW	$1000000000, R3
+	MULLU	R0, R3, (R1, R0)
+	MUL	R3, R4
+	ADD.S	R2, R0
+	ADC	R4, R1
+
+	MOVW	R0, ret_lo+0(FP)
+	MOVW	R1, ret_hi+4(FP)
+	RET
+
+TEXT runtime·sigaction(SB),NOSPLIT,$0
+	MOVW	signum+0(FP), R0	// arg 1 - signum
+	MOVW	nsa+4(FP), R1		// arg 2 - nsa
+	MOVW	osa+8(FP), R2		// arg 3 - osa
+	MOVW	$46, R12		// sys_sigaction
+	SWI	$0
+	MOVW.CS	$3, R8			// crash on syscall failure
+	MOVW.CS	R8, (R8)
+	RET
+
+TEXT runtime·sigprocmask(SB),NOSPLIT,$0
+	MOVW	how+0(FP), R0		// arg 1 - how
+	MOVW	mask+4(FP), R1		// arg 2 - mask
+	MOVW	$48, R12		// sys_sigprocmask
+	SWI	$0
+	MOVW.CS	$3, R8			// crash on syscall failure
+	MOVW.CS	R8, (R8)
+	MOVW	R0, ret+8(FP)
+	RET
+
+TEXT runtime·sigtramp(SB),NOSPLIT,$24
+	// If called from an external code context, g will not be set.
+	// Save R0, since runtime·load_g will clobber it.
+	MOVW	R0, 4(R13)		// signum
+	MOVB	runtime·iscgo(SB), R0
+	CMP	$0, R0
+	BL.NE	runtime·load_g(SB)
+
+	CMP	$0, g
+	BNE	4(PC)
+	// Signal number saved in 4(R13).
+	MOVW	runtime·badsignal(SB), R11
+	BL	(R11)
+	RET
+
+	// Save g.
+	MOVW	g, R3
+	MOVW	g, 20(R13)
+
+	// g = m->signal
+	MOVW	g_m(g), R8
+	MOVW	m_gsignal(R8), g
+
+	// R0 already saved.
+	MOVW	R1, 8(R13)		// info
+	MOVW	R2, 12(R13)		// context
+	MOVW	R3, 16(R13)		// gp (original g)
+
+	BL	runtime·sighandler(SB)
+
+	// Restore g.
+	MOVW	20(R13), g
+	RET
+
+// int32 tfork(void *param, uintptr psize, M *mp, G *gp, void (*fn)(void));
+TEXT runtime·tfork(SB),NOSPLIT,$0
+
+	// Copy mp, gp and fn off parent stack for use by child.
+	MOVW	mm+8(FP), R4
+	MOVW	gg+12(FP), R5
+	MOVW	fn+16(FP), R6
+
+	MOVW	param+0(FP), R0		// arg 1 - param
+	MOVW	psize+4(FP), R1		// arg 2 - psize
+	MOVW	$8, R12			// sys___tfork
+	SWI	$0
+
+	// Return if syscall failed.
+	B.CC	4(PC)
+	RSB	$0, R0
+	MOVW	R0, ret+20(FP)
+	RET
+
+	// In parent, return.
+	CMP	$0, R0
+	BEQ	3(PC)
+	MOVW	R0, ret+20(FP)
+	RET
+
+	// Initialise m, g.
+	MOVW	R5, g
+	MOVW	R4, g_m(g)
+
+	// Paranoia; check that stack splitting code works.
+	BL	runtime·emptyfunc(SB)
+
+	// Call fn.
+	BL	(R6)
+
+	BL	runtime·exit1(SB)
+	MOVW	$2, R8			// crash if reached
+	MOVW	R8, (R8)
+	RET
+
+TEXT runtime·sigaltstack(SB),NOSPLIT,$0
+	MOVW	nss+0(FP), R0		// arg 1 - nss
+	MOVW	oss+4(FP), R1		// arg 2 - oss
+	MOVW	$288, R12		// sys_sigaltstack
+	SWI	$0
+	MOVW.CS	$0, R8			// crash on syscall failure
+	MOVW.CS	R8, (R8)
+	RET
+
+TEXT runtime·osyield(SB),NOSPLIT,$0
+	MOVW	$298, R12		// sys_sched_yield
+	SWI	$0
+	RET
+
+TEXT runtime·thrsleep(SB),NOSPLIT,$4
+	MOVW	ident+0(FP), R0		// arg 1 - ident
+	MOVW	clock_id+4(FP), R1	// arg 2 - clock_id
+	MOVW	tp+8(FP), R2		// arg 3 - tp
+	MOVW	lock+12(FP), R3		// arg 4 - lock
+	MOVW	abort+16(FP), R4	// arg 5 - abort (on stack)
+	MOVW	R4, 4(R13)
+	ADD	$4, R13
+	MOVW	$94, R12		// sys___thrsleep
+	SWI	$0
+	SUB	$4, R13
+	MOVW	R0, ret+20(FP)
+	RET
+
+TEXT runtime·thrwakeup(SB),NOSPLIT,$0
+	MOVW	ident+0(FP), R0		// arg 1 - ident
+	MOVW	n+4(FP), R1		// arg 2 - n
+	MOVW	$301, R12		// sys___thrwakeup
+	SWI	$0
+	MOVW	R0, ret+8(FP)
+	RET
+
+TEXT runtime·sysctl(SB),NOSPLIT,$8
+	MOVW	name+0(FP), R0		// arg 1 - name
+	MOVW	namelen+4(FP), R1	// arg 2 - namelen
+	MOVW	oldp+8(FP), R2		// arg 3 - oldp
+	MOVW	oldlenp+12(FP), R3	// arg 4 - oldlenp
+	MOVW	newp+16(FP), R4		// arg 5 - newp (on stack)
+	MOVW	R4, 4(R13)
+	MOVW	newlen+20(FP), R5	// arg 6 - newlen (on stack)
+	MOVW	R5, 8(R13)
+	ADD	$4, R13
+	MOVW	$202, R12		// sys___sysctl
+	SWI	$0
+	SUB	$4, R13
+	MOVW.CC	$0, R0
+	RSB.CS	$0, R0
+	MOVW	R0, ret+24(FP)
+	RET
+
+// int32 runtime·kqueue(void);
+TEXT runtime·kqueue(SB),NOSPLIT,$0
+	MOVW	$269, R12		// sys_kqueue
+	SWI	$0
+	RSB.CS	$0, R0
+	MOVW	R0, ret+0(FP)
+	RET
+
+// int32 runtime·kevent(int kq, Kevent *changelist, int nchanges, Kevent *eventlist, int nevents, Timespec *timeout);
+TEXT runtime·kevent(SB),NOSPLIT,$8
+	MOVW	fd+0(FP), R0		// arg 1 - fd
+	MOVW	changelist+4(FP), R1	// arg 2 - changelist
+	MOVW	nchanges+8(FP), R2	// arg 3 - nchanges
+	MOVW	eventlist+12(FP), R3	// arg 4 - eventlist
+	MOVW	nevents+16(FP), R4	// arg 5 - nevents (on stack)
+	MOVW	R4, 4(R13)
+	MOVW	timeout+20(FP), R5	// arg 6 - timeout (on stack)
+	MOVW	R5, 8(R13)
+	ADD	$4, R13
+	MOVW	$72, R12		// sys_kevent
+	SWI	$0
+	RSB.CS	$0, R0
+	SUB	$4, R13
+	MOVW	R0, ret+24(FP)
+	RET
+
+// int32 runtime·closeonexec(int32 fd);
+TEXT runtime·closeonexec(SB),NOSPLIT,$0
+	MOVW	fd+0(FP), R0		// arg 1 - fd
+	MOVW	$2, R1			// arg 2 - cmd (F_SETFD)
+	MOVW	$1, R2			// arg 3 - arg (FD_CLOEXEC)
+	MOVW	$92, R12		// sys_fcntl
+	SWI	$0
+	RSB.CS	$0, R0
+	MOVW	R0, ret+4(FP)
+	RET
+
+TEXT runtime·casp1(SB),NOSPLIT,$0
+	//B	runtime·armcas(SB)
+	B	runtime·cas(SB)
+
+TEXT runtime·cas(SB),NOSPLIT,$0
+	B	runtime·armcas(SB)
+
+// TODO(jsing): Implement.
+TEXT runtime·read_tls_fallback(SB),NOSPLIT,$-4
+	MOVW	$5, R0
+	MOVW	R0, (R0)
+	RET
diff --git a/src/runtime/syscall2_solaris.go b/src/runtime/syscall2_solaris.go
index cbf2a95..df72996 100644
--- a/src/runtime/syscall2_solaris.go
+++ b/src/runtime/syscall2_solaris.go
@@ -15,13 +15,14 @@
 //go:cgo_import_dynamic libc_execve execve "libc.so"
 //go:cgo_import_dynamic libc_fcntl fcntl "libc.so"
 //go:cgo_import_dynamic libc_gethostname gethostname "libc.so"
+//go:cgo_import_dynamic libc_getpid getpid "libc.so"
 //go:cgo_import_dynamic libc_ioctl ioctl "libc.so"
 //go:cgo_import_dynamic libc_pipe pipe "libc.so"
 //go:cgo_import_dynamic libc_setgid setgid "libc.so"
 //go:cgo_import_dynamic libc_setgroups setgroups "libc.so"
 //go:cgo_import_dynamic libc_setsid setsid "libc.so"
 //go:cgo_import_dynamic libc_setuid setuid "libc.so"
-//go:cgo_import_dynamic libc_setpgid setsid "libc.so"
+//go:cgo_import_dynamic libc_setpgid setpgid "libc.so"
 //go:cgo_import_dynamic libc_syscall syscall "libc.so"
 //go:cgo_import_dynamic libc_forkx forkx "libc.so"
 //go:cgo_import_dynamic libc_wait4 wait4 "libc.so"
@@ -35,6 +36,7 @@
 //go:linkname libc_execve libc_execve
 //go:linkname libc_fcntl libc_fcntl
 //go:linkname libc_gethostname libc_gethostname
+//go:linkname libc_getpid libc_getpid
 //go:linkname libc_ioctl libc_ioctl
 //go:linkname libc_pipe libc_pipe
 //go:linkname libc_setgid libc_setgid
diff --git a/src/runtime/syscall_nacl.h b/src/runtime/syscall_nacl.h
index b33852e..834ecfc 100644
--- a/src/runtime/syscall_nacl.h
+++ b/src/runtime/syscall_nacl.h
@@ -8,10 +8,10 @@
 #define SYS_read 12
 #define SYS_write 13
 #define SYS_lseek 14
-#define SYS_ioctl 15
 #define SYS_stat 16
 #define SYS_fstat 17
 #define SYS_chmod 18
+#define SYS_isatty 19
 #define SYS_brk 20
 #define SYS_mmap 21
 #define SYS_munmap 22
@@ -69,3 +69,16 @@
 #define SYS_test_crash 110
 #define SYS_test_syscall_1 111
 #define SYS_test_syscall_2 112
+#define SYS_futex_wait_abs 120
+#define SYS_futex_wake 121
+#define SYS_pread 130
+#define SYS_pwrite 131
+#define SYS_truncate 140
+#define SYS_lstat 141
+#define SYS_link 142
+#define SYS_rename 143
+#define SYS_symlink 144
+#define SYS_access 145
+#define SYS_readlink 146
+#define SYS_utimes 147
+#define SYS_get_random_bytes 150
diff --git a/src/runtime/syscall_solaris.go b/src/runtime/syscall_solaris.go
index 9b99716..440421d 100644
--- a/src/runtime/syscall_solaris.go
+++ b/src/runtime/syscall_solaris.go
@@ -16,6 +16,7 @@
 	libc_fcntl,
 	libc_forkx,
 	libc_gethostname,
+	libc_getpid,
 	libc_ioctl,
 	libc_pipe,
 	libc_setgid,
@@ -184,6 +185,17 @@
 }
 
 //go:nosplit
+func syscall_getpid() (pid, err uintptr) {
+	call := libcall{
+		fn:   uintptr(unsafe.Pointer(libc_getpid)),
+		n:    0,
+		args: uintptr(unsafe.Pointer(libc_getpid)), // it's unused but must be non-nil, otherwise crashes
+	}
+	asmcgocall(unsafe.Pointer(&asmsysvicall6), unsafe.Pointer(&call))
+	return call.r1, call.err
+}
+
+//go:nosplit
 func syscall_ioctl(fd, req, arg uintptr) (err uintptr) {
 	call := libcall{
 		fn:   uintptr(unsafe.Pointer(libc_ioctl)),
diff --git a/src/runtime/syscall_windows_test.go b/src/runtime/syscall_windows_test.go
index c40641a..720f70b 100644
--- a/src/runtime/syscall_windows_test.go
+++ b/src/runtime/syscall_windows_test.go
@@ -436,6 +436,9 @@
 }
 
 func TestStdcallAndCDeclCallbacks(t *testing.T) {
+	if _, err := exec.LookPath("gcc"); err != nil {
+		t.Skip("skipping test: gcc is missing")
+	}
 	tmp, err := ioutil.TempDir("", "TestCDeclCallback")
 	if err != nil {
 		t.Fatal("TempDir failed: ", err)
diff --git a/src/runtime/time.go b/src/runtime/time.go
index 6a2cc21..ffe7590 100644
--- a/src/runtime/time.go
+++ b/src/runtime/time.go
@@ -56,7 +56,7 @@
 	t.arg = getg()
 	lock(&timers.lock)
 	addtimerLocked(t)
-	goparkunlock(&timers.lock, "sleep", traceEvGoSleep)
+	goparkunlock(&timers.lock, "sleep", traceEvGoSleep, 2)
 }
 
 // startTimer adds t to the timer heap.
@@ -79,7 +79,7 @@
 
 // Ready the goroutine arg.
 func goroutineReady(arg interface{}, seq uintptr) {
-	goready(arg.(*g))
+	goready(arg.(*g), 0)
 }
 
 func addtimer(t *timer) {
@@ -108,7 +108,7 @@
 		}
 		if timers.rescheduling {
 			timers.rescheduling = false
-			goready(timers.gp)
+			goready(timers.gp, 0)
 		}
 	}
 	if !timers.created {
@@ -199,7 +199,7 @@
 		if delta < 0 || faketime > 0 {
 			// No timers left - put goroutine to sleep.
 			timers.rescheduling = true
-			goparkunlock(&timers.lock, "timer goroutine (idle)", traceEvGoBlock)
+			goparkunlock(&timers.lock, "timer goroutine (idle)", traceEvGoBlock, 1)
 			continue
 		}
 		// At least one timer pending.  Sleep until then.
diff --git a/src/runtime/trace.go b/src/runtime/trace.go
index 3a4421b..7c4d8d3 100644
--- a/src/runtime/trace.go
+++ b/src/runtime/trace.go
@@ -21,7 +21,7 @@
 	traceEvFrequency      = 2  // contains tracer timer frequency [frequency (ticks per second)]
 	traceEvStack          = 3  // stack [stack id, number of PCs, array of PCs]
 	traceEvGomaxprocs     = 4  // current value of GOMAXPROCS [timestamp, GOMAXPROCS, stack id]
-	traceEvProcStart      = 5  // start of P [timestamp]
+	traceEvProcStart      = 5  // start of P [timestamp, thread id]
 	traceEvProcStop       = 6  // stop of P [timestamp]
 	traceEvGCStart        = 7  // GC start [timestamp, stack id]
 	traceEvGCDone         = 8  // GC done [timestamp]
@@ -46,13 +46,14 @@
 	traceEvGoBlockNet     = 27 // goroutine blocks on network [timestamp, stack]
 	traceEvGoSysCall      = 28 // syscall enter [timestamp, stack]
 	traceEvGoSysExit      = 29 // syscall exit [timestamp, goroutine id]
-	traceEvGoSysBlock     = 30 // syscall blocks [timestamp, stack]
+	traceEvGoSysBlock     = 30 // syscall blocks [timestamp]
 	traceEvGoWaiting      = 31 // denotes that goroutine is blocked when tracing starts [goroutine id]
 	traceEvGoInSyscall    = 32 // denotes that goroutine is in syscall when tracing starts [goroutine id]
 	traceEvHeapAlloc      = 33 // memstats.heap_alloc change [timestamp, heap_alloc]
 	traceEvNextGC         = 34 // memstats.next_gc change [timestamp, next_gc]
 	traceEvTimerGoroutine = 35 // denotes timer goroutine [timer goroutine id]
-	traceEvCount          = 36
+	traceEvFutileWakeup   = 36 // denotes that the previous wakeup of this goroutine was futile [timestamp]
+	traceEvCount          = 37
 )
 
 const (
@@ -71,6 +72,13 @@
 	traceBytesPerNumber = 10
 	// Shift of the number of arguments in the first event byte.
 	traceArgCountShift = 6
+	// Flag passed to traceGoPark to denote that the previous wakeup of this
+	// goroutine was futile. For example, a goroutine was unblocked on a mutex,
+	// but another goroutine got ahead and acquired the mutex before the first
+	// goroutine is scheduled, so the first goroutine has to block again.
+	// Such wakeups happen on buffered channels and sync.Mutex,
+	// but are generally not interesting for end user.
+	traceFutileWakeup byte = 128
 )
 
 // trace is global tracing context.
@@ -151,10 +159,10 @@
 			traceGoCreate(gp, gp.startpc)
 		}
 		if status == _Gwaiting {
-			traceEvent(traceEvGoWaiting, false, uint64(gp.goid))
+			traceEvent(traceEvGoWaiting, -1, uint64(gp.goid))
 		}
 		if status == _Gsyscall {
-			traceEvent(traceEvGoInSyscall, false, uint64(gp.goid))
+			traceEvent(traceEvGoInSyscall, -1, uint64(gp.goid))
 		}
 	}
 	traceProcStart()
@@ -302,7 +310,7 @@
 	// Wait for new data.
 	if trace.fullHead == nil && !trace.shutdown {
 		trace.reader = getg()
-		goparkunlock(&trace.lock, "trace reader (blocked)", traceEvGoBlock)
+		goparkunlock(&trace.lock, "trace reader (blocked)", traceEvGoBlock, 2)
 		lock(&trace.lock)
 	}
 	// Write a buffer.
@@ -405,8 +413,10 @@
 
 // traceEvent writes a single event to trace buffer, flushing the buffer if necessary.
 // ev is event type.
-// If stack, write current stack id as the last argument.
-func traceEvent(ev byte, stack bool, args ...uint64) {
+// If skip > 0, write current stack id as the last argument (skipping skip top frames).
+// If skip = 0, this event type should contain a stack, but we don't want
+// to collect and remember it for this particular call.
+func traceEvent(ev byte, skip int, args ...uint64) {
 	mp, pid, bufp := traceAcquireBuffer()
 	// Double-check trace.enabled now that we've done m.locks++ and acquired bufLock.
 	// This protects from races between traceEvent and StartTrace/StopTrace.
@@ -440,7 +450,7 @@
 	}
 	buf.lastTicks = ticks
 	narg := byte(len(args))
-	if stack {
+	if skip >= 0 {
 		narg++
 	}
 	// We have only 2 bits for number of arguments.
@@ -460,17 +470,23 @@
 	for _, a := range args {
 		data = traceAppend(data, a)
 	}
-	if stack {
+	if skip == 0 {
+		data = append(data, 0)
+	} else if skip > 0 {
 		_g_ := getg()
 		gp := mp.curg
-		if gp == nil && ev == traceEvGoSysBlock {
-			gp = _g_
-		}
 		var nstk int
 		if gp == _g_ {
-			nstk = callers(1, buf.stk[:])
+			nstk = callers(skip, buf.stk[:])
 		} else if gp != nil {
-			nstk = gcallers(mp.curg, 1, buf.stk[:])
+			gp = mp.curg
+			nstk = gcallers(gp, skip, buf.stk[:])
+		}
+		if nstk > 0 {
+			nstk-- // skip runtime.goexit
+		}
+		if nstk > 0 && gp.goid == 1 {
+			nstk-- // skip runtime.main
 		}
 		id := trace.stackTab.put(buf.stk[:nstk])
 		data = traceAppend(data, uint64(id))
@@ -704,11 +720,11 @@
 // The following functions write specific events to trace.
 
 func traceGomaxprocs(procs int32) {
-	traceEvent(traceEvGomaxprocs, true, uint64(procs))
+	traceEvent(traceEvGomaxprocs, 1, uint64(procs))
 }
 
 func traceProcStart() {
-	traceEvent(traceEvProcStart, false)
+	traceEvent(traceEvProcStart, -1, uint64(getg().m.id))
 }
 
 func traceProcStop(pp *p) {
@@ -717,73 +733,72 @@
 	mp := acquirem()
 	oldp := mp.p
 	mp.p = pp
-	traceEvent(traceEvProcStop, false)
+	traceEvent(traceEvProcStop, -1)
 	mp.p = oldp
 	releasem(mp)
 }
 
 func traceGCStart() {
-	traceEvent(traceEvGCStart, true)
+	traceEvent(traceEvGCStart, 4)
 }
 
 func traceGCDone() {
-	traceEvent(traceEvGCDone, false)
+	traceEvent(traceEvGCDone, -1)
 }
 
 func traceGCScanStart() {
-	traceEvent(traceEvGCScanStart, false)
+	traceEvent(traceEvGCScanStart, -1)
 }
 
 func traceGCScanDone() {
-	traceEvent(traceEvGCScanDone, false)
+	traceEvent(traceEvGCScanDone, -1)
 }
 
 func traceGCSweepStart() {
-	traceEvent(traceEvGCSweepStart, true)
+	traceEvent(traceEvGCSweepStart, 1)
 }
 
 func traceGCSweepDone() {
-	traceEvent(traceEvGCSweepDone, false)
+	traceEvent(traceEvGCSweepDone, -1)
 }
 
 func traceGoCreate(newg *g, pc uintptr) {
-	traceEvent(traceEvGoCreate, true, uint64(newg.goid), uint64(pc))
+	traceEvent(traceEvGoCreate, 2, uint64(newg.goid), uint64(pc))
 }
 
 func traceGoStart() {
-	traceEvent(traceEvGoStart, false, uint64(getg().m.curg.goid))
+	traceEvent(traceEvGoStart, -1, uint64(getg().m.curg.goid))
 }
 
 func traceGoEnd() {
-	traceEvent(traceEvGoEnd, false)
+	traceEvent(traceEvGoEnd, -1)
 }
 
 func traceGoSched() {
-	traceEvent(traceEvGoSched, true)
+	traceEvent(traceEvGoSched, 1)
 }
 
 func traceGoPreempt() {
-	traceEvent(traceEvGoPreempt, true)
+	traceEvent(traceEvGoPreempt, 1)
 }
 
-func traceGoStop() {
-	traceEvent(traceEvGoStop, true)
+func traceGoPark(traceEv byte, skip int, gp *g) {
+	if traceEv&traceFutileWakeup != 0 {
+		traceEvent(traceEvFutileWakeup, -1)
+	}
+	traceEvent(traceEv & ^traceFutileWakeup, skip)
 }
 
-func traceGoPark(traceEv byte, gp *g) {
-	traceEvent(traceEv, true)
-}
-
-func traceGoUnpark(gp *g) {
-	traceEvent(traceEvGoUnblock, true, uint64(gp.goid))
+func traceGoUnpark(gp *g, skip int) {
+	traceEvent(traceEvGoUnblock, skip, uint64(gp.goid))
 }
 
 func traceGoSysCall() {
-	traceEvent(traceEvGoSysCall, true)
+	traceEvent(traceEvGoSysCall, 4)
 }
 
 func traceGoSysExit() {
-	traceEvent(traceEvGoSysExit, false, uint64(getg().m.curg.goid))
+	traceEvent(traceEvGoSysExit, -1, uint64(getg().m.curg.goid))
 }
 
 func traceGoSysBlock(pp *p) {
@@ -792,15 +807,15 @@
 	mp := acquirem()
 	oldp := mp.p
 	mp.p = pp
-	traceEvent(traceEvGoSysBlock, true)
+	traceEvent(traceEvGoSysBlock, -1)
 	mp.p = oldp
 	releasem(mp)
 }
 
 func traceHeapAlloc() {
-	traceEvent(traceEvHeapAlloc, false, memstats.heap_alloc)
+	traceEvent(traceEvHeapAlloc, -1, memstats.heap_alloc)
 }
 
 func traceNextGC() {
-	traceEvent(traceEvNextGC, false, memstats.next_gc)
+	traceEvent(traceEvNextGC, -1, memstats.next_gc)
 }
diff --git a/src/runtime/traceback.go b/src/runtime/traceback.go
index 92dddfd..b6f4374 100644
--- a/src/runtime/traceback.go
+++ b/src/runtime/traceback.go
@@ -357,11 +357,15 @@
 		if usesLR && waspanic {
 			x := *(*uintptr)(unsafe.Pointer(frame.sp))
 			frame.sp += ptrSize
+			if GOARCH == "arm64" {
+				// arm64 needs 16-byte aligned SP, always
+				frame.sp += ptrSize
+			}
 			f = findfunc(frame.pc)
 			frame.fn = f
 			if f == nil {
 				frame.pc = x
-			} else if f.frame == 0 {
+			} else if funcspdelta(f, frame.pc) == 0 {
 				frame.lr = x
 			}
 		}
@@ -642,7 +646,7 @@
 		externalthreadhandlerp != 0 && pc == externalthreadhandlerp
 }
 
-// isSystemGoroutine returns true if the goroutine g must be omitted in
+// isSystemGoroutine reports whether the goroutine g must be omitted in
 // stack dumps and deadlock detector.
 func isSystemGoroutine(gp *g) bool {
 	pc := gp.startpc
diff --git a/src/runtime/type.go b/src/runtime/type.go
index 64d7c30..70ed24c 100644
--- a/src/runtime/type.go
+++ b/src/runtime/type.go
@@ -8,7 +8,7 @@
 
 import "unsafe"
 
-// Needs to be in sync with ../../cmd/ld/decodesym.c:/^commonsize and pkg/reflect/type.go:/type.
+// Needs to be in sync with ../../cmd/internal/ld/decodesym.go:/^commonsize and pkg/reflect/type.go:/type.
 type _type struct {
 	size       uintptr
 	hash       uint32
diff --git a/src/runtime/typekind.h b/src/runtime/typekind.h
deleted file mode 100644
index 39cd45c..0000000
--- a/src/runtime/typekind.h
+++ /dev/null
@@ -1,40 +0,0 @@
-// Copyright 2012 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.
-
-// Must match runtime and reflect.
-// Included by cmd/gc.
-
-enum {
-	KindBool = 1,
-	KindInt,
-	KindInt8,
-	KindInt16,
-	KindInt32,
-	KindInt64,
-	KindUint,
-	KindUint8,
-	KindUint16,
-	KindUint32,
-	KindUint64,
-	KindUintptr,
-	KindFloat32,
-	KindFloat64,
-	KindComplex64,
-	KindComplex128,
-	KindArray,
-	KindChan,
-	KindFunc,
-	KindInterface,
-	KindMap,
-	KindPtr,
-	KindSlice,
-	KindString,
-	KindStruct,
-	KindUnsafePointer,
-
-	KindDirectIface = 1 << 5,
-	KindGCProg      = 1 << 6, // Type.gc points to GC program
-	KindNoPointers  = 1 << 7,
-	KindMask        = (1 << 5) - 1,
-};
diff --git a/src/runtime/unaligned1.go b/src/runtime/unaligned1.go
index 0a88ff2..d3d6c70 100644
--- a/src/runtime/unaligned1.go
+++ b/src/runtime/unaligned1.go
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// +build 386 amd64 amd64p32
+// +build 386 amd64 amd64p32 arm64
 
 package runtime
 
diff --git a/src/runtime/zgoarch_386.go b/src/runtime/zgoarch_386.go
index 8aa3da9..79053f1 100644
--- a/src/runtime/zgoarch_386.go
+++ b/src/runtime/zgoarch_386.go
@@ -8,5 +8,6 @@
 const goarch_amd64 = 0
 const goarch_amd64p32 = 0
 const goarch_arm = 0
+const goarch_arm64 = 0
 const goarch_ppc64 = 0
 const goarch_ppc64le = 0
diff --git a/src/runtime/zgoarch_amd64.go b/src/runtime/zgoarch_amd64.go
index eb4f31d..70095f5 100644
--- a/src/runtime/zgoarch_amd64.go
+++ b/src/runtime/zgoarch_amd64.go
@@ -8,5 +8,6 @@
 const goarch_amd64 = 1
 const goarch_amd64p32 = 0
 const goarch_arm = 0
+const goarch_arm64 = 0
 const goarch_ppc64 = 0
 const goarch_ppc64le = 0
diff --git a/src/runtime/zgoarch_amd64p32.go b/src/runtime/zgoarch_amd64p32.go
index c2579e2..9ac3f0b 100644
--- a/src/runtime/zgoarch_amd64p32.go
+++ b/src/runtime/zgoarch_amd64p32.go
@@ -8,5 +8,6 @@
 const goarch_amd64 = 0
 const goarch_amd64p32 = 1
 const goarch_arm = 0
+const goarch_arm64 = 0
 const goarch_ppc64 = 0
 const goarch_ppc64le = 0
diff --git a/src/runtime/zgoarch_arm.go b/src/runtime/zgoarch_arm.go
index 3098bed..c865dc0 100644
--- a/src/runtime/zgoarch_arm.go
+++ b/src/runtime/zgoarch_arm.go
@@ -8,5 +8,6 @@
 const goarch_amd64 = 0
 const goarch_amd64p32 = 0
 const goarch_arm = 1
+const goarch_arm64 = 0
 const goarch_ppc64 = 0
 const goarch_ppc64le = 0
diff --git a/src/runtime/zgoarch_arm64.go b/src/runtime/zgoarch_arm64.go
new file mode 100644
index 0000000..cde5e9f
--- /dev/null
+++ b/src/runtime/zgoarch_arm64.go
@@ -0,0 +1,13 @@
+// generated by gengoos.go using 'go generate'
+
+package runtime
+
+const theGoarch = `arm64`
+
+const goarch_386 = 0
+const goarch_amd64 = 0
+const goarch_amd64p32 = 0
+const goarch_arm = 0
+const goarch_arm64 = 1
+const goarch_ppc64 = 0
+const goarch_ppc64le = 0
diff --git a/src/runtime/zgoarch_ppc64.go b/src/runtime/zgoarch_ppc64.go
index 3097322..13d87d9 100644
--- a/src/runtime/zgoarch_ppc64.go
+++ b/src/runtime/zgoarch_ppc64.go
@@ -8,5 +8,6 @@
 const goarch_amd64 = 0
 const goarch_amd64p32 = 0
 const goarch_arm = 0
+const goarch_arm64 = 0
 const goarch_ppc64 = 1
 const goarch_ppc64le = 0
diff --git a/src/runtime/zgoarch_ppc64le.go b/src/runtime/zgoarch_ppc64le.go
index f4102ac..5d088aa 100644
--- a/src/runtime/zgoarch_ppc64le.go
+++ b/src/runtime/zgoarch_ppc64le.go
@@ -8,5 +8,6 @@
 const goarch_amd64 = 0
 const goarch_amd64p32 = 0
 const goarch_arm = 0
+const goarch_arm64 = 0
 const goarch_ppc64 = 0
 const goarch_ppc64le = 1
diff --git a/src/strconv/extfloat.go b/src/strconv/extfloat.go
index bed8b16..019b4ee 100644
--- a/src/strconv/extfloat.go
+++ b/src/strconv/extfloat.go
@@ -256,7 +256,7 @@
 }
 
 // AssignDecimal sets f to an approximate value mantissa*10^exp. It
-// returns true if the value represented by f is guaranteed to be the
+// reports whether the value represented by f is guaranteed to be the
 // best approximation of d after being rounded to a float64 or
 // float32 depending on flt.
 func (f *extFloat) AssignDecimal(mantissa uint64, exp10 int, neg bool, trunc bool, flt *floatInfo) (ok bool) {
diff --git a/src/strconv/ftoa.go b/src/strconv/ftoa.go
index f885d96..d59c78e 100644
--- a/src/strconv/ftoa.go
+++ b/src/strconv/ftoa.go
@@ -47,7 +47,7 @@
 
 // AppendFloat appends the string form of the floating-point number f,
 // as generated by FormatFloat, to dst and returns the extended buffer.
-func AppendFloat(dst []byte, f float64, fmt byte, prec int, bitSize int) []byte {
+func AppendFloat(dst []byte, f float64, fmt byte, prec, bitSize int) []byte {
 	return genericFtoa(dst, f, fmt, prec, bitSize)
 }
 
@@ -418,39 +418,27 @@
 	return dst
 }
 
-// %b: -ddddddddp+ddd
+// %b: -ddddddddp±ddd
 func fmtB(dst []byte, neg bool, mant uint64, exp int, flt *floatInfo) []byte {
-	var buf [50]byte
-	w := len(buf)
-	exp -= int(flt.mantbits)
-	esign := byte('+')
-	if exp < 0 {
-		esign = '-'
-		exp = -exp
-	}
-	n := 0
-	for exp > 0 || n < 1 {
-		n++
-		w--
-		buf[w] = byte(exp%10 + '0')
-		exp /= 10
-	}
-	w--
-	buf[w] = esign
-	w--
-	buf[w] = 'p'
-	n = 0
-	for mant > 0 || n < 1 {
-		n++
-		w--
-		buf[w] = byte(mant%10 + '0')
-		mant /= 10
-	}
+	// sign
 	if neg {
-		w--
-		buf[w] = '-'
+		dst = append(dst, '-')
 	}
-	return append(dst, buf[w:]...)
+
+	// mantissa
+	dst, _ = formatBits(dst, mant, 10, false, true)
+
+	// p
+	dst = append(dst, 'p')
+
+	// ±exponent
+	exp -= int(flt.mantbits)
+	if exp >= 0 {
+		dst = append(dst, '+')
+	}
+	dst, _ = formatBits(dst, uint64(exp), 10, exp < 0, true)
+
+	return dst
 }
 
 func min(a, b int) int {
diff --git a/src/strconv/ftoa_test.go b/src/strconv/ftoa_test.go
index 39b8615..1b4dcd9 100644
--- a/src/strconv/ftoa_test.go
+++ b/src/strconv/ftoa_test.go
@@ -227,6 +227,7 @@
 func BenchmarkAppendFloatBig(b *testing.B) {
 	benchmarkAppendFloat(b, 123456789123456789123456789, 'g', -1, 64)
 }
+func BenchmarkAppendFloatBinaryExp(b *testing.B) { benchmarkAppendFloat(b, -1, 'b', -1, 64) }
 
 func BenchmarkAppendFloat32Integer(b *testing.B)       { benchmarkAppendFloat(b, 33909, 'g', -1, 32) }
 func BenchmarkAppendFloat32ExactFraction(b *testing.B) { benchmarkAppendFloat(b, 3.375, 'g', -1, 32) }
diff --git a/src/strings/strings.go b/src/strings/strings.go
index f362f18..c6085f5 100644
--- a/src/strings/strings.go
+++ b/src/strings/strings.go
@@ -126,17 +126,17 @@
 	return n
 }
 
-// Contains returns true if substr is within s.
+// Contains reports whether substr is within s.
 func Contains(s, substr string) bool {
 	return Index(s, substr) >= 0
 }
 
-// ContainsAny returns true if any Unicode code points in chars are within s.
+// ContainsAny reports whether any Unicode code points in chars are within s.
 func ContainsAny(s, chars string) bool {
 	return IndexAny(s, chars) >= 0
 }
 
-// ContainsRune returns true if the Unicode code point r is within s.
+// ContainsRune reports whether the Unicode code point r is within s.
 func ContainsRune(s string, r rune) bool {
 	return IndexRune(s, r) >= 0
 }
@@ -520,7 +520,7 @@
 // Title returns a copy of the string s with all Unicode letters that begin words
 // mapped to their title case.
 //
-// BUG: The rule Title uses for word boundaries does not handle Unicode punctuation properly.
+// BUG(rsc): The rule Title uses for word boundaries does not handle Unicode punctuation properly.
 func Title(s string) string {
 	// Use a closure here to remember state.
 	// Hackish but effective. Depends on Map scanning in order and calling
diff --git a/src/strings/strings_test.go b/src/strings/strings_test.go
index 7bb81ef..ee0c260 100644
--- a/src/strings/strings_test.go
+++ b/src/strings/strings_test.go
@@ -569,6 +569,35 @@
 	}
 }
 
+func BenchmarkTrim(b *testing.B) {
+	b.ReportAllocs()
+
+	for i := 0; i < b.N; i++ {
+		for _, tc := range trimTests {
+			name := tc.f
+			var f func(string, string) string
+			switch name {
+			case "Trim":
+				f = Trim
+			case "TrimLeft":
+				f = TrimLeft
+			case "TrimRight":
+				f = TrimRight
+			case "TrimPrefix":
+				f = TrimPrefix
+			case "TrimSuffix":
+				f = TrimSuffix
+			default:
+				b.Errorf("Undefined trim function %s", name)
+			}
+			actual := f(tc.in, tc.arg)
+			if actual != tc.out {
+				b.Errorf("%s(%q, %q) = %q; want %q", name, tc.in, tc.arg, actual, tc.out)
+			}
+		}
+	}
+}
+
 type predicate struct {
 	f    func(rune) bool
 	name string
diff --git a/src/sync/atomic/asm_arm64.s b/src/sync/atomic/asm_arm64.s
new file mode 100644
index 0000000..32e9625
--- /dev/null
+++ b/src/sync/atomic/asm_arm64.s
@@ -0,0 +1,149 @@
+// 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.
+
+#include "textflag.h"
+
+TEXT ·SwapInt32(SB),NOSPLIT,$0-20
+	B	·SwapUint32(SB)
+
+TEXT ·SwapUint32(SB),NOSPLIT,$0-20
+	MOVD	addr+0(FP), R0
+	MOVW	new+8(FP), R1
+again:
+	LDAXRW	(R0), R2
+	STLXRW	R1, (R0), R3
+	CBNZ	R3, again
+	MOVW	R2, old+16(FP)
+	RET
+
+TEXT ·SwapInt64(SB),NOSPLIT,$0-24
+	B	·SwapUint64(SB)
+
+TEXT ·SwapUint64(SB),NOSPLIT,$0-24
+	MOVD	addr+0(FP), R0
+	MOVD	new+8(FP), R1
+again:
+	LDAXR	(R0), R2
+	STLXR	R1, (R0), R3
+	CBNZ	R3, again
+	MOVD	R2, old+16(FP)
+	RET
+
+TEXT ·SwapUintptr(SB),NOSPLIT,$0-24
+	B	·SwapUint64(SB)
+
+TEXT ·CompareAndSwapInt32(SB),NOSPLIT,$0-17
+	B	·CompareAndSwapUint32(SB)
+
+TEXT ·CompareAndSwapUint32(SB),NOSPLIT,$0-17
+	MOVD	addr+0(FP), R0
+	MOVW	old+8(FP), R1
+	MOVW	new+12(FP), R2
+again:
+	LDAXRW	(R0), R3
+	CMPW	R1, R3
+	BNE	ok
+	STLXRW	R2, (R0), R3
+	CBNZ	R3, again
+ok:
+	CSET	EQ, R0
+	MOVB	R0, swapped+16(FP)
+	RET
+
+TEXT ·CompareAndSwapUintptr(SB),NOSPLIT,$0-25
+	B	·CompareAndSwapUint64(SB)
+
+TEXT ·CompareAndSwapInt64(SB),NOSPLIT,$0-25
+	B	·CompareAndSwapUint64(SB)
+
+TEXT ·CompareAndSwapUint64(SB),NOSPLIT,$0-25
+	MOVD	addr+0(FP), R0
+	MOVD	old+8(FP), R1
+	MOVD	new+16(FP), R2
+again:
+	LDAXR	(R0), R3
+	CMP	R1, R3
+	BNE	ok
+	STLXR	R2, (R0), R3
+	CBNZ	R3, again
+ok:
+	CSET	EQ, R0
+	MOVB	R0, swapped+24(FP)
+	RET
+
+TEXT ·AddInt32(SB),NOSPLIT,$0-20
+	B	·AddUint32(SB)
+
+TEXT ·AddUint32(SB),NOSPLIT,$0-20
+	MOVD	addr+0(FP), R0
+	MOVW	delta+8(FP), R1
+again:
+	LDAXRW	(R0), R2
+	ADDW	R2, R1, R2
+	STLXRW	R2, (R0), R3
+	CBNZ	R3, again
+	MOVW	R2, new+16(FP)
+	RET
+
+TEXT ·AddUintptr(SB),NOSPLIT,$0-24
+	B	·AddUint64(SB)
+
+TEXT ·AddInt64(SB),NOSPLIT,$0-24
+	B	·AddUint64(SB)
+
+TEXT ·AddUint64(SB),NOSPLIT,$0-24
+	MOVD	addr+0(FP), R0
+	MOVD	delta+8(FP), R1
+again:
+	LDAXR	(R0), R2
+	ADD	R2, R1, R2
+	STLXR	R2, (R0), R3
+	CBNZ	R3, again
+	MOVD	R2, new+16(FP)
+	RET
+
+TEXT ·LoadInt32(SB),NOSPLIT,$0-12
+	B	·LoadUint32(SB)
+
+TEXT ·LoadUint32(SB),NOSPLIT,$0-12
+	MOVD	addr+0(FP), R0
+	LDARW	(R0), R0
+	MOVW	R0, val+8(FP)
+	RET
+
+TEXT ·LoadInt64(SB),NOSPLIT,$0-16
+	B	·LoadUint64(SB)
+
+TEXT ·LoadUint64(SB),NOSPLIT,$0-16
+	MOVD	addr+0(FP), R0
+	LDAR	(R0), R0
+	MOVD	R0, val+8(FP)
+	RET
+
+TEXT ·LoadUintptr(SB),NOSPLIT,$0-16
+	B	·LoadPointer(SB)
+
+TEXT ·LoadPointer(SB),NOSPLIT,$0-16
+	B	·LoadUint64(SB)
+
+TEXT ·StoreInt32(SB),NOSPLIT,$0-12
+	B	·StoreUint32(SB)
+
+TEXT ·StoreUint32(SB),NOSPLIT,$0-12
+	MOVD	addr+0(FP), R0
+	MOVW	val+8(FP), R1
+	STLRW	R1, (R0)
+	RET
+
+TEXT ·StoreInt64(SB),NOSPLIT,$0-16
+	B	·StoreUint64(SB)
+
+TEXT ·StoreUint64(SB),NOSPLIT,$0-16
+	MOVD	addr+0(FP), R0
+	MOVD	val+8(FP), R1
+	STLR	R1, (R0)
+	RET
+
+TEXT ·StoreUintptr(SB),NOSPLIT,$0-16
+	B	·StoreUint64(SB)
diff --git a/src/sync/atomic/asm_openbsd_arm.s b/src/sync/atomic/asm_openbsd_arm.s
new file mode 100644
index 0000000..8c48a0a
--- /dev/null
+++ b/src/sync/atomic/asm_openbsd_arm.s
@@ -0,0 +1,100 @@
+// Copyright 2013 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.
+
+#include "textflag.h"
+
+// OpenBSD/ARM atomic operations.
+// TODO(minux): this only supports ARMv6K or higher.
+
+TEXT ·CompareAndSwapInt32(SB),NOSPLIT,$0
+	B ·CompareAndSwapUint32(SB)
+
+TEXT ·CompareAndSwapUint32(SB),NOSPLIT,$0
+	B ·armCompareAndSwapUint32(SB)
+
+TEXT ·CompareAndSwapUintptr(SB),NOSPLIT,$0
+	B ·CompareAndSwapUint32(SB)
+
+TEXT ·AddInt32(SB),NOSPLIT,$0
+	B ·AddUint32(SB)
+
+TEXT ·AddUint32(SB),NOSPLIT,$0
+	B ·armAddUint32(SB)
+
+TEXT ·AddUintptr(SB),NOSPLIT,$0
+	B ·AddUint32(SB)
+
+TEXT ·SwapInt32(SB),NOSPLIT,$0
+	B ·SwapUint32(SB)
+
+TEXT ·SwapUint32(SB),NOSPLIT,$0
+	B ·armSwapUint32(SB)
+
+TEXT ·SwapUintptr(SB),NOSPLIT,$0
+	B ·SwapUint32(SB)
+
+TEXT ·CompareAndSwapInt64(SB),NOSPLIT,$0
+	B ·CompareAndSwapUint64(SB)
+
+TEXT ·CompareAndSwapUint64(SB),NOSPLIT,$-4
+	B ·armCompareAndSwapUint64(SB)
+
+TEXT ·AddInt64(SB),NOSPLIT,$0
+	B ·addUint64(SB)
+
+TEXT ·AddUint64(SB),NOSPLIT,$0
+	B ·addUint64(SB)
+
+TEXT ·SwapInt64(SB),NOSPLIT,$0
+	B ·swapUint64(SB)
+
+TEXT ·SwapUint64(SB),NOSPLIT,$0
+	B ·swapUint64(SB)
+
+TEXT ·LoadInt32(SB),NOSPLIT,$0
+	B ·LoadUint32(SB)
+
+TEXT ·LoadUint32(SB),NOSPLIT,$0-8
+	MOVW addr+0(FP), R1
+load32loop:
+	LDREX (R1), R2		// loads R2
+	STREX R2, (R1), R0	// stores R2
+	CMP $0, R0
+	BNE load32loop
+	MOVW R2, val+4(FP)
+	RET
+
+TEXT ·LoadInt64(SB),NOSPLIT,$0
+	B ·loadUint64(SB)
+
+TEXT ·LoadUint64(SB),NOSPLIT,$0
+	B ·loadUint64(SB)
+
+TEXT ·LoadUintptr(SB),NOSPLIT,$0
+	B ·LoadUint32(SB)
+
+TEXT ·LoadPointer(SB),NOSPLIT,$0
+	B ·LoadUint32(SB)
+
+TEXT ·StoreInt32(SB),NOSPLIT,$0
+	B ·StoreUint32(SB)
+
+TEXT ·StoreUint32(SB),NOSPLIT,$0-8
+	MOVW addr+0(FP), R1
+	MOVW val+4(FP), R2
+storeloop:
+	LDREX (R1), R4		// loads R4
+	STREX R2, (R1), R0	// stores R2
+	CMP $0, R0
+	BNE storeloop
+	RET
+
+TEXT ·StoreInt64(SB),NOSPLIT,$0
+	B ·storeUint64(SB)
+
+TEXT ·StoreUint64(SB),NOSPLIT,$0
+	B ·storeUint64(SB)
+
+TEXT ·StoreUintptr(SB),NOSPLIT,$0
+	B ·StoreUint32(SB)
diff --git a/src/sync/atomic/atomic_test.go b/src/sync/atomic/atomic_test.go
index 3a59f59..ca9ebcf 100644
--- a/src/sync/atomic/atomic_test.go
+++ b/src/sync/atomic/atomic_test.go
@@ -1403,8 +1403,11 @@
 }
 
 func TestNilDeref(t *testing.T) {
-	if p := runtime.GOOS + "/" + runtime.GOARCH; p == "freebsd/arm" || p == "netbsd/arm" {
-		t.Skipf("issue 7338: skipping test on %q", p)
+	switch runtime.GOOS {
+	case "darwin", "freebsd", "netbsd":
+		if runtime.GOARCH == "arm" {
+			t.Skipf("issue 7338: skipping test on %s/%s", runtime.GOOS, runtime.GOARCH)
+		}
 	}
 	funcs := [...]func(){
 		func() { CompareAndSwapInt32(nil, 0, 0) },
diff --git a/src/syscall/asm_darwin_amd64.s b/src/syscall/asm_darwin_amd64.s
index 9cf9bcb..01f461b 100644
--- a/src/syscall/asm_darwin_amd64.s
+++ b/src/syscall/asm_darwin_amd64.s
@@ -9,10 +9,9 @@
 // System call support for AMD64, Darwin
 //
 
-// func Syscall(trap int64, a1, a2, a3 int64) (r1, r2, err int64);
-// func Syscall6(trap int64, a1, a2, a3, a4, a5, a6 int64) (r1, r2, err int64);
 // Trap # in AX, args in DI SI DX, return in AX DX
 
+// func Syscall(trap, a1, a2, a3 uintptr) (r1, r2 uintptr, err Errno);
 TEXT	·Syscall(SB),NOSPLIT,$0-56
 	CALL	runtime·entersyscall(SB)
 	MOVQ	a1+8(FP), DI
@@ -37,6 +36,7 @@
 	CALL	runtime·exitsyscall(SB)
 	RET
 
+// func Syscall6(trap, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2 uintptr, err Errno);
 TEXT	·Syscall6(SB),NOSPLIT,$0-80
 	CALL	runtime·entersyscall(SB)
 	MOVQ	a1+8(FP), DI
@@ -61,6 +61,41 @@
 	CALL	runtime·exitsyscall(SB)
 	RET
 
+// func Syscall9(trap, a1, a2, a3, a4, a5, a6, a7, a8, a9 uintptr) (r1, r2 uintptr, err Errno)
+TEXT	·Syscall9(SB),NOSPLIT,$0-104
+	CALL	runtime·entersyscall(SB)
+	MOVQ	trap+0(FP), AX	// syscall entry
+	MOVQ	a1+8(FP), DI
+	MOVQ	a2+16(FP), SI
+	MOVQ	a3+24(FP), DX
+	MOVQ	a4+32(FP), R10
+	MOVQ	a5+40(FP), R8
+	MOVQ	a6+48(FP), R9
+	MOVQ	a7+56(FP), R11
+	MOVQ	a8+64(FP), R12
+	MOVQ	a9+72(FP), R13
+	SUBQ	$32, SP
+	MOVQ	R11, 8(SP)
+	MOVQ	R12, 16(SP)
+	MOVQ	R13, 24(SP)
+	ADDQ	$0x2000000, AX
+	SYSCALL
+	JCC	ok9
+	ADDQ	$32, SP
+	MOVQ	$-1, r1+80(FP)
+	MOVQ	$0, r2+88(FP)
+	MOVQ	AX, err+96(FP)
+	CALL	runtime·exitsyscall(SB)
+	RET
+ok9:
+	ADDQ	$32, SP
+	MOVQ	AX, r1+80(FP)
+	MOVQ	DX, r2+88(FP)
+	MOVQ	$0, err+96(FP)
+	CALL	runtime·exitsyscall(SB)
+	RET
+
+// func RawSyscall(trap, a1, a2, a3 uintptr) (r1, r2 uintptr, err Errno)
 TEXT ·RawSyscall(SB),NOSPLIT,$0-56
 	MOVQ	a1+8(FP), DI
 	MOVQ	a2+16(FP), SI
@@ -82,6 +117,7 @@
 	MOVQ	$0, err+48(FP)
 	RET
 
+// func RawSyscall(trap, a1, a2, a3 uintptr) (r1, r2 uintptr, err Errno)
 TEXT	·RawSyscall6(SB),NOSPLIT,$0-80
 	MOVQ	a1+8(FP), DI
 	MOVQ	a2+16(FP), SI
diff --git a/src/syscall/asm_dragonfly_386.s b/src/syscall/asm_dragonfly_386.s
deleted file mode 100644
index 7012d23..0000000
--- a/src/syscall/asm_dragonfly_386.s
+++ /dev/null
@@ -1,140 +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.
-
-#include "textflag.h"
-#include "funcdata.h"
-
-//
-// System call support for 386, FreeBSD
-//
-
-// func Syscall(trap int32, a1, a2, a3 int32) (r1, r2, err int32);
-// func Syscall6(trap int32, a1, a2, a3, a4, a5, a6 int32) (r1, r2, err int32);
-// Trap # in AX, args on stack above caller pc.
-
-TEXT	·Syscall(SB),NOSPLIT,$0-32
-	CALL	runtime·entersyscall(SB)
-	MOVL	4(SP), AX	// syscall entry
-	// slide args down on top of system call number
-	LEAL		8(SP), SI
-	LEAL		4(SP), DI
-	CLD
-	MOVSL
-	MOVSL
-	MOVSL
-	INT	$0x80
-	JAE	ok
-	MOVL	$-1, 20(SP)	// r1
-	MOVL	$-1, 24(SP)	// r2
-	MOVL	AX, 28(SP)		// errno
-	CALL	runtime·exitsyscall(SB)
-	RET
-ok:
-	MOVL	AX, 20(SP)	// r1
-	MOVL	DX, 24(SP)	// r2
-	MOVL	$0, 28(SP)	// errno
-	CALL	runtime·exitsyscall(SB)
-	RET
-
-TEXT	·Syscall6(SB),NOSPLIT,$0-44
-	CALL	runtime·entersyscall(SB)
-	MOVL	4(SP), AX	// syscall entry
-	// slide args down on top of system call number
-	LEAL		8(SP), SI
-	LEAL		4(SP), DI
-	CLD
-	MOVSL
-	MOVSL
-	MOVSL
-	MOVSL
-	MOVSL
-	MOVSL
-	INT	$0x80
-	JAE	ok6
-	MOVL	$-1, 32(SP)	// r1
-	MOVL	$-1, 36(SP)	// r2
-	MOVL	AX, 40(SP)		// errno
-	CALL	runtime·exitsyscall(SB)
-	RET
-ok6:
-	MOVL	AX, 32(SP)	// r1
-	MOVL	DX, 36(SP)	// r2
-	MOVL	$0, 40(SP)	// errno
-	CALL	runtime·exitsyscall(SB)
-	RET
-
-TEXT	·Syscall9(SB),NOSPLIT,$0-56
-	CALL	runtime·entersyscall(SB)
-	MOVL	4(SP), AX	// syscall entry
-	// slide args down on top of system call number
-	LEAL		8(SP), SI
-	LEAL		4(SP), DI
-	CLD
-	MOVSL
-	MOVSL
-	MOVSL
-	MOVSL
-	MOVSL
-	MOVSL
-	MOVSL
-	MOVSL
-	MOVSL
-	INT	$0x80
-	JAE	ok9
-	MOVL	$-1, 44(SP)	// r1
-	MOVL	$-1, 48(SP)	// r2
-	MOVL	AX, 52(SP)		// errno
-	CALL	runtime·exitsyscall(SB)
-	RET
-ok9:
-	MOVL	AX, 44(SP)	// r1
-	MOVL	DX, 48(SP)	// r2
-	MOVL	$0, 52(SP)	// errno
-	CALL	runtime·exitsyscall(SB)
-	RET
-
-TEXT ·RawSyscall(SB),NOSPLIT,$0-32
-	MOVL	4(SP), AX	// syscall entry
-	// slide args down on top of system call number
-	LEAL		8(SP), SI
-	LEAL		4(SP), DI
-	CLD
-	MOVSL
-	MOVSL
-	MOVSL
-	INT	$0x80
-	JAE	ok1
-	MOVL	$-1, 20(SP)	// r1
-	MOVL	$-1, 24(SP)	// r2
-	MOVL	AX, 28(SP)		// errno
-	RET
-ok1:
-	MOVL	AX, 20(SP)	// r1
-	MOVL	DX, 24(SP)	// r2
-	MOVL	$0, 28(SP)	// errno
-	RET
-
-TEXT	·RawSyscall6(SB),NOSPLIT,$0-44
-	MOVL	4(SP), AX	// syscall entry
-	// slide args down on top of system call number
-	LEAL		8(SP), SI
-	LEAL		4(SP), DI
-	CLD
-	MOVSL
-	MOVSL
-	MOVSL
-	MOVSL
-	MOVSL
-	MOVSL
-	INT	$0x80
-	JAE	ok2
-	MOVL	$-1, 32(SP)	// r1
-	MOVL	$-1, 36(SP)	// r2
-	MOVL	AX, 40(SP)		// errno
-	RET
-ok2:
-	MOVL	AX, 32(SP)	// r1
-	MOVL	DX, 36(SP)	// r2
-	MOVL	$0, 40(SP)	// errno
-	RET
diff --git a/src/syscall/asm_linux_arm64.s b/src/syscall/asm_linux_arm64.s
new file mode 100644
index 0000000..184a44f
--- /dev/null
+++ b/src/syscall/asm_linux_arm64.s
@@ -0,0 +1,105 @@
+// Copyright 2015 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.
+
+#include "textflag.h"
+
+// func Syscall(trap int64, a1, a2, a3 int64) (r1, r2, err int64);
+
+TEXT	·Syscall(SB),NOSPLIT,$0-56
+	BL	runtime·entersyscall(SB)
+	MOVD	a1+8(FP), R0
+	MOVD	a2+16(FP), R1
+	MOVD	a3+24(FP), R2
+	MOVD	$0, R3
+	MOVD	$0, R4
+	MOVD	$0, R5
+	MOVD	trap+0(FP), R8	// syscall entry
+	SVC
+	CMN	$4095, R0
+	BCC	ok
+	MOVD	$-1, R4
+	MOVD	R4, r1+32(FP)	// r1
+	MOVD	ZR, r2+40(FP)	// r2
+	NEG	R0, R0
+	MOVD	R0, err+48(FP)	// errno
+	BL	runtime·exitsyscall(SB)
+	RET
+ok:
+	MOVD	R0, r1+32(FP)	// r1
+	MOVD	R1, r2+40(FP)	// r2
+	MOVD	ZR, err+48(FP)	// errno
+	BL	runtime·exitsyscall(SB)
+	RET
+
+TEXT ·Syscall6(SB),NOSPLIT,$0-80
+	BL	runtime·entersyscall(SB)
+	MOVD	a1+8(FP), R0
+	MOVD	a2+16(FP), R1
+	MOVD	a3+24(FP), R2
+	MOVD	a4+32(FP), R3
+	MOVD	a5+40(FP), R4
+	MOVD	a6+48(FP), R5
+	MOVD	trap+0(FP), R8	// syscall entry
+	SVC
+	CMN	$4095, R0
+	BCC	ok
+	MOVD	$-1, R4
+	MOVD	R4, r1+56(FP)	// r1
+	MOVD	ZR, r2+64(FP)	// r2
+	NEG	R0, R0
+	MOVD	R0, err+72(FP)	// errno
+	BL	runtime·exitsyscall(SB)
+	RET
+ok:
+	MOVD	R0, r1+56(FP)	// r1
+	MOVD	R1, r2+64(FP)	// r2
+	MOVD	ZR, err+72(FP)	// errno
+	BL	runtime·exitsyscall(SB)
+	RET
+
+TEXT ·RawSyscall(SB),NOSPLIT,$0-56
+	MOVD	a1+8(FP), R0
+	MOVD	a2+16(FP), R1
+	MOVD	a3+24(FP), R2
+	MOVD	$0, R3
+	MOVD	$0, R4
+	MOVD	$0, R5
+	MOVD	trap+0(FP), R8	// syscall entry
+	SVC
+	CMN	$4095, R0
+	BCC	ok
+	MOVD	$-1, R4
+	MOVD	R4, r1+32(FP)	// r1
+	MOVD	ZR, r2+40(FP)	// r2
+	NEG	R0, R0
+	MOVD	R0, err+48(FP)	// errno
+	RET
+ok:
+	MOVD	R0, r1+32(FP)	// r1
+	MOVD	R1, r2+40(FP)	// r2
+	MOVD	ZR, err+48(FP)	// errno
+	RET
+
+TEXT ·RawSyscall6(SB),NOSPLIT,$0-80
+	MOVD	a1+8(FP), R0
+	MOVD	a2+16(FP), R1
+	MOVD	a3+24(FP), R2
+	MOVD	a4+32(FP), R3
+	MOVD	a5+40(FP), R4
+	MOVD	a6+48(FP), R5
+	MOVD	trap+0(FP), R8	// syscall entry
+	SVC
+	CMN	$4095, R0
+	BCC	ok
+	MOVD	$-1, R4
+	MOVD	R4, r1+56(FP)	// r1
+	MOVD	ZR, r2+64(FP)	// r2
+	NEG	R0, R0
+	MOVD	R0, err+72(FP)	// errno
+	RET
+ok:
+	MOVD	R0, r1+56(FP)	// r1
+	MOVD	R1, r2+64(FP)	// r2
+	MOVD	ZR, err+72(FP)	// errno
+	RET
diff --git a/src/syscall/asm_openbsd_arm.s b/src/syscall/asm_openbsd_arm.s
new file mode 100644
index 0000000..4f034a0
--- /dev/null
+++ b/src/syscall/asm_openbsd_arm.s
@@ -0,0 +1,132 @@
+// Copyright 2013 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.
+
+#include "textflag.h"
+#include "funcdata.h"
+
+//
+// System call support for ARM, OpenBSD
+//
+
+// func Syscall(trap int32, a1, a2, a3 int32) (r1, r2, err int32);
+// func Syscall6(trap int32, a1, a2, a3, a4, a5, a6 int32) (r1, r2, err int32);
+// func Syscall9(trap int32, a1, a2, a3, a4, a5, a6, a7, a8, a9 int64) (r1, r2, err int32)
+// func RawSyscall(trap int32, a1, a2, a3 int32) (r1, r2, err int32);
+// func RawSyscall6(trap int32, a1, a2, a3, a4, a5, a6 int32) (r1, r2, err int32);
+
+TEXT	·Syscall(SB),NOSPLIT,$0-28
+	BL runtime·entersyscall(SB)
+	MOVW syscall+0(FP), R12		// syscall number
+	MOVW a1+4(FP), R0		// arg 1
+	MOVW a2+8(FP), R1		// arg 2
+	MOVW a3+12(FP), R2		// arg 3
+	SWI $0
+	MOVW $0, R2
+	BCS error
+	MOVW R0, r1+16(FP)		// ret 1
+	MOVW R1, r2+20(FP)		// ret 2
+	MOVW R2, err+24(FP)		// err
+	BL runtime·exitsyscall(SB)
+	RET
+error:
+	MOVW $-1, R3
+	MOVW R3, r1+16(FP)		// ret 1
+	MOVW R2, r2+20(FP)		// ret 2
+	MOVW R0, err+24(FP)		// err
+	BL runtime·exitsyscall(SB)
+	RET
+
+TEXT	·Syscall6(SB),NOSPLIT,$0-40
+	BL runtime·entersyscall(SB)
+	MOVW syscall+0(FP), R12		// syscall number
+	MOVW a1+4(FP), R0		// arg 1
+	MOVW a2+8(FP), R1		// arg 2
+	MOVW a3+12(FP), R2		// arg 3
+	MOVW a4+16(FP), R3		// arg 4
+	MOVW R13, R4
+	MOVW $a5+20(FP), R13		// arg 5 to arg 6 are passed on stack
+	SWI $0
+	MOVW R4, R13
+	MOVW $0, R2
+	BCS error6
+	MOVW R0, r1+28(FP)		// ret 1
+	MOVW R1, r2+32(FP)		// ret 2
+	MOVW R2, err+36(FP)		// err
+	BL runtime·exitsyscall(SB)
+	RET
+error6:
+	MOVW $-1, R3
+	MOVW R3, r1+28(FP)		// ret 1
+	MOVW R2, r2+32(FP)		// ret 2
+	MOVW R0, err+36(FP)		// err
+	BL runtime·exitsyscall(SB)
+	RET
+
+TEXT	·Syscall9(SB),NOSPLIT,$0-52
+	BL runtime·entersyscall(SB)
+	MOVW syscall+0(FP), R12		// syscall number
+	MOVW a1+4(FP), R0		// arg 1
+	MOVW a2+8(FP), R1		// arg 2
+	MOVW a3+12(FP), R2		// arg 3
+	MOVW a4+16(FP), R3		// arg 4
+	MOVW R13, R4
+	MOVW $a5+20(FP), R13		// arg 5 to arg 9 are passed on stack
+	SWI $0
+	MOVW R4, R13
+	MOVW $0, R2
+	BCS error9
+	MOVW R0, r1+40(FP)		// ret 1
+	MOVW R1, r2+44(FP)		// ret 2
+	MOVW R2, err+48(FP)		// err
+	BL runtime·exitsyscall(SB)
+	RET
+error9:
+	MOVW $-1, R3
+	MOVW R3, r1+40(FP)		// ret 1
+	MOVW R2, r2+44(FP)		// ret 2
+	MOVW R0, err+48(FP)		// err
+	BL runtime·exitsyscall(SB)
+	RET
+
+TEXT	·RawSyscall(SB),NOSPLIT,$0-28
+	MOVW syscall+0(FP), R12		// syscall number
+	MOVW a1+4(FP), R0		// arg 1
+	MOVW a2+8(FP), R1		// arg 2
+	MOVW a3+12(FP), R2		// arg 3
+	SWI $0
+	MOVW $0, R2
+	BCS errorr
+	MOVW R0, r1+16(FP)		// ret 1
+	MOVW R1, r2+20(FP)		// ret 2
+	MOVW R2, err+24(FP)		// err
+	RET
+errorr:
+	MOVW $-1, R3
+	MOVW R3, r1+16(FP)		// ret 1
+	MOVW R2, r2+20(FP)		// ret 2
+	MOVW R0, err+24(FP)		// err
+	RET
+
+TEXT	·RawSyscall6(SB),NOSPLIT,$0-40
+	MOVW syscall+0(FP), R12		// syscall number
+	MOVW a1+4(FP), R0		// arg 1
+	MOVW a2+8(FP), R1		// arg 2
+	MOVW a3+12(FP), R2		// arg 3
+	MOVW a4+16(FP), R3		// arg 4
+	MOVW R13, R4
+	MOVW $a5+20(FP), R13		// arg 5 to arg 6 are passed on stack
+	SWI $0
+	MOVW R4, R13
+	MOVW $0, R2
+	BCS errorr6
+	MOVW R0, r1+28(FP)		// ret 1
+	MOVW R1, r2+32(FP)		// ret 2
+	MOVW R2, err+36(FP)		// err
+	RET
+errorr6:
+	MOVW $-1, R3
+	MOVW R3, r1+28(FP)		// ret 1
+	MOVW R2, r2+32(FP)		// ret 2
+	MOVW R0, err+36(FP)		// err
+	RET
diff --git a/src/syscall/asm_solaris_amd64.s b/src/syscall/asm_solaris_amd64.s
index d0d271c..cc69caa 100644
--- a/src/syscall/asm_solaris_amd64.s
+++ b/src/syscall/asm_solaris_amd64.s
@@ -47,6 +47,9 @@
 TEXT ·gethostname(SB),NOSPLIT,$0
 	JMP	runtime·syscall_gethostname(SB)
 
+TEXT ·getpid(SB),NOSPLIT,$0
+	JMP	runtime·syscall_getpid(SB)
+
 TEXT ·ioctl(SB),NOSPLIT,$0
 	JMP	runtime·syscall_ioctl(SB)
 
diff --git a/src/syscall/exec_bsd.go b/src/syscall/exec_bsd.go
index ff78f19..4b5774b 100644
--- a/src/syscall/exec_bsd.go
+++ b/src/syscall/exec_bsd.go
@@ -16,9 +16,12 @@
 	Credential *Credential // Credential.
 	Ptrace     bool        // Enable tracing.
 	Setsid     bool        // Create session.
-	Setpgid    bool        // Set process group ID to new pid (SYSV setpgrp)
-	Setctty    bool        // Set controlling terminal to fd 0
+	Setpgid    bool        // Set process group ID to Pgid, or, if Pgid == 0, to new pid.
+	Setctty    bool        // Set controlling terminal to fd Ctty
 	Noctty     bool        // Detach fd 0 from controlling terminal
+	Ctty       int         // Controlling TTY fd
+	Foreground bool        // Place child's process group in foreground. (Implies Setpgid. Uses Ctty as fd of controlling TTY)
+	Pgid       int         // Child's process group ID if Setpgid.
 }
 
 // Implemented in runtime package.
@@ -101,8 +104,27 @@
 	}
 
 	// Set process group
-	if sys.Setpgid {
-		_, _, err1 = RawSyscall(SYS_SETPGID, 0, 0, 0)
+	if sys.Setpgid || sys.Foreground {
+		// Place child in process group.
+		_, _, err1 = RawSyscall(SYS_SETPGID, 0, uintptr(sys.Pgid), 0)
+		if err1 != 0 {
+			goto childerror
+		}
+	}
+
+	if sys.Foreground {
+		pgrp := sys.Pgid
+		if pgrp == 0 {
+			r1, _, err1 = RawSyscall(SYS_GETPID, 0, 0, 0)
+			if err1 != 0 {
+				goto childerror
+			}
+
+			pgrp = int(r1)
+		}
+
+		// Place process group in foreground.
+		_, _, err1 = RawSyscall(SYS_IOCTL, uintptr(sys.Ctty), uintptr(TIOCSPGRP), uintptr(unsafe.Pointer(&pgrp)))
 		if err1 != 0 {
 			goto childerror
 		}
@@ -210,9 +232,9 @@
 		}
 	}
 
-	// Make fd 0 the tty
+	// Set the controlling TTY to Ctty
 	if sys.Setctty {
-		_, _, err1 = RawSyscall(SYS_IOCTL, 0, uintptr(TIOCSCTTY), 0)
+		_, _, err1 = RawSyscall(SYS_IOCTL, uintptr(sys.Ctty), uintptr(TIOCSCTTY), 0)
 		if err1 != 0 {
 			goto childerror
 		}
diff --git a/src/syscall/exec_linux.go b/src/syscall/exec_linux.go
index 03dd5c5..02474fc 100644
--- a/src/syscall/exec_linux.go
+++ b/src/syscall/exec_linux.go
@@ -23,10 +23,12 @@
 	Credential  *Credential    // Credential.
 	Ptrace      bool           // Enable tracing.
 	Setsid      bool           // Create session.
-	Setpgid     bool           // Set process group ID to new pid (SYSV setpgrp)
+	Setpgid     bool           // Set process group ID to Pgid, or, if Pgid == 0, to new pid.
 	Setctty     bool           // Set controlling terminal to fd Ctty (only meaningful if Setsid is set)
 	Noctty      bool           // Detach fd 0 from controlling terminal
-	Ctty        int            // Controlling TTY fd (Linux only)
+	Ctty        int            // Controlling TTY fd
+	Foreground  bool           // Place child's process group in foreground. (Implies Setpgid. Uses Ctty as fd of controlling TTY)
+	Pgid        int            // Child's process group ID if Setpgid.
 	Pdeathsig   Signal         // Signal that the process will get when its parent dies (Linux only)
 	Cloneflags  uintptr        // Flags for clone calls (Linux only)
 	UidMappings []SysProcIDMap // User ID mappings for user namespaces.
@@ -167,8 +169,27 @@
 	}
 
 	// Set process group
-	if sys.Setpgid {
-		_, _, err1 = RawSyscall(SYS_SETPGID, 0, 0, 0)
+	if sys.Setpgid || sys.Foreground {
+		// Place child in process group.
+		_, _, err1 = RawSyscall(SYS_SETPGID, 0, uintptr(sys.Pgid), 0)
+		if err1 != 0 {
+			goto childerror
+		}
+	}
+
+	if sys.Foreground {
+		pgrp := sys.Pgid
+		if pgrp == 0 {
+			r1, _, err1 = RawSyscall(SYS_GETPID, 0, 0, 0)
+			if err1 != 0 {
+				goto childerror
+			}
+
+			pgrp = int(r1)
+		}
+
+		// Place process group in foreground.
+		_, _, err1 = RawSyscall(SYS_IOCTL, uintptr(sys.Ctty), uintptr(TIOCSPGRP), uintptr(unsafe.Pointer(&pgrp)))
 		if err1 != 0 {
 			goto childerror
 		}
@@ -214,7 +235,7 @@
 	// Pass 1: look for fd[i] < i and move those up above len(fd)
 	// so that pass 2 won't stomp on an fd it needs later.
 	if pipe < nextfd {
-		_, _, err1 = RawSyscall(SYS_DUP2, uintptr(pipe), uintptr(nextfd), 0)
+		_, _, err1 = RawSyscall(_SYS_dup, uintptr(pipe), uintptr(nextfd), 0)
 		if err1 != 0 {
 			goto childerror
 		}
@@ -224,7 +245,7 @@
 	}
 	for i = 0; i < len(fd); i++ {
 		if fd[i] >= 0 && fd[i] < int(i) {
-			_, _, err1 = RawSyscall(SYS_DUP2, uintptr(fd[i]), uintptr(nextfd), 0)
+			_, _, err1 = RawSyscall(_SYS_dup, uintptr(fd[i]), uintptr(nextfd), 0)
 			if err1 != 0 {
 				goto childerror
 			}
@@ -254,7 +275,7 @@
 		}
 		// The new fd is created NOT close-on-exec,
 		// which is exactly what we want.
-		_, _, err1 = RawSyscall(SYS_DUP2, uintptr(fd[i]), uintptr(i), 0)
+		_, _, err1 = RawSyscall(_SYS_dup, uintptr(fd[i]), uintptr(i), 0)
 		if err1 != 0 {
 			goto childerror
 		}
@@ -277,7 +298,7 @@
 	}
 
 	// Set the controlling TTY to Ctty
-	if sys.Setctty && sys.Ctty >= 0 {
+	if sys.Setctty {
 		_, _, err1 = RawSyscall(SYS_IOCTL, uintptr(sys.Ctty), uintptr(TIOCSCTTY), 0)
 		if err1 != 0 {
 			goto childerror
diff --git a/src/syscall/exec_solaris.go b/src/syscall/exec_solaris.go
index 2052a66..3e949f1 100644
--- a/src/syscall/exec_solaris.go
+++ b/src/syscall/exec_solaris.go
@@ -12,9 +12,12 @@
 	Chroot     string      // Chroot.
 	Credential *Credential // Credential.
 	Setsid     bool        // Create session.
-	Setpgid    bool        // Set process group ID to new pid (SYSV setpgrp)
-	Setctty    bool        // Set controlling terminal to fd 0
+	Setpgid    bool        // Set process group ID to Pgid, or, if Pgid == 0, to new pid.
+	Setctty    bool        // Set controlling terminal to fd Ctty
 	Noctty     bool        // Detach fd 0 from controlling terminal
+	Ctty       int         // Controlling TTY fd
+	Foreground bool        // Place child's process group in foreground. (Implies Setpgid. Uses Ctty as fd of controlling TTY)
+	Pgid       int         // Child's process group ID if Setpgid.
 }
 
 // Implemented in runtime package.
@@ -28,6 +31,7 @@
 func exit(code uintptr)
 func fcntl1(fd uintptr, cmd uintptr, arg uintptr) (val uintptr, err Errno)
 func forkx(flags uintptr) (pid uintptr, err Errno)
+func getpid() (pid uintptr, err Errno)
 func ioctl(fd uintptr, req uintptr, arg uintptr) (err Errno)
 func setgid(gid uintptr) (err Errno)
 func setgroups1(ngid uintptr, gid uintptr) (err Errno)
@@ -97,8 +101,27 @@
 	}
 
 	// Set process group
-	if sys.Setpgid {
-		err1 = setpgid(0, 0)
+	if sys.Setpgid || sys.Foreground {
+		// Place child in process group.
+		err1 = setpgid(0, uintptr(sys.Pgid))
+		if err1 != 0 {
+			goto childerror
+		}
+	}
+
+	if sys.Foreground {
+		pgrp := sys.Pgid
+		if pgrp == 0 {
+			r1, err1 = getpid()
+			if err1 != 0 {
+				goto childerror
+			}
+
+			pgrp = int(r1)
+		}
+
+		// Place process group in foreground.
+		err1 = ioctl(uintptr(sys.Ctty), uintptr(TIOCSPGRP), uintptr(unsafe.Pointer(&pgrp)))
 		if err1 != 0 {
 			goto childerror
 		}
@@ -206,9 +229,9 @@
 		}
 	}
 
-	// Make fd 0 the tty
+	// Set the controlling TTY to Ctty
 	if sys.Setctty {
-		err1 = ioctl(0, uintptr(TIOCSCTTY), 0)
+		err1 = ioctl(uintptr(sys.Ctty), uintptr(TIOCSCTTY), 0)
 		if err1 != 0 {
 			goto childerror
 		}
diff --git a/src/syscall/exec_solaris_test.go b/src/syscall/exec_solaris_test.go
new file mode 100644
index 0000000..123d9f1
--- /dev/null
+++ b/src/syscall/exec_solaris_test.go
@@ -0,0 +1,29 @@
+// Copyright 2015 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.
+
+// +build solaris
+
+package syscall
+
+var (
+	procGetpgid = modlibc.NewProc("getpgid")
+	procGetpgrp = modlibc.NewProc("getpgrp")
+)
+
+func Getpgid(pid int) (pgid int, err error) {
+	r0, _, e1 := sysvicall6(procGetpgid.Addr(), 1, uintptr(pid), 0, 0, 0, 0, 0)
+	pgid = int(r0)
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+func Getpgrp() (pgrp int) {
+	r0, _, _ := sysvicall6(procGetpgrp.Addr(), 0, 0, 0, 0, 0, 0, 0)
+	pgrp = int(r0)
+	return
+}
+
+var Ioctl = ioctl
diff --git a/src/syscall/exec_unix_test.go b/src/syscall/exec_unix_test.go
new file mode 100644
index 0000000..ff82611
--- /dev/null
+++ b/src/syscall/exec_unix_test.go
@@ -0,0 +1,216 @@
+// Copyright 2015 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.
+
+// +build darwin dragonfly freebsd linux netbsd openbsd solaris
+
+package syscall_test
+
+import (
+	"io"
+	"os"
+	"os/exec"
+	"os/signal"
+	"runtime"
+	"syscall"
+	"testing"
+	"unsafe"
+)
+
+type command struct {
+	pipe io.WriteCloser
+	proc *exec.Cmd
+	test *testing.T
+}
+
+func (c *command) Info() (pid, pgrp int) {
+	pid = c.proc.Process.Pid
+
+	pgrp, err := syscall.Getpgid(pid)
+	if err != nil {
+		c.test.Fatal(err)
+	}
+
+	return
+}
+
+func (c *command) Start() {
+	if err := c.proc.Start(); err != nil {
+		c.test.Fatal(err)
+	}
+}
+
+func (c *command) Stop() {
+	c.pipe.Close()
+	if err := c.proc.Wait(); err != nil {
+		c.test.Fatal(err)
+	}
+}
+
+func create(t *testing.T) *command {
+	if runtime.GOOS == "darwin" && (runtime.GOARCH == "arm" || runtime.GOARCH == "arm64") {
+		t.Skipf("skipping on %s/%s, cannot fork", runtime.GOOS, runtime.GOARCH)
+	}
+	proc := exec.Command("cat")
+	stdin, err := proc.StdinPipe()
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	return &command{stdin, proc, t}
+}
+
+func parent() (pid, pgrp int) {
+	return syscall.Getpid(), syscall.Getpgrp()
+}
+
+func TestZeroSysProcAttr(t *testing.T) {
+	ppid, ppgrp := parent()
+
+	cmd := create(t)
+
+	cmd.Start()
+	defer cmd.Stop()
+
+	cpid, cpgrp := cmd.Info()
+
+	if cpid == ppid {
+		t.Fatalf("Parent and child have the same process ID")
+	}
+
+	if cpgrp != ppgrp {
+		t.Fatalf("Child is not in parent's process group")
+	}
+}
+
+func TestSetpgid(t *testing.T) {
+	ppid, ppgrp := parent()
+
+	cmd := create(t)
+
+	cmd.proc.SysProcAttr = &syscall.SysProcAttr{Setpgid: true}
+	cmd.Start()
+	defer cmd.Stop()
+
+	cpid, cpgrp := cmd.Info()
+
+	if cpid == ppid {
+		t.Fatalf("Parent and child have the same process ID")
+	}
+
+	if cpgrp == ppgrp {
+		t.Fatalf("Parent and child are in the same process group")
+	}
+
+	if cpid != cpgrp {
+		t.Fatalf("Child's process group is not the child's process ID")
+	}
+}
+
+func TestPgid(t *testing.T) {
+	ppid, ppgrp := parent()
+
+	cmd1 := create(t)
+
+	cmd1.proc.SysProcAttr = &syscall.SysProcAttr{Setpgid: true}
+	cmd1.Start()
+	defer cmd1.Stop()
+
+	cpid1, cpgrp1 := cmd1.Info()
+
+	if cpid1 == ppid {
+		t.Fatalf("Parent and child 1 have the same process ID")
+	}
+
+	if cpgrp1 == ppgrp {
+		t.Fatalf("Parent and child 1 are in the same process group")
+	}
+
+	if cpid1 != cpgrp1 {
+		t.Fatalf("Child 1's process group is not its process ID")
+	}
+
+	cmd2 := create(t)
+
+	cmd2.proc.SysProcAttr = &syscall.SysProcAttr{
+		Setpgid: true,
+		Pgid:    cpgrp1,
+	}
+	cmd2.Start()
+	defer cmd2.Stop()
+
+	cpid2, cpgrp2 := cmd2.Info()
+
+	if cpid2 == ppid {
+		t.Fatalf("Parent and child 2 have the same process ID")
+	}
+
+	if cpgrp2 == ppgrp {
+		t.Fatalf("Parent and child 2 are in the same process group")
+	}
+
+	if cpid2 == cpgrp2 {
+		t.Fatalf("Child 2's process group is its process ID")
+	}
+
+	if cpid1 == cpid2 {
+		t.Fatalf("Child 1 and 2 have the same process ID")
+	}
+
+	if cpgrp1 != cpgrp2 {
+		t.Fatalf("Child 1 and 2 are not in the same process group")
+	}
+}
+
+func TestForeground(t *testing.T) {
+	signal.Ignore(syscall.SIGTTIN, syscall.SIGTTOU)
+
+	tty, err := os.OpenFile("/dev/tty", os.O_RDWR, 0)
+	if err != nil {
+		t.Skipf("Can't test Foreground. Couldn't open /dev/tty: %s", err)
+	}
+
+	fpgrp := 0
+
+	errno := syscall.Ioctl(tty.Fd(), syscall.TIOCGPGRP, uintptr(unsafe.Pointer(&fpgrp)))
+	if errno != 0 {
+		t.Fatalf("TIOCGPGRP failed with error code: %s", errno)
+	}
+
+	if fpgrp == 0 {
+		t.Fatalf("Foreground process group is zero")
+	}
+
+	ppid, ppgrp := parent()
+
+	cmd := create(t)
+
+	cmd.proc.SysProcAttr = &syscall.SysProcAttr{
+		Ctty:       int(tty.Fd()),
+		Foreground: true,
+	}
+	cmd.Start()
+
+	cpid, cpgrp := cmd.Info()
+
+	if cpid == ppid {
+		t.Fatalf("Parent and child have the same process ID")
+	}
+
+	if cpgrp == ppgrp {
+		t.Fatalf("Parent and child are in the same process group")
+	}
+
+	if cpid != cpgrp {
+		t.Fatalf("Child's process group is not the child's process ID")
+	}
+
+	cmd.Stop()
+
+	errno = syscall.Ioctl(tty.Fd(), syscall.TIOCSPGRP, uintptr(unsafe.Pointer(&fpgrp)))
+	if errno != 0 {
+		t.Fatalf("TIOCSPGRP failed with error code: %s", errno)
+	}
+
+	signal.Reset()
+}
diff --git a/src/syscall/export_unix_test.go b/src/syscall/export_unix_test.go
new file mode 100644
index 0000000..b41fe2f
--- /dev/null
+++ b/src/syscall/export_unix_test.go
@@ -0,0 +1,12 @@
+// Copyright 2015 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.
+
+// +build darwin dragonfly freebsd linux netbsd openbsd
+
+package syscall
+
+func Ioctl(fd, req, arg uintptr) (err Errno) {
+	_, _, err = Syscall(SYS_IOCTL, fd, req, arg)
+	return err
+}
diff --git a/src/syscall/fs_nacl.go b/src/syscall/fs_nacl.go
index f52897e..711809f 100644
--- a/src/syscall/fs_nacl.go
+++ b/src/syscall/fs_nacl.go
@@ -772,29 +772,24 @@
 	return len(b), nil
 }
 
-type randomFile struct {
-	naclFD int
-}
+type randomFile struct{}
 
 func openRandom() (devFile, error) {
-	fd, err := openNamedService("SecureRandom", O_RDONLY)
-	if err != nil {
-		return nil, err
-	}
-	return &randomFile{naclFD: fd}, nil
+	return randomFile{}, nil
 }
 
-func (f *randomFile) close() error {
-	naclClose(f.naclFD)
-	f.naclFD = -1
+func (f randomFile) close() error {
 	return nil
 }
 
-func (f *randomFile) pread(b []byte, offset int64) (int, error) {
-	return naclRead(f.naclFD, b)
+func (f randomFile) pread(b []byte, offset int64) (int, error) {
+	if err := naclGetRandomBytes(b); err != nil {
+		return 0, err
+	}
+	return len(b), nil
 }
 
-func (f *randomFile) pwrite(b []byte, offset int64) (int, error) {
+func (f randomFile) pwrite(b []byte, offset int64) (int, error) {
 	return 0, EPERM
 }
 
diff --git a/src/syscall/mkall.sh b/src/syscall/mkall.sh
index f3bfeba..7709ebf 100755
--- a/src/syscall/mkall.sh
+++ b/src/syscall/mkall.sh
@@ -177,6 +177,17 @@
 	mksysnum="curl -s 'http://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/plain/arch/arm/include/uapi/asm/unistd.h' | ./mksysnum_linux.pl"
 	mktypes="GOARCH=$GOARCH go tool cgo -godefs"
 	;;
+linux_arm64)
+	unistd_h=$(ls -1 /usr/include/asm/unistd.h /usr/include/asm-generic/unistd.h 2>/dev/null | head -1)
+	if [ "$unistd_h" = "" ]; then
+		echo >&2 cannot find unistd_64.h
+		exit 1
+	fi
+	mksysnum="./mksysnum_linux.pl $unistd_h"
+	# Let the type of C char be singed for making the bare syscall
+	# API consistent across over platforms.
+	mktypes="GOARCH=$GOARCH go tool cgo -godefs -- -fsigned-char"
+	;;
 linux_ppc64)
 	GOOSARCH_in=syscall_linux_ppc64x.go
 	unistd_h=/usr/include/asm/unistd.h
@@ -220,7 +231,7 @@
 	mksyscall="./mksyscall.pl -l32 -openbsd"
 	mksysctl="./mksysctl_openbsd.pl"
 	zsysctl="zsysctl_openbsd.go"
-	mksysnum="curl -s 'http://www.openbsd.org/cgi-bin/cvsweb/~checkout~/src/sys/kern/syscalls.master' | ./mksysnum_openbsd.pl"
+	mksysnum="curl -s 'http://cvsweb.openbsd.org/cgi-bin/cvsweb/~checkout~/src/sys/kern/syscalls.master' | ./mksysnum_openbsd.pl"
 	mktypes="GOARCH=$GOARCH go tool cgo -godefs"
 	;;
 openbsd_amd64)
@@ -228,7 +239,15 @@
 	mksyscall="./mksyscall.pl -openbsd"
 	mksysctl="./mksysctl_openbsd.pl"
 	zsysctl="zsysctl_openbsd.go"
-	mksysnum="curl -s 'http://www.openbsd.org/cgi-bin/cvsweb/~checkout~/src/sys/kern/syscalls.master' | ./mksysnum_openbsd.pl"
+	mksysnum="curl -s 'http://cvsweb.openbsd.org/cgi-bin/cvsweb/~checkout~/src/sys/kern/syscalls.master' | ./mksysnum_openbsd.pl"
+	mktypes="GOARCH=$GOARCH go tool cgo -godefs"
+	;;
+openbsd_arm)
+	mkerrors="$mkerrors"
+	mksyscall="./mksyscall.pl -l32 -openbsd -arm"
+	mksysctl="./mksysctl_openbsd.pl"
+	zsysctl="zsysctl_openbsd.go"
+	mksysnum="curl -s 'http://cvsweb.openbsd.org/cgi-bin/cvsweb/~checkout~/src/sys/kern/syscalls.master' | ./mksysnum_openbsd.pl"
 	mktypes="GOARCH=$GOARCH go tool cgo -godefs"
 	;;
 plan9_386)
diff --git a/src/syscall/mkerrors.sh b/src/syscall/mkerrors.sh
index 4711f30..d25527b 100755
--- a/src/syscall/mkerrors.sh
+++ b/src/syscall/mkerrors.sh
@@ -121,6 +121,14 @@
 #ifndef MSG_FASTOPEN
 #define MSG_FASTOPEN    0x20000000
 #endif
+
+#ifndef PTRACE_GETREGS
+#define PTRACE_GETREGS	0xc
+#endif
+
+#ifndef PTRACE_SETREGS
+#define PTRACE_SETREGS	0xd
+#endif
 '
 
 includes_NetBSD='
diff --git a/src/syscall/mksyscall.pl b/src/syscall/mksyscall.pl
index dff9138..96437fe 100755
--- a/src/syscall/mksyscall.pl
+++ b/src/syscall/mksyscall.pl
@@ -292,7 +292,7 @@
 		$text .= "\t}\n";
 	} elsif ($do_errno) {
 		$text .= "\tif e1 != 0 {\n";
-		$text .= "\t\terr = e1\n";
+		$text .= "\t\terr = errnoErr(e1)\n";
 		$text .= "\t}\n";
 	}
 	$text .= "\treturn\n";
diff --git a/src/syscall/mksyscall_solaris.pl b/src/syscall/mksyscall_solaris.pl
index e72a4d1..3f52aa4 100755
--- a/src/syscall/mksyscall_solaris.pl
+++ b/src/syscall/mksyscall_solaris.pl
@@ -248,7 +248,7 @@
 
 	if ($do_errno) {
 		$text .= "\tif e1 != 0 {\n";
-		$text .= "\t\terr = e1\n";
+		$text .= "\t\terr = errnoErr(e1)\n";
 		$text .= "\t}\n";
 	}
 	$text .= "\treturn\n";
diff --git a/src/syscall/mksysnum_linux.pl b/src/syscall/mksysnum_linux.pl
index c7e5cf7..7a8add8 100755
--- a/src/syscall/mksysnum_linux.pl
+++ b/src/syscall/mksysnum_linux.pl
@@ -18,13 +18,25 @@
 
 sub fmt {
 	my ($name, $num) = @_;
+	if($num > 999){
+		# ignore depricated syscalls that are no longer implemented
+		# https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/tree/include/uapi/asm-generic/unistd.h?id=refs/heads/master#n716
+		return;
+	}
 	$name =~ y/a-z/A-Z/;
 	print "	SYS_$name = $num;\n";
 }
 
 my $prev;
 while(<>){
-	if(/^#define __NR_(\w+)\s+([0-9]+)/){
+	if(/^#define __NR_syscalls\s+/) {
+		# ignore redefinitions of __NR_syscalls
+	}
+	elsif(/^#define __NR_(\w+)\s+([0-9]+)/){
+		$prev = $2;
+		fmt($1, $2);
+	}
+	elsif(/^#define __NR3264_(\w+)\s+([0-9]+)/){
 		$prev = $2;
 		fmt($1, $2);
 	}
diff --git a/src/syscall/route_bsd.go b/src/syscall/route_bsd.go
index bc5de69..a55198b 100644
--- a/src/syscall/route_bsd.go
+++ b/src/syscall/route_bsd.go
@@ -140,8 +140,14 @@
 	if len(b) < l {
 		return nil, EINVAL
 	}
-	switch family {
-	case AF_INET6:
+	// Don't reorder case expressions.
+	// The case expressions for IPv6 must come first.
+	switch {
+	case b[0] == SizeofSockaddrInet6:
+		sa := &SockaddrInet6{}
+		copy(sa.Addr[:], b[offsetofInet6:])
+		return sa, nil
+	case family == AF_INET6:
 		sa := &SockaddrInet6{}
 		if l-1 < offsetofInet6 {
 			copy(sa.Addr[:], b[1:l])
@@ -149,6 +155,10 @@
 			copy(sa.Addr[:], b[l-offsetofInet6:l])
 		}
 		return sa, nil
+	case b[0] == SizeofSockaddrInet4:
+		sa := &SockaddrInet4{}
+		copy(sa.Addr[:], b[offsetofInet4:])
+		return sa, nil
 	default: // an old fashion, AF_UNSPEC or unknown means AF_INET
 		sa := &SockaddrInet4{}
 		if l-1 < offsetofInet4 {
diff --git a/src/syscall/route_bsd_test.go b/src/syscall/route_bsd_test.go
index 471f4a2..8617663 100644
--- a/src/syscall/route_bsd_test.go
+++ b/src/syscall/route_bsd_test.go
@@ -18,7 +18,18 @@
 func TestRouteRIB(t *testing.T) {
 	for _, facility := range []int{syscall.NET_RT_DUMP, syscall.NET_RT_IFLIST} {
 		for _, param := range []int{syscall.AF_UNSPEC, syscall.AF_INET, syscall.AF_INET6} {
-			b, err := syscall.RouteRIB(facility, param)
+			var err error
+			var b []byte
+			// The VM allocator wrapper functions can
+			// return ENOMEM easily.
+			for i := 0; i < 3; i++ {
+				b, err = syscall.RouteRIB(facility, param)
+				if err != nil {
+					time.Sleep(5 * time.Millisecond)
+					continue
+				}
+				break
+			}
 			if err != nil {
 				t.Error(facility, param, err)
 				continue
@@ -185,10 +196,27 @@
 
 func (sas sockaddrs) match(flags addrFlags) error {
 	var f addrFlags
+	family := syscall.AF_UNSPEC
 	for i := range sas {
 		if sas[i] != nil {
 			f |= 1 << uint(i)
 		}
+		switch sas[i].(type) {
+		case *syscall.SockaddrInet4:
+			if family == syscall.AF_UNSPEC {
+				family = syscall.AF_INET
+			}
+			if family != syscall.AF_INET {
+				return fmt.Errorf("got %v; want %v", sockaddrs(sas), family)
+			}
+		case *syscall.SockaddrInet6:
+			if family == syscall.AF_UNSPEC {
+				family = syscall.AF_INET6
+			}
+			if family != syscall.AF_INET6 {
+				return fmt.Errorf("got %v; want %v", sockaddrs(sas), family)
+			}
+		}
 	}
 	if f != flags {
 		return fmt.Errorf("got %v; want %v", f, flags)
diff --git a/src/syscall/syscall_darwin.go b/src/syscall/syscall_darwin.go
index f026a56..52fd4e7 100644
--- a/src/syscall/syscall_darwin.go
+++ b/src/syscall/syscall_darwin.go
@@ -222,8 +222,8 @@
 //sys	Chown(path string, uid int, gid int) (err error)
 //sys	Chroot(path string) (err error)
 //sys	Close(fd int) (err error)
-//sysnb	Dup(fd int) (nfd int, err error)
-//sysnb	Dup2(from int, to int) (err error)
+//sys	Dup(fd int) (nfd int, err error)
+//sys	Dup2(from int, to int) (err error)
 //sys	Exchangedata(path1 string, path2 string, options int) (err error)
 //sys	Exit(code int)
 //sys	Fchdir(fd int) (err error)
diff --git a/src/syscall/syscall_darwin_amd64.go b/src/syscall/syscall_darwin_amd64.go
index 81b1fd3..70b53b8 100644
--- a/src/syscall/syscall_darwin_amd64.go
+++ b/src/syscall/syscall_darwin_amd64.go
@@ -67,4 +67,4 @@
 	return
 }
 
-func Syscall9(num, a1, a2, a3, a4, a5, a6, a7, a8, a9 uintptr) (r1, r2 uintptr, err Errno) // sic
+func Syscall9(trap, a1, a2, a3, a4, a5, a6, a7, a8, a9 uintptr) (r1, r2 uintptr, err Errno)
diff --git a/src/syscall/syscall_dragonfly.go b/src/syscall/syscall_dragonfly.go
index 39c51df..c25963c 100644
--- a/src/syscall/syscall_dragonfly.go
+++ b/src/syscall/syscall_dragonfly.go
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// FreeBSD system calls.
+// DragonflyBSD system calls.
 // This file is compiled as ordinary Go code,
 // but it is also input to mksyscall,
 // which parses the //sys lines and generates system call stubs.
@@ -127,8 +127,8 @@
 //sys	Chown(path string, uid int, gid int) (err error)
 //sys	Chroot(path string) (err error)
 //sys	Close(fd int) (err error)
-//sysnb	Dup(fd int) (nfd int, err error)
-//sysnb	Dup2(from int, to int) (err error)
+//sys	Dup(fd int) (nfd int, err error)
+//sys	Dup2(from int, to int) (err error)
 //sys	Exit(code int)
 //sys	Fchdir(fd int) (err error)
 //sys	Fchflags(fd int, flags int) (err error)
diff --git a/src/syscall/syscall_freebsd.go b/src/syscall/syscall_freebsd.go
index 3d834f5..257d419 100644
--- a/src/syscall/syscall_freebsd.go
+++ b/src/syscall/syscall_freebsd.go
@@ -147,8 +147,8 @@
 //sys	Chown(path string, uid int, gid int) (err error)
 //sys	Chroot(path string) (err error)
 //sys	Close(fd int) (err error)
-//sysnb	Dup(fd int) (nfd int, err error)
-//sysnb	Dup2(from int, to int) (err error)
+//sys	Dup(fd int) (nfd int, err error)
+//sys	Dup2(from int, to int) (err error)
 //sys	Exit(code int)
 //sys	Fchdir(fd int) (err error)
 //sys	Fchflags(fd int, flags int) (err error)
diff --git a/src/syscall/syscall_linux.go b/src/syscall/syscall_linux.go
index 813ef28..05d4044 100644
--- a/src/syscall/syscall_linux.go
+++ b/src/syscall/syscall_linux.go
@@ -820,8 +820,8 @@
 //sys	Chdir(path string) (err error)
 //sys	Chroot(path string) (err error)
 //sys	Close(fd int) (err error)
-//sysnb	Dup(oldfd int) (fd int, err error)
-//sysnb	Dup3(oldfd int, newfd int, flags int) (err error)
+//sys	Dup(oldfd int) (fd int, err error)
+//sys	Dup3(oldfd int, newfd int, flags int) (err error)
 //sysnb	EpollCreate(size int) (fd int, err error)
 //sysnb	EpollCreate1(flag int) (fd int, err error)
 //sysnb	EpollCtl(epfd int, op int, fd int, event *EpollEvent) (err error)
@@ -839,7 +839,12 @@
 //sys	Fsync(fd int) (err error)
 //sys	Getdents(fd int, buf []byte) (n int, err error) = SYS_GETDENTS64
 //sysnb	Getpgid(pid int) (pgid int, err error)
-//sysnb	Getpgrp() (pid int)
+
+func Getpgrp() (pid int) {
+	pid, _ = Getpgid(0)
+	return
+}
+
 //sysnb	Getpid() (pid int)
 //sysnb	Getppid() (ppid int)
 //sys	Getpriority(which int, who int) (prio int, err error)
diff --git a/src/syscall/syscall_linux_386.go b/src/syscall/syscall_linux_386.go
index 0dcc6be..98636a5 100644
--- a/src/syscall/syscall_linux_386.go
+++ b/src/syscall/syscall_linux_386.go
@@ -9,6 +9,8 @@
 
 import "unsafe"
 
+const _SYS_dup = SYS_DUP2
+
 func Getpagesize() int { return 4096 }
 
 func TimespecToNsec(ts Timespec) int64 { return int64(ts.Sec)*1e9 + int64(ts.Nsec) }
@@ -56,7 +58,7 @@
 
 // 64-bit file system and 32-bit uid calls
 // (386 default is 32-bit file system and 16-bit uid).
-//sysnb	Dup2(oldfd int, newfd int) (err error)
+//sys	Dup2(oldfd int, newfd int) (err error)
 //sys	Fchown(fd int, uid int, gid int) (err error) = SYS_FCHOWN32
 //sys	Fstat(fd int, stat *Stat_t) (err error) = SYS_FSTAT64
 //sys	Ftruncate(fd int, length int64) (err error) = SYS_FTRUNCATE64
diff --git a/src/syscall/syscall_linux_amd64.go b/src/syscall/syscall_linux_amd64.go
index 8d0777c..4111c07 100644
--- a/src/syscall/syscall_linux_amd64.go
+++ b/src/syscall/syscall_linux_amd64.go
@@ -4,7 +4,9 @@
 
 package syscall
 
-//sysnb	Dup2(oldfd int, newfd int) (err error)
+const _SYS_dup = SYS_DUP2
+
+//sys	Dup2(oldfd int, newfd int) (err error)
 //sys	Fchown(fd int, uid int, gid int) (err error)
 //sys	Fstat(fd int, stat *Stat_t) (err error)
 //sys	Fstatfs(fd int, buf *Statfs_t) (err error)
diff --git a/src/syscall/syscall_linux_arm.go b/src/syscall/syscall_linux_arm.go
index ebbaa17..f0cc25e 100644
--- a/src/syscall/syscall_linux_arm.go
+++ b/src/syscall/syscall_linux_arm.go
@@ -6,6 +6,8 @@
 
 import "unsafe"
 
+const _SYS_dup = SYS_DUP2
+
 func Getpagesize() int { return 4096 }
 
 func TimespecToNsec(ts Timespec) int64 { return int64(ts.Sec)*1e9 + int64(ts.Nsec) }
@@ -78,7 +80,7 @@
 
 // 64-bit file system and 32-bit uid calls
 // (16-bit uid calls are not always supported in newer kernels)
-//sysnb	Dup2(oldfd int, newfd int) (err error)
+//sys	Dup2(oldfd int, newfd int) (err error)
 //sys	Fchown(fd int, uid int, gid int) (err error) = SYS_FCHOWN32
 //sys	Fstat(fd int, stat *Stat_t) (err error) = SYS_FSTAT64
 //sysnb	Getegid() (egid int) = SYS_GETEGID32
diff --git a/src/syscall/syscall_linux_arm64.go b/src/syscall/syscall_linux_arm64.go
new file mode 100644
index 0000000..3c4eabc
--- /dev/null
+++ b/src/syscall/syscall_linux_arm64.go
@@ -0,0 +1,142 @@
+// Copyright 2015 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 syscall
+
+const _SYS_dup = SYS_DUP3
+
+//sys	Fchown(fd int, uid int, gid int) (err error)
+//sys	Fstat(fd int, stat *Stat_t) (err error)
+//sys	Fstatat(fd int, path string, stat *Stat_t, flags int) (err error)
+//sys	Fstatfs(fd int, buf *Statfs_t) (err error)
+//sys	Ftruncate(fd int, length int64) (err error)
+//sysnb	Getegid() (egid int)
+//sysnb	Geteuid() (euid int)
+//sysnb	Getgid() (gid int)
+//sysnb	Getrlimit(resource int, rlim *Rlimit) (err error)
+//sysnb	Getuid() (uid int)
+//sys	Lchown(path string, uid int, gid int) (err error)
+//sys	Listen(s int, n int) (err error)
+//sys	Pread(fd int, p []byte, offset int64) (n int, err error) = SYS_PREAD64
+//sys	Pwrite(fd int, p []byte, offset int64) (n int, err error) = SYS_PWRITE64
+//sys	Seek(fd int, offset int64, whence int) (off int64, err error) = SYS_LSEEK
+//sys	Select(nfd int, r *FdSet, w *FdSet, e *FdSet, timeout *Timeval) (n int, err error) = SYS_PSELECT6
+//sys	sendfile(outfd int, infd int, offset *int64, count int) (written int, err error)
+//sys	Setfsgid(gid int) (err error)
+//sys	Setfsuid(uid int) (err error)
+//sysnb	Setregid(rgid int, egid int) (err error)
+//sysnb	Setresgid(rgid int, egid int, sgid int) (err error)
+//sysnb	Setresuid(ruid int, euid int, suid int) (err error)
+//sysnb	Setrlimit(resource int, rlim *Rlimit) (err error)
+//sysnb	Setreuid(ruid int, euid int) (err error)
+//sys	Shutdown(fd int, how int) (err error)
+//sys	Splice(rfd int, roff *int64, wfd int, woff *int64, len int, flags int) (n int64, err error)
+
+func Stat(path string, stat *Stat_t) (err error) {
+	return Fstatat(_AT_FDCWD, path, stat, 0)
+}
+
+func Lstat(path string, stat *Stat_t) (err error) {
+	return Fstatat(_AT_FDCWD, path, stat, _AT_SYMLINK_NOFOLLOW)
+}
+
+//sys	Statfs(path string, buf *Statfs_t) (err error)
+//sys	SyncFileRange(fd int, off int64, n int64, flags int) (err error) = SYS_SYNC_FILE_RANGE2
+//sys	Truncate(path string, length int64) (err error)
+//sys	accept(s int, rsa *RawSockaddrAny, addrlen *_Socklen) (fd int, err error)
+//sys	accept4(s int, rsa *RawSockaddrAny, addrlen *_Socklen, flags int) (fd int, err error)
+//sys	bind(s int, addr unsafe.Pointer, addrlen _Socklen) (err error)
+//sys	connect(s int, addr unsafe.Pointer, addrlen _Socklen) (err error)
+//sysnb	getgroups(n int, list *_Gid_t) (nn int, err error)
+//sysnb	setgroups(n int, list *_Gid_t) (err error)
+//sys	getsockopt(s int, level int, name int, val unsafe.Pointer, vallen *_Socklen) (err error)
+//sys	setsockopt(s int, level int, name int, val unsafe.Pointer, vallen uintptr) (err error)
+//sysnb	socket(domain int, typ int, proto int) (fd int, err error)
+//sysnb	socketpair(domain int, typ int, proto int, fd *[2]int32) (err error)
+//sysnb	getpeername(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (err error)
+//sysnb	getsockname(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (err error)
+//sys	recvfrom(fd int, p []byte, flags int, from *RawSockaddrAny, fromlen *_Socklen) (n int, err error)
+//sys	sendto(s int, buf []byte, flags int, to unsafe.Pointer, addrlen _Socklen) (err error)
+//sys	recvmsg(s int, msg *Msghdr, flags int) (n int, err error)
+//sys	sendmsg(s int, msg *Msghdr, flags int) (n int, err error)
+//sys	mmap(addr uintptr, length uintptr, prot int, flags int, fd int, offset int64) (xaddr uintptr, err error)
+
+func Getpagesize() int { return 65536 }
+
+//sysnb	Gettimeofday(tv *Timeval) (err error)
+//sysnb	Time(t *Time_t) (tt Time_t, err error)
+
+func TimespecToNsec(ts Timespec) int64 { return int64(ts.Sec)*1e9 + int64(ts.Nsec) }
+
+func NsecToTimespec(nsec int64) (ts Timespec) {
+	ts.Sec = nsec / 1e9
+	ts.Nsec = nsec % 1e9
+	return
+}
+
+func TimevalToNsec(tv Timeval) int64 { return int64(tv.Sec)*1e9 + int64(tv.Usec)*1e3 }
+
+func NsecToTimeval(nsec int64) (tv Timeval) {
+	nsec += 999 // round up to microsecond
+	tv.Sec = nsec / 1e9
+	tv.Usec = nsec % 1e9 / 1e3
+	return
+}
+
+func Pipe(p []int) (err error) {
+	if len(p) != 2 {
+		return EINVAL
+	}
+	var pp [2]_C_int
+	err = pipe2(&pp, 0)
+	p[0] = int(pp[0])
+	p[1] = int(pp[1])
+	return
+}
+
+//sysnb pipe2(p *[2]_C_int, flags int) (err error)
+
+func Pipe2(p []int, flags int) (err error) {
+	if len(p) != 2 {
+		return EINVAL
+	}
+	var pp [2]_C_int
+	err = pipe2(&pp, flags)
+	p[0] = int(pp[0])
+	p[1] = int(pp[1])
+	return
+}
+
+func (r *PtraceRegs) PC() uint64 { return r.Pc }
+
+func (r *PtraceRegs) SetPC(pc uint64) { r.Pc = pc }
+
+func (iov *Iovec) SetLen(length int) {
+	iov.Len = uint64(length)
+}
+
+func (msghdr *Msghdr) SetControllen(length int) {
+	msghdr.Controllen = uint64(length)
+}
+
+func (cmsg *Cmsghdr) SetLen(length int) {
+	cmsg.Len = uint64(length)
+}
+
+// TODO(dfc): constants that should be in zsysnum_linux_arm64.go, remove
+// these when the deprecated syscalls that the syscall package relies on
+// are removed.
+const (
+	SYS_INOTIFY_INIT = 1043
+	SYS_GETPGRP      = 1060
+	SYS_UTIMES       = 1037
+	SYS_FUTIMESAT    = 1066
+	SYS_PAUSE        = 1061
+	SYS_USTAT        = 1070
+	SYS_UTIME        = 1063
+	SYS_LCHOWN       = 1032
+	SYS_TIME         = 1062
+	SYS_EPOLL_CREATE = 1042
+	SYS_EPOLL_WAIT   = 1069
+)
diff --git a/src/syscall/syscall_linux_ppc64x.go b/src/syscall/syscall_linux_ppc64x.go
index c266c85..5318c61 100644
--- a/src/syscall/syscall_linux_ppc64x.go
+++ b/src/syscall/syscall_linux_ppc64x.go
@@ -7,7 +7,9 @@
 
 package syscall
 
-//sysnb	Dup2(oldfd int, newfd int) (err error)
+const _SYS_dup = SYS_DUP2
+
+//sys	Dup2(oldfd int, newfd int) (err error)
 //sys	Fchown(fd int, uid int, gid int) (err error)
 //sys	Fstat(fd int, stat *Stat_t) (err error)
 //sys	Fstatfs(fd int, buf *Statfs_t) (err error)
diff --git a/src/syscall/syscall_nacl.go b/src/syscall/syscall_nacl.go
index c2788b2..f8f63ef 100644
--- a/src/syscall/syscall_nacl.go
+++ b/src/syscall/syscall_nacl.go
@@ -14,6 +14,7 @@
 //sys	naclFstat(fd int, stat *Stat_t) (err error) = sys_fstat
 //sys	naclRead(fd int, b []byte) (n int, err error) = sys_read
 //sys	naclSeek(fd int, off *int64, whence int) (err error) = sys_lseek
+//sys	naclGetRandomBytes(b []byte) (err error) = sys_get_random_bytes
 
 const direntSize = 8 + 8 + 2 + 256
 
diff --git a/src/syscall/syscall_netbsd.go b/src/syscall/syscall_netbsd.go
index 9781271..7fd6e2b 100644
--- a/src/syscall/syscall_netbsd.go
+++ b/src/syscall/syscall_netbsd.go
@@ -148,8 +148,8 @@
 //sys	Chown(path string, uid int, gid int) (err error)
 //sys	Chroot(path string) (err error)
 //sys	Close(fd int) (err error)
-//sysnb	Dup(fd int) (nfd int, err error)
-//sysnb	Dup2(from int, to int) (err error)
+//sys	Dup(fd int) (nfd int, err error)
+//sys	Dup2(from int, to int) (err error)
 //sys	Exit(code int)
 //sys	Fchdir(fd int) (err error)
 //sys	Fchflags(fd int, flags int) (err error)
diff --git a/src/syscall/syscall_openbsd.go b/src/syscall/syscall_openbsd.go
index 8d3f825..e196e59 100644
--- a/src/syscall/syscall_openbsd.go
+++ b/src/syscall/syscall_openbsd.go
@@ -126,8 +126,8 @@
 //sys	Chown(path string, uid int, gid int) (err error)
 //sys	Chroot(path string) (err error)
 //sys	Close(fd int) (err error)
-//sysnb	Dup(fd int) (nfd int, err error)
-//sysnb	Dup2(from int, to int) (err error)
+//sys	Dup(fd int) (nfd int, err error)
+//sys	Dup2(from int, to int) (err error)
 //sys	Exit(code int)
 //sys	Fchdir(fd int) (err error)
 //sys	Fchflags(fd int, flags int) (err error)
diff --git a/src/syscall/syscall_dragonfly_386.go b/src/syscall/syscall_openbsd_arm.go
similarity index 64%
rename from src/syscall/syscall_dragonfly_386.go
rename to src/syscall/syscall_openbsd_arm.go
index ebd3d4c..ad5ae14 100644
--- a/src/syscall/syscall_dragonfly_386.go
+++ b/src/syscall/syscall_openbsd_arm.go
@@ -4,14 +4,12 @@
 
 package syscall
 
-import "unsafe"
-
 func Getpagesize() int { return 4096 }
 
 func TimespecToNsec(ts Timespec) int64 { return int64(ts.Sec)*1e9 + int64(ts.Nsec) }
 
 func NsecToTimespec(nsec int64) (ts Timespec) {
-	ts.Sec = int32(nsec / 1e9)
+	ts.Sec = int64(nsec / 1e9)
 	ts.Nsec = int32(nsec % 1e9)
 	return
 }
@@ -21,7 +19,7 @@
 func NsecToTimeval(nsec int64) (tv Timeval) {
 	nsec += 999 // round up to microsecond
 	tv.Usec = int32(nsec % 1e9 / 1e3)
-	tv.Sec = int32(nsec / 1e9)
+	tv.Sec = int64(nsec / 1e9)
 	return
 }
 
@@ -42,17 +40,3 @@
 func (cmsg *Cmsghdr) SetLen(length int) {
 	cmsg.Len = uint32(length)
 }
-
-func sendfile(outfd int, infd int, offset *int64, count int) (written int, err error) {
-	var writtenOut uint64 = 0
-	_, _, e1 := Syscall9(SYS_SENDFILE, uintptr(infd), uintptr(outfd), uintptr(*offset), uintptr((*offset)>>32), uintptr(count), 0, uintptr(unsafe.Pointer(&writtenOut)), 0, 0)
-
-	written = int(writtenOut)
-
-	if e1 != 0 {
-		err = e1
-	}
-	return
-}
-
-func Syscall9(num, a1, a2, a3, a4, a5, a6, a7, a8, a9 uintptr) (r1, r2 uintptr, err Errno) // sic
diff --git a/src/syscall/syscall_unix.go b/src/syscall/syscall_unix.go
index a06bd7d..b133ea7 100644
--- a/src/syscall/syscall_unix.go
+++ b/src/syscall/syscall_unix.go
@@ -116,6 +116,30 @@
 	return e == EAGAIN || e == EWOULDBLOCK || e == ETIMEDOUT
 }
 
+// Do the interface allocations only once for common
+// Errno values.
+var (
+	errEAGAIN error = EAGAIN
+	errEINVAL error = EINVAL
+	errENOENT error = ENOENT
+)
+
+// errnoErr returns common boxed Errno values, to prevent
+// allocations at runtime.
+func errnoErr(e Errno) error {
+	switch e {
+	case 0:
+		return nil
+	case EAGAIN:
+		return errEAGAIN
+	case EINVAL:
+		return errEINVAL
+	case ENOENT:
+		return errENOENT
+	}
+	return e
+}
+
 // A Signal is a number describing a process signal.
 // It implements the os.Signal interface.
 type Signal int
diff --git a/src/syscall/tables_nacl.go b/src/syscall/tables_nacl.go
index 08f4ced..adc6be2 100644
--- a/src/syscall/tables_nacl.go
+++ b/src/syscall/tables_nacl.go
@@ -15,10 +15,10 @@
 	sys_read                 = 12
 	sys_write                = 13
 	sys_lseek                = 14
-	sys_ioctl                = 15
 	sys_stat                 = 16
 	sys_fstat                = 17
 	sys_chmod                = 18
+	sys_isatty               = 19
 	sys_brk                  = 20
 	sys_mmap                 = 21
 	sys_munmap               = 22
@@ -76,6 +76,19 @@
 	sys_test_crash           = 110
 	sys_test_syscall_1       = 111
 	sys_test_syscall_2       = 112
+	sys_futex_wait_abs       = 120
+	sys_futex_wake           = 121
+	sys_pread                = 130
+	sys_pwrite               = 131
+	sys_truncate             = 140
+	sys_lstat                = 141
+	sys_link                 = 142
+	sys_rename               = 143
+	sys_symlink              = 144
+	sys_access               = 145
+	sys_readlink             = 146
+	sys_utimes               = 147
+	sys_get_random_bytes     = 150
 )
 
 // TODO: Auto-generate some day. (Hard-coded in binaries so not likely to change.)
@@ -322,3 +335,27 @@
 	ENOSHARE:        "No such host or network path",
 	ECASECLASH:      "Filename exists with different case",
 }
+
+// Do the interface allocations only once for common
+// Errno values.
+var (
+	errEAGAIN error = EAGAIN
+	errEINVAL error = EINVAL
+	errENOENT error = ENOENT
+)
+
+// errnoErr returns common boxed Errno values, to prevent
+// allocations at runtime.
+func errnoErr(e Errno) error {
+	switch e {
+	case 0:
+		return nil
+	case EAGAIN:
+		return errEAGAIN
+	case EINVAL:
+		return errEINVAL
+	case ENOENT:
+		return errENOENT
+	}
+	return e
+}
diff --git a/src/syscall/types_linux.go b/src/syscall/types_linux.go
index 1fec1bc..0ebdc7c 100644
--- a/src/syscall/types_linux.go
+++ b/src/syscall/types_linux.go
@@ -87,6 +87,8 @@
 
 #ifdef __ARM_EABI__
 typedef struct user_regs PtraceRegs;
+#elif defined(__aarch64__)
+typedef struct user_pt_regs PtraceRegs;
 #elif defined(__powerpc64__)
 typedef struct pt_regs PtraceRegs;
 #else
diff --git a/src/syscall/zerrors_linux_arm64.go b/src/syscall/zerrors_linux_arm64.go
new file mode 100644
index 0000000..f3d708b
--- /dev/null
+++ b/src/syscall/zerrors_linux_arm64.go
@@ -0,0 +1,1822 @@
+// mkerrors.sh
+// MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
+
+// Created by cgo -godefs - DO NOT EDIT
+// cgo -godefs -- _const.go
+
+package syscall
+
+const (
+	AF_ALG                           = 0x26
+	AF_APPLETALK                     = 0x5
+	AF_ASH                           = 0x12
+	AF_ATMPVC                        = 0x8
+	AF_ATMSVC                        = 0x14
+	AF_AX25                          = 0x3
+	AF_BLUETOOTH                     = 0x1f
+	AF_BRIDGE                        = 0x7
+	AF_CAIF                          = 0x25
+	AF_CAN                           = 0x1d
+	AF_DECnet                        = 0xc
+	AF_ECONET                        = 0x13
+	AF_FILE                          = 0x1
+	AF_IEEE802154                    = 0x24
+	AF_INET                          = 0x2
+	AF_INET6                         = 0xa
+	AF_IPX                           = 0x4
+	AF_IRDA                          = 0x17
+	AF_ISDN                          = 0x22
+	AF_IUCV                          = 0x20
+	AF_KEY                           = 0xf
+	AF_LLC                           = 0x1a
+	AF_LOCAL                         = 0x1
+	AF_MAX                           = 0x29
+	AF_NETBEUI                       = 0xd
+	AF_NETLINK                       = 0x10
+	AF_NETROM                        = 0x6
+	AF_NFC                           = 0x27
+	AF_PACKET                        = 0x11
+	AF_PHONET                        = 0x23
+	AF_PPPOX                         = 0x18
+	AF_RDS                           = 0x15
+	AF_ROSE                          = 0xb
+	AF_ROUTE                         = 0x10
+	AF_RXRPC                         = 0x21
+	AF_SECURITY                      = 0xe
+	AF_SNA                           = 0x16
+	AF_TIPC                          = 0x1e
+	AF_UNIX                          = 0x1
+	AF_UNSPEC                        = 0x0
+	AF_VSOCK                         = 0x28
+	AF_WANPIPE                       = 0x19
+	AF_X25                           = 0x9
+	ARPHRD_ADAPT                     = 0x108
+	ARPHRD_APPLETLK                  = 0x8
+	ARPHRD_ARCNET                    = 0x7
+	ARPHRD_ASH                       = 0x30d
+	ARPHRD_ATM                       = 0x13
+	ARPHRD_AX25                      = 0x3
+	ARPHRD_BIF                       = 0x307
+	ARPHRD_CAIF                      = 0x336
+	ARPHRD_CAN                       = 0x118
+	ARPHRD_CHAOS                     = 0x5
+	ARPHRD_CISCO                     = 0x201
+	ARPHRD_CSLIP                     = 0x101
+	ARPHRD_CSLIP6                    = 0x103
+	ARPHRD_DDCMP                     = 0x205
+	ARPHRD_DLCI                      = 0xf
+	ARPHRD_ECONET                    = 0x30e
+	ARPHRD_EETHER                    = 0x2
+	ARPHRD_ETHER                     = 0x1
+	ARPHRD_EUI64                     = 0x1b
+	ARPHRD_FCAL                      = 0x311
+	ARPHRD_FCFABRIC                  = 0x313
+	ARPHRD_FCPL                      = 0x312
+	ARPHRD_FCPP                      = 0x310
+	ARPHRD_FDDI                      = 0x306
+	ARPHRD_FRAD                      = 0x302
+	ARPHRD_HDLC                      = 0x201
+	ARPHRD_HIPPI                     = 0x30c
+	ARPHRD_HWX25                     = 0x110
+	ARPHRD_IEEE1394                  = 0x18
+	ARPHRD_IEEE802                   = 0x6
+	ARPHRD_IEEE80211                 = 0x321
+	ARPHRD_IEEE80211_PRISM           = 0x322
+	ARPHRD_IEEE80211_RADIOTAP        = 0x323
+	ARPHRD_IEEE802154                = 0x324
+	ARPHRD_IEEE802154_MONITOR        = 0x325
+	ARPHRD_IEEE802_TR                = 0x320
+	ARPHRD_INFINIBAND                = 0x20
+	ARPHRD_IP6GRE                    = 0x337
+	ARPHRD_IPDDP                     = 0x309
+	ARPHRD_IPGRE                     = 0x30a
+	ARPHRD_IRDA                      = 0x30f
+	ARPHRD_LAPB                      = 0x204
+	ARPHRD_LOCALTLK                  = 0x305
+	ARPHRD_LOOPBACK                  = 0x304
+	ARPHRD_METRICOM                  = 0x17
+	ARPHRD_NETLINK                   = 0x338
+	ARPHRD_NETROM                    = 0x0
+	ARPHRD_NONE                      = 0xfffe
+	ARPHRD_PHONET                    = 0x334
+	ARPHRD_PHONET_PIPE               = 0x335
+	ARPHRD_PIMREG                    = 0x30b
+	ARPHRD_PPP                       = 0x200
+	ARPHRD_PRONET                    = 0x4
+	ARPHRD_RAWHDLC                   = 0x206
+	ARPHRD_ROSE                      = 0x10e
+	ARPHRD_RSRVD                     = 0x104
+	ARPHRD_SIT                       = 0x308
+	ARPHRD_SKIP                      = 0x303
+	ARPHRD_SLIP                      = 0x100
+	ARPHRD_SLIP6                     = 0x102
+	ARPHRD_TUNNEL                    = 0x300
+	ARPHRD_TUNNEL6                   = 0x301
+	ARPHRD_VOID                      = 0xffff
+	ARPHRD_X25                       = 0x10f
+	B0                               = 0x0
+	B1000000                         = 0x1008
+	B110                             = 0x3
+	B115200                          = 0x1002
+	B1152000                         = 0x1009
+	B1200                            = 0x9
+	B134                             = 0x4
+	B150                             = 0x5
+	B1500000                         = 0x100a
+	B1800                            = 0xa
+	B19200                           = 0xe
+	B200                             = 0x6
+	B2000000                         = 0x100b
+	B230400                          = 0x1003
+	B2400                            = 0xb
+	B2500000                         = 0x100c
+	B300                             = 0x7
+	B3000000                         = 0x100d
+	B3500000                         = 0x100e
+	B38400                           = 0xf
+	B4000000                         = 0x100f
+	B460800                          = 0x1004
+	B4800                            = 0xc
+	B50                              = 0x1
+	B500000                          = 0x1005
+	B57600                           = 0x1001
+	B576000                          = 0x1006
+	B600                             = 0x8
+	B75                              = 0x2
+	B921600                          = 0x1007
+	B9600                            = 0xd
+	BPF_A                            = 0x10
+	BPF_ABS                          = 0x20
+	BPF_ADD                          = 0x0
+	BPF_ALU                          = 0x4
+	BPF_AND                          = 0x50
+	BPF_B                            = 0x10
+	BPF_DIV                          = 0x30
+	BPF_H                            = 0x8
+	BPF_IMM                          = 0x0
+	BPF_IND                          = 0x40
+	BPF_JA                           = 0x0
+	BPF_JEQ                          = 0x10
+	BPF_JGE                          = 0x30
+	BPF_JGT                          = 0x20
+	BPF_JMP                          = 0x5
+	BPF_JSET                         = 0x40
+	BPF_K                            = 0x0
+	BPF_LD                           = 0x0
+	BPF_LDX                          = 0x1
+	BPF_LEN                          = 0x80
+	BPF_LSH                          = 0x60
+	BPF_MAJOR_VERSION                = 0x1
+	BPF_MAXINSNS                     = 0x1000
+	BPF_MEM                          = 0x60
+	BPF_MEMWORDS                     = 0x10
+	BPF_MINOR_VERSION                = 0x1
+	BPF_MISC                         = 0x7
+	BPF_MOD                          = 0x90
+	BPF_MSH                          = 0xa0
+	BPF_MUL                          = 0x20
+	BPF_NEG                          = 0x80
+	BPF_OR                           = 0x40
+	BPF_RET                          = 0x6
+	BPF_RSH                          = 0x70
+	BPF_ST                           = 0x2
+	BPF_STX                          = 0x3
+	BPF_SUB                          = 0x10
+	BPF_TAX                          = 0x0
+	BPF_TXA                          = 0x80
+	BPF_W                            = 0x0
+	BPF_X                            = 0x8
+	BPF_XOR                          = 0xa0
+	BRKINT                           = 0x2
+	CFLUSH                           = 0xf
+	CLOCAL                           = 0x800
+	CLONE_CHILD_CLEARTID             = 0x200000
+	CLONE_CHILD_SETTID               = 0x1000000
+	CLONE_DETACHED                   = 0x400000
+	CLONE_FILES                      = 0x400
+	CLONE_FS                         = 0x200
+	CLONE_IO                         = 0x80000000
+	CLONE_NEWIPC                     = 0x8000000
+	CLONE_NEWNET                     = 0x40000000
+	CLONE_NEWNS                      = 0x20000
+	CLONE_NEWPID                     = 0x20000000
+	CLONE_NEWUSER                    = 0x10000000
+	CLONE_NEWUTS                     = 0x4000000
+	CLONE_PARENT                     = 0x8000
+	CLONE_PARENT_SETTID              = 0x100000
+	CLONE_PTRACE                     = 0x2000
+	CLONE_SETTLS                     = 0x80000
+	CLONE_SIGHAND                    = 0x800
+	CLONE_SYSVSEM                    = 0x40000
+	CLONE_THREAD                     = 0x10000
+	CLONE_UNTRACED                   = 0x800000
+	CLONE_VFORK                      = 0x4000
+	CLONE_VM                         = 0x100
+	CREAD                            = 0x80
+	CS5                              = 0x0
+	CS6                              = 0x10
+	CS7                              = 0x20
+	CS8                              = 0x30
+	CSIGNAL                          = 0xff
+	CSIZE                            = 0x30
+	CSTART                           = 0x11
+	CSTATUS                          = 0x0
+	CSTOP                            = 0x13
+	CSTOPB                           = 0x40
+	CSUSP                            = 0x1a
+	DT_BLK                           = 0x6
+	DT_CHR                           = 0x2
+	DT_DIR                           = 0x4
+	DT_FIFO                          = 0x1
+	DT_LNK                           = 0xa
+	DT_REG                           = 0x8
+	DT_SOCK                          = 0xc
+	DT_UNKNOWN                       = 0x0
+	DT_WHT                           = 0xe
+	ECHO                             = 0x8
+	ECHOCTL                          = 0x200
+	ECHOE                            = 0x10
+	ECHOK                            = 0x20
+	ECHOKE                           = 0x800
+	ECHONL                           = 0x40
+	ECHOPRT                          = 0x400
+	ENCODING_DEFAULT                 = 0x0
+	ENCODING_FM_MARK                 = 0x3
+	ENCODING_FM_SPACE                = 0x4
+	ENCODING_MANCHESTER              = 0x5
+	ENCODING_NRZ                     = 0x1
+	ENCODING_NRZI                    = 0x2
+	EPOLLERR                         = 0x8
+	EPOLLET                          = 0x80000000
+	EPOLLHUP                         = 0x10
+	EPOLLIN                          = 0x1
+	EPOLLMSG                         = 0x400
+	EPOLLONESHOT                     = 0x40000000
+	EPOLLOUT                         = 0x4
+	EPOLLPRI                         = 0x2
+	EPOLLRDBAND                      = 0x80
+	EPOLLRDHUP                       = 0x2000
+	EPOLLRDNORM                      = 0x40
+	EPOLLWAKEUP                      = 0x20000000
+	EPOLLWRBAND                      = 0x200
+	EPOLLWRNORM                      = 0x100
+	EPOLL_CLOEXEC                    = 0x80000
+	EPOLL_CTL_ADD                    = 0x1
+	EPOLL_CTL_DEL                    = 0x2
+	EPOLL_CTL_MOD                    = 0x3
+	ETH_P_1588                       = 0x88f7
+	ETH_P_8021AD                     = 0x88a8
+	ETH_P_8021AH                     = 0x88e7
+	ETH_P_8021Q                      = 0x8100
+	ETH_P_802_2                      = 0x4
+	ETH_P_802_3                      = 0x1
+	ETH_P_802_3_MIN                  = 0x600
+	ETH_P_802_EX1                    = 0x88b5
+	ETH_P_AARP                       = 0x80f3
+	ETH_P_AF_IUCV                    = 0xfbfb
+	ETH_P_ALL                        = 0x3
+	ETH_P_AOE                        = 0x88a2
+	ETH_P_ARCNET                     = 0x1a
+	ETH_P_ARP                        = 0x806
+	ETH_P_ATALK                      = 0x809b
+	ETH_P_ATMFATE                    = 0x8884
+	ETH_P_ATMMPOA                    = 0x884c
+	ETH_P_AX25                       = 0x2
+	ETH_P_BATMAN                     = 0x4305
+	ETH_P_BPQ                        = 0x8ff
+	ETH_P_CAIF                       = 0xf7
+	ETH_P_CAN                        = 0xc
+	ETH_P_CANFD                      = 0xd
+	ETH_P_CONTROL                    = 0x16
+	ETH_P_CUST                       = 0x6006
+	ETH_P_DDCMP                      = 0x6
+	ETH_P_DEC                        = 0x6000
+	ETH_P_DIAG                       = 0x6005
+	ETH_P_DNA_DL                     = 0x6001
+	ETH_P_DNA_RC                     = 0x6002
+	ETH_P_DNA_RT                     = 0x6003
+	ETH_P_DSA                        = 0x1b
+	ETH_P_ECONET                     = 0x18
+	ETH_P_EDSA                       = 0xdada
+	ETH_P_FCOE                       = 0x8906
+	ETH_P_FIP                        = 0x8914
+	ETH_P_HDLC                       = 0x19
+	ETH_P_IEEE802154                 = 0xf6
+	ETH_P_IEEEPUP                    = 0xa00
+	ETH_P_IEEEPUPAT                  = 0xa01
+	ETH_P_IP                         = 0x800
+	ETH_P_IPV6                       = 0x86dd
+	ETH_P_IPX                        = 0x8137
+	ETH_P_IRDA                       = 0x17
+	ETH_P_LAT                        = 0x6004
+	ETH_P_LINK_CTL                   = 0x886c
+	ETH_P_LOCALTALK                  = 0x9
+	ETH_P_LOOP                       = 0x60
+	ETH_P_MOBITEX                    = 0x15
+	ETH_P_MPLS_MC                    = 0x8848
+	ETH_P_MPLS_UC                    = 0x8847
+	ETH_P_MVRP                       = 0x88f5
+	ETH_P_PAE                        = 0x888e
+	ETH_P_PAUSE                      = 0x8808
+	ETH_P_PHONET                     = 0xf5
+	ETH_P_PPPTALK                    = 0x10
+	ETH_P_PPP_DISC                   = 0x8863
+	ETH_P_PPP_MP                     = 0x8
+	ETH_P_PPP_SES                    = 0x8864
+	ETH_P_PRP                        = 0x88fb
+	ETH_P_PUP                        = 0x200
+	ETH_P_PUPAT                      = 0x201
+	ETH_P_QINQ1                      = 0x9100
+	ETH_P_QINQ2                      = 0x9200
+	ETH_P_QINQ3                      = 0x9300
+	ETH_P_RARP                       = 0x8035
+	ETH_P_SCA                        = 0x6007
+	ETH_P_SLOW                       = 0x8809
+	ETH_P_SNAP                       = 0x5
+	ETH_P_TDLS                       = 0x890d
+	ETH_P_TEB                        = 0x6558
+	ETH_P_TIPC                       = 0x88ca
+	ETH_P_TRAILER                    = 0x1c
+	ETH_P_TR_802_2                   = 0x11
+	ETH_P_WAN_PPP                    = 0x7
+	ETH_P_WCCP                       = 0x883e
+	ETH_P_X25                        = 0x805
+	EXTA                             = 0xe
+	EXTB                             = 0xf
+	EXTPROC                          = 0x10000
+	FD_CLOEXEC                       = 0x1
+	FD_SETSIZE                       = 0x400
+	FLUSHO                           = 0x1000
+	F_DUPFD                          = 0x0
+	F_DUPFD_CLOEXEC                  = 0x406
+	F_EXLCK                          = 0x4
+	F_GETFD                          = 0x1
+	F_GETFL                          = 0x3
+	F_GETLEASE                       = 0x401
+	F_GETLK                          = 0x5
+	F_GETLK64                        = 0x5
+	F_GETOWN                         = 0x9
+	F_GETOWN_EX                      = 0x10
+	F_GETPIPE_SZ                     = 0x408
+	F_GETSIG                         = 0xb
+	F_LOCK                           = 0x1
+	F_NOTIFY                         = 0x402
+	F_OK                             = 0x0
+	F_RDLCK                          = 0x0
+	F_SETFD                          = 0x2
+	F_SETFL                          = 0x4
+	F_SETLEASE                       = 0x400
+	F_SETLK                          = 0x6
+	F_SETLK64                        = 0x6
+	F_SETLKW                         = 0x7
+	F_SETLKW64                       = 0x7
+	F_SETOWN                         = 0x8
+	F_SETOWN_EX                      = 0xf
+	F_SETPIPE_SZ                     = 0x407
+	F_SETSIG                         = 0xa
+	F_SHLCK                          = 0x8
+	F_TEST                           = 0x3
+	F_TLOCK                          = 0x2
+	F_ULOCK                          = 0x0
+	F_UNLCK                          = 0x2
+	F_WRLCK                          = 0x1
+	HUPCL                            = 0x400
+	ICANON                           = 0x2
+	ICMPV6_FILTER                    = 0x1
+	ICRNL                            = 0x100
+	IEXTEN                           = 0x8000
+	IFA_F_DADFAILED                  = 0x8
+	IFA_F_DEPRECATED                 = 0x20
+	IFA_F_HOMEADDRESS                = 0x10
+	IFA_F_NODAD                      = 0x2
+	IFA_F_OPTIMISTIC                 = 0x4
+	IFA_F_PERMANENT                  = 0x80
+	IFA_F_SECONDARY                  = 0x1
+	IFA_F_TEMPORARY                  = 0x1
+	IFA_F_TENTATIVE                  = 0x40
+	IFA_MAX                          = 0x7
+	IFF_802_1Q_VLAN                  = 0x1
+	IFF_ALLMULTI                     = 0x200
+	IFF_ATTACH_QUEUE                 = 0x200
+	IFF_AUTOMEDIA                    = 0x4000
+	IFF_BONDING                      = 0x20
+	IFF_BRIDGE_PORT                  = 0x4000
+	IFF_BROADCAST                    = 0x2
+	IFF_DEBUG                        = 0x4
+	IFF_DETACH_QUEUE                 = 0x400
+	IFF_DISABLE_NETPOLL              = 0x1000
+	IFF_DONT_BRIDGE                  = 0x800
+	IFF_DORMANT                      = 0x20000
+	IFF_DYNAMIC                      = 0x8000
+	IFF_EBRIDGE                      = 0x2
+	IFF_ECHO                         = 0x40000
+	IFF_ISATAP                       = 0x80
+	IFF_LIVE_ADDR_CHANGE             = 0x100000
+	IFF_LOOPBACK                     = 0x8
+	IFF_LOWER_UP                     = 0x10000
+	IFF_MACVLAN                      = 0x200000
+	IFF_MACVLAN_PORT                 = 0x2000
+	IFF_MASTER                       = 0x400
+	IFF_MASTER_8023AD                = 0x8
+	IFF_MASTER_ALB                   = 0x10
+	IFF_MASTER_ARPMON                = 0x100
+	IFF_MULTICAST                    = 0x1000
+	IFF_MULTI_QUEUE                  = 0x100
+	IFF_NOARP                        = 0x80
+	IFF_NOFILTER                     = 0x1000
+	IFF_NOTRAILERS                   = 0x20
+	IFF_NO_PI                        = 0x1000
+	IFF_ONE_QUEUE                    = 0x2000
+	IFF_OVS_DATAPATH                 = 0x8000
+	IFF_PERSIST                      = 0x800
+	IFF_POINTOPOINT                  = 0x10
+	IFF_PORTSEL                      = 0x2000
+	IFF_PROMISC                      = 0x100
+	IFF_RUNNING                      = 0x40
+	IFF_SLAVE                        = 0x800
+	IFF_SLAVE_INACTIVE               = 0x4
+	IFF_SLAVE_NEEDARP                = 0x40
+	IFF_SUPP_NOFCS                   = 0x80000
+	IFF_TAP                          = 0x2
+	IFF_TEAM_PORT                    = 0x40000
+	IFF_TUN                          = 0x1
+	IFF_TUN_EXCL                     = 0x8000
+	IFF_TX_SKB_SHARING               = 0x10000
+	IFF_UNICAST_FLT                  = 0x20000
+	IFF_UP                           = 0x1
+	IFF_VNET_HDR                     = 0x4000
+	IFF_VOLATILE                     = 0x70c5a
+	IFF_WAN_HDLC                     = 0x200
+	IFF_XMIT_DST_RELEASE             = 0x400
+	IFNAMSIZ                         = 0x10
+	IGNBRK                           = 0x1
+	IGNCR                            = 0x80
+	IGNPAR                           = 0x4
+	IMAXBEL                          = 0x2000
+	INLCR                            = 0x40
+	INPCK                            = 0x10
+	IN_ACCESS                        = 0x1
+	IN_ALL_EVENTS                    = 0xfff
+	IN_ATTRIB                        = 0x4
+	IN_CLASSA_HOST                   = 0xffffff
+	IN_CLASSA_MAX                    = 0x80
+	IN_CLASSA_NET                    = 0xff000000
+	IN_CLASSA_NSHIFT                 = 0x18
+	IN_CLASSB_HOST                   = 0xffff
+	IN_CLASSB_MAX                    = 0x10000
+	IN_CLASSB_NET                    = 0xffff0000
+	IN_CLASSB_NSHIFT                 = 0x10
+	IN_CLASSC_HOST                   = 0xff
+	IN_CLASSC_NET                    = 0xffffff00
+	IN_CLASSC_NSHIFT                 = 0x8
+	IN_CLOEXEC                       = 0x80000
+	IN_CLOSE                         = 0x18
+	IN_CLOSE_NOWRITE                 = 0x10
+	IN_CLOSE_WRITE                   = 0x8
+	IN_CREATE                        = 0x100
+	IN_DELETE                        = 0x200
+	IN_DELETE_SELF                   = 0x400
+	IN_DONT_FOLLOW                   = 0x2000000
+	IN_EXCL_UNLINK                   = 0x4000000
+	IN_IGNORED                       = 0x8000
+	IN_ISDIR                         = 0x40000000
+	IN_LOOPBACKNET                   = 0x7f
+	IN_MASK_ADD                      = 0x20000000
+	IN_MODIFY                        = 0x2
+	IN_MOVE                          = 0xc0
+	IN_MOVED_FROM                    = 0x40
+	IN_MOVED_TO                      = 0x80
+	IN_MOVE_SELF                     = 0x800
+	IN_NONBLOCK                      = 0x800
+	IN_ONESHOT                       = 0x80000000
+	IN_ONLYDIR                       = 0x1000000
+	IN_OPEN                          = 0x20
+	IN_Q_OVERFLOW                    = 0x4000
+	IN_UNMOUNT                       = 0x2000
+	IPPROTO_AH                       = 0x33
+	IPPROTO_BEETPH                   = 0x5e
+	IPPROTO_COMP                     = 0x6c
+	IPPROTO_DCCP                     = 0x21
+	IPPROTO_DSTOPTS                  = 0x3c
+	IPPROTO_EGP                      = 0x8
+	IPPROTO_ENCAP                    = 0x62
+	IPPROTO_ESP                      = 0x32
+	IPPROTO_FRAGMENT                 = 0x2c
+	IPPROTO_GRE                      = 0x2f
+	IPPROTO_HOPOPTS                  = 0x0
+	IPPROTO_ICMP                     = 0x1
+	IPPROTO_ICMPV6                   = 0x3a
+	IPPROTO_IDP                      = 0x16
+	IPPROTO_IGMP                     = 0x2
+	IPPROTO_IP                       = 0x0
+	IPPROTO_IPIP                     = 0x4
+	IPPROTO_IPV6                     = 0x29
+	IPPROTO_MH                       = 0x87
+	IPPROTO_MTP                      = 0x5c
+	IPPROTO_NONE                     = 0x3b
+	IPPROTO_PIM                      = 0x67
+	IPPROTO_PUP                      = 0xc
+	IPPROTO_RAW                      = 0xff
+	IPPROTO_ROUTING                  = 0x2b
+	IPPROTO_RSVP                     = 0x2e
+	IPPROTO_SCTP                     = 0x84
+	IPPROTO_TCP                      = 0x6
+	IPPROTO_TP                       = 0x1d
+	IPPROTO_UDP                      = 0x11
+	IPPROTO_UDPLITE                  = 0x88
+	IPV6_2292DSTOPTS                 = 0x4
+	IPV6_2292HOPLIMIT                = 0x8
+	IPV6_2292HOPOPTS                 = 0x3
+	IPV6_2292PKTINFO                 = 0x2
+	IPV6_2292PKTOPTIONS              = 0x6
+	IPV6_2292RTHDR                   = 0x5
+	IPV6_ADDRFORM                    = 0x1
+	IPV6_ADD_MEMBERSHIP              = 0x14
+	IPV6_AUTHHDR                     = 0xa
+	IPV6_CHECKSUM                    = 0x7
+	IPV6_DROP_MEMBERSHIP             = 0x15
+	IPV6_DSTOPTS                     = 0x3b
+	IPV6_HOPLIMIT                    = 0x34
+	IPV6_HOPOPTS                     = 0x36
+	IPV6_IPSEC_POLICY                = 0x22
+	IPV6_JOIN_ANYCAST                = 0x1b
+	IPV6_JOIN_GROUP                  = 0x14
+	IPV6_LEAVE_ANYCAST               = 0x1c
+	IPV6_LEAVE_GROUP                 = 0x15
+	IPV6_MTU                         = 0x18
+	IPV6_MTU_DISCOVER                = 0x17
+	IPV6_MULTICAST_HOPS              = 0x12
+	IPV6_MULTICAST_IF                = 0x11
+	IPV6_MULTICAST_LOOP              = 0x13
+	IPV6_NEXTHOP                     = 0x9
+	IPV6_PKTINFO                     = 0x32
+	IPV6_PMTUDISC_DO                 = 0x2
+	IPV6_PMTUDISC_DONT               = 0x0
+	IPV6_PMTUDISC_PROBE              = 0x3
+	IPV6_PMTUDISC_WANT               = 0x1
+	IPV6_RECVDSTOPTS                 = 0x3a
+	IPV6_RECVERR                     = 0x19
+	IPV6_RECVHOPLIMIT                = 0x33
+	IPV6_RECVHOPOPTS                 = 0x35
+	IPV6_RECVPKTINFO                 = 0x31
+	IPV6_RECVRTHDR                   = 0x38
+	IPV6_RECVTCLASS                  = 0x42
+	IPV6_ROUTER_ALERT                = 0x16
+	IPV6_RTHDR                       = 0x39
+	IPV6_RTHDRDSTOPTS                = 0x37
+	IPV6_RTHDR_LOOSE                 = 0x0
+	IPV6_RTHDR_STRICT                = 0x1
+	IPV6_RTHDR_TYPE_0                = 0x0
+	IPV6_RXDSTOPTS                   = 0x3b
+	IPV6_RXHOPOPTS                   = 0x36
+	IPV6_TCLASS                      = 0x43
+	IPV6_UNICAST_HOPS                = 0x10
+	IPV6_V6ONLY                      = 0x1a
+	IPV6_XFRM_POLICY                 = 0x23
+	IP_ADD_MEMBERSHIP                = 0x23
+	IP_ADD_SOURCE_MEMBERSHIP         = 0x27
+	IP_BLOCK_SOURCE                  = 0x26
+	IP_DEFAULT_MULTICAST_LOOP        = 0x1
+	IP_DEFAULT_MULTICAST_TTL         = 0x1
+	IP_DF                            = 0x4000
+	IP_DROP_MEMBERSHIP               = 0x24
+	IP_DROP_SOURCE_MEMBERSHIP        = 0x28
+	IP_FREEBIND                      = 0xf
+	IP_HDRINCL                       = 0x3
+	IP_IPSEC_POLICY                  = 0x10
+	IP_MAXPACKET                     = 0xffff
+	IP_MAX_MEMBERSHIPS               = 0x14
+	IP_MF                            = 0x2000
+	IP_MINTTL                        = 0x15
+	IP_MSFILTER                      = 0x29
+	IP_MSS                           = 0x240
+	IP_MTU                           = 0xe
+	IP_MTU_DISCOVER                  = 0xa
+	IP_MULTICAST_ALL                 = 0x31
+	IP_MULTICAST_IF                  = 0x20
+	IP_MULTICAST_LOOP                = 0x22
+	IP_MULTICAST_TTL                 = 0x21
+	IP_OFFMASK                       = 0x1fff
+	IP_OPTIONS                       = 0x4
+	IP_ORIGDSTADDR                   = 0x14
+	IP_PASSSEC                       = 0x12
+	IP_PKTINFO                       = 0x8
+	IP_PKTOPTIONS                    = 0x9
+	IP_PMTUDISC                      = 0xa
+	IP_PMTUDISC_DO                   = 0x2
+	IP_PMTUDISC_DONT                 = 0x0
+	IP_PMTUDISC_PROBE                = 0x3
+	IP_PMTUDISC_WANT                 = 0x1
+	IP_RECVERR                       = 0xb
+	IP_RECVOPTS                      = 0x6
+	IP_RECVORIGDSTADDR               = 0x14
+	IP_RECVRETOPTS                   = 0x7
+	IP_RECVTOS                       = 0xd
+	IP_RECVTTL                       = 0xc
+	IP_RETOPTS                       = 0x7
+	IP_RF                            = 0x8000
+	IP_ROUTER_ALERT                  = 0x5
+	IP_TOS                           = 0x1
+	IP_TRANSPARENT                   = 0x13
+	IP_TTL                           = 0x2
+	IP_UNBLOCK_SOURCE                = 0x25
+	IP_UNICAST_IF                    = 0x32
+	IP_XFRM_POLICY                   = 0x11
+	ISIG                             = 0x1
+	ISTRIP                           = 0x20
+	IUTF8                            = 0x4000
+	IXANY                            = 0x800
+	IXOFF                            = 0x1000
+	IXON                             = 0x400
+	LINUX_REBOOT_CMD_CAD_OFF         = 0x0
+	LINUX_REBOOT_CMD_CAD_ON          = 0x89abcdef
+	LINUX_REBOOT_CMD_HALT            = 0xcdef0123
+	LINUX_REBOOT_CMD_KEXEC           = 0x45584543
+	LINUX_REBOOT_CMD_POWER_OFF       = 0x4321fedc
+	LINUX_REBOOT_CMD_RESTART         = 0x1234567
+	LINUX_REBOOT_CMD_RESTART2        = 0xa1b2c3d4
+	LINUX_REBOOT_CMD_SW_SUSPEND      = 0xd000fce2
+	LINUX_REBOOT_MAGIC1              = 0xfee1dead
+	LINUX_REBOOT_MAGIC2              = 0x28121969
+	LOCK_EX                          = 0x2
+	LOCK_NB                          = 0x4
+	LOCK_SH                          = 0x1
+	LOCK_UN                          = 0x8
+	MADV_DODUMP                      = 0x11
+	MADV_DOFORK                      = 0xb
+	MADV_DONTDUMP                    = 0x10
+	MADV_DONTFORK                    = 0xa
+	MADV_DONTNEED                    = 0x4
+	MADV_HUGEPAGE                    = 0xe
+	MADV_HWPOISON                    = 0x64
+	MADV_MERGEABLE                   = 0xc
+	MADV_NOHUGEPAGE                  = 0xf
+	MADV_NORMAL                      = 0x0
+	MADV_RANDOM                      = 0x1
+	MADV_REMOVE                      = 0x9
+	MADV_SEQUENTIAL                  = 0x2
+	MADV_UNMERGEABLE                 = 0xd
+	MADV_WILLNEED                    = 0x3
+	MAP_ANON                         = 0x20
+	MAP_ANONYMOUS                    = 0x20
+	MAP_DENYWRITE                    = 0x800
+	MAP_EXECUTABLE                   = 0x1000
+	MAP_FILE                         = 0x0
+	MAP_FIXED                        = 0x10
+	MAP_GROWSDOWN                    = 0x100
+	MAP_HUGETLB                      = 0x40000
+	MAP_HUGE_MASK                    = 0x3f
+	MAP_HUGE_SHIFT                   = 0x1a
+	MAP_LOCKED                       = 0x2000
+	MAP_NONBLOCK                     = 0x10000
+	MAP_NORESERVE                    = 0x4000
+	MAP_POPULATE                     = 0x8000
+	MAP_PRIVATE                      = 0x2
+	MAP_SHARED                       = 0x1
+	MAP_STACK                        = 0x20000
+	MAP_TYPE                         = 0xf
+	MCL_CURRENT                      = 0x1
+	MCL_FUTURE                       = 0x2
+	MNT_DETACH                       = 0x2
+	MNT_EXPIRE                       = 0x4
+	MNT_FORCE                        = 0x1
+	MSG_CMSG_CLOEXEC                 = 0x40000000
+	MSG_CONFIRM                      = 0x800
+	MSG_CTRUNC                       = 0x8
+	MSG_DONTROUTE                    = 0x4
+	MSG_DONTWAIT                     = 0x40
+	MSG_EOR                          = 0x80
+	MSG_ERRQUEUE                     = 0x2000
+	MSG_FASTOPEN                     = 0x20000000
+	MSG_FIN                          = 0x200
+	MSG_MORE                         = 0x8000
+	MSG_NOSIGNAL                     = 0x4000
+	MSG_OOB                          = 0x1
+	MSG_PEEK                         = 0x2
+	MSG_PROXY                        = 0x10
+	MSG_RST                          = 0x1000
+	MSG_SYN                          = 0x400
+	MSG_TRUNC                        = 0x20
+	MSG_TRYHARD                      = 0x4
+	MSG_WAITALL                      = 0x100
+	MSG_WAITFORONE                   = 0x10000
+	MS_ACTIVE                        = 0x40000000
+	MS_ASYNC                         = 0x1
+	MS_BIND                          = 0x1000
+	MS_DIRSYNC                       = 0x80
+	MS_INVALIDATE                    = 0x2
+	MS_I_VERSION                     = 0x800000
+	MS_KERNMOUNT                     = 0x400000
+	MS_MANDLOCK                      = 0x40
+	MS_MGC_MSK                       = 0xffff0000
+	MS_MGC_VAL                       = 0xc0ed0000
+	MS_MOVE                          = 0x2000
+	MS_NOATIME                       = 0x400
+	MS_NODEV                         = 0x4
+	MS_NODIRATIME                    = 0x800
+	MS_NOEXEC                        = 0x8
+	MS_NOSUID                        = 0x2
+	MS_NOUSER                        = -0x80000000
+	MS_POSIXACL                      = 0x10000
+	MS_PRIVATE                       = 0x40000
+	MS_RDONLY                        = 0x1
+	MS_REC                           = 0x4000
+	MS_RELATIME                      = 0x200000
+	MS_REMOUNT                       = 0x20
+	MS_RMT_MASK                      = 0x800051
+	MS_SHARED                        = 0x100000
+	MS_SILENT                        = 0x8000
+	MS_SLAVE                         = 0x80000
+	MS_STRICTATIME                   = 0x1000000
+	MS_SYNC                          = 0x4
+	MS_SYNCHRONOUS                   = 0x10
+	MS_UNBINDABLE                    = 0x20000
+	NAME_MAX                         = 0xff
+	NETLINK_ADD_MEMBERSHIP           = 0x1
+	NETLINK_AUDIT                    = 0x9
+	NETLINK_BROADCAST_ERROR          = 0x4
+	NETLINK_CONNECTOR                = 0xb
+	NETLINK_CRYPTO                   = 0x15
+	NETLINK_DNRTMSG                  = 0xe
+	NETLINK_DROP_MEMBERSHIP          = 0x2
+	NETLINK_ECRYPTFS                 = 0x13
+	NETLINK_FIB_LOOKUP               = 0xa
+	NETLINK_FIREWALL                 = 0x3
+	NETLINK_GENERIC                  = 0x10
+	NETLINK_INET_DIAG                = 0x4
+	NETLINK_IP6_FW                   = 0xd
+	NETLINK_ISCSI                    = 0x8
+	NETLINK_KOBJECT_UEVENT           = 0xf
+	NETLINK_NETFILTER                = 0xc
+	NETLINK_NFLOG                    = 0x5
+	NETLINK_NO_ENOBUFS               = 0x5
+	NETLINK_PKTINFO                  = 0x3
+	NETLINK_RDMA                     = 0x14
+	NETLINK_ROUTE                    = 0x0
+	NETLINK_RX_RING                  = 0x6
+	NETLINK_SCSITRANSPORT            = 0x12
+	NETLINK_SELINUX                  = 0x7
+	NETLINK_SOCK_DIAG                = 0x4
+	NETLINK_TX_RING                  = 0x7
+	NETLINK_UNUSED                   = 0x1
+	NETLINK_USERSOCK                 = 0x2
+	NETLINK_XFRM                     = 0x6
+	NLA_ALIGNTO                      = 0x4
+	NLA_F_NESTED                     = 0x8000
+	NLA_F_NET_BYTEORDER              = 0x4000
+	NLA_HDRLEN                       = 0x4
+	NLMSG_ALIGNTO                    = 0x4
+	NLMSG_DONE                       = 0x3
+	NLMSG_ERROR                      = 0x2
+	NLMSG_HDRLEN                     = 0x10
+	NLMSG_MIN_TYPE                   = 0x10
+	NLMSG_NOOP                       = 0x1
+	NLMSG_OVERRUN                    = 0x4
+	NLM_F_ACK                        = 0x4
+	NLM_F_APPEND                     = 0x800
+	NLM_F_ATOMIC                     = 0x400
+	NLM_F_CREATE                     = 0x400
+	NLM_F_DUMP                       = 0x300
+	NLM_F_DUMP_INTR                  = 0x10
+	NLM_F_ECHO                       = 0x8
+	NLM_F_EXCL                       = 0x200
+	NLM_F_MATCH                      = 0x200
+	NLM_F_MULTI                      = 0x2
+	NLM_F_REPLACE                    = 0x100
+	NLM_F_REQUEST                    = 0x1
+	NLM_F_ROOT                       = 0x100
+	NOFLSH                           = 0x80
+	OCRNL                            = 0x8
+	OFDEL                            = 0x80
+	OFILL                            = 0x40
+	ONLCR                            = 0x4
+	ONLRET                           = 0x20
+	ONOCR                            = 0x10
+	OPOST                            = 0x1
+	O_ACCMODE                        = 0x3
+	O_APPEND                         = 0x400
+	O_ASYNC                          = 0x2000
+	O_CLOEXEC                        = 0x80000
+	O_CREAT                          = 0x40
+	O_DIRECT                         = 0x10000
+	O_DIRECTORY                      = 0x4000
+	O_DSYNC                          = 0x1000
+	O_EXCL                           = 0x80
+	O_FSYNC                          = 0x101000
+	O_LARGEFILE                      = 0x0
+	O_NDELAY                         = 0x800
+	O_NOATIME                        = 0x40000
+	O_NOCTTY                         = 0x100
+	O_NOFOLLOW                       = 0x8000
+	O_NONBLOCK                       = 0x800
+	O_PATH                           = 0x200000
+	O_RDONLY                         = 0x0
+	O_RDWR                           = 0x2
+	O_RSYNC                          = 0x101000
+	O_SYNC                           = 0x101000
+	O_TMPFILE                        = 0x410000
+	O_TRUNC                          = 0x200
+	O_WRONLY                         = 0x1
+	PACKET_ADD_MEMBERSHIP            = 0x1
+	PACKET_AUXDATA                   = 0x8
+	PACKET_BROADCAST                 = 0x1
+	PACKET_COPY_THRESH               = 0x7
+	PACKET_DROP_MEMBERSHIP           = 0x2
+	PACKET_FANOUT                    = 0x12
+	PACKET_FANOUT_CPU                = 0x2
+	PACKET_FANOUT_FLAG_DEFRAG        = 0x8000
+	PACKET_FANOUT_FLAG_ROLLOVER      = 0x1000
+	PACKET_FANOUT_HASH               = 0x0
+	PACKET_FANOUT_LB                 = 0x1
+	PACKET_FANOUT_RND                = 0x4
+	PACKET_FANOUT_ROLLOVER           = 0x3
+	PACKET_FASTROUTE                 = 0x6
+	PACKET_HDRLEN                    = 0xb
+	PACKET_HOST                      = 0x0
+	PACKET_LOOPBACK                  = 0x5
+	PACKET_LOSS                      = 0xe
+	PACKET_MR_ALLMULTI               = 0x2
+	PACKET_MR_MULTICAST              = 0x0
+	PACKET_MR_PROMISC                = 0x1
+	PACKET_MR_UNICAST                = 0x3
+	PACKET_MULTICAST                 = 0x2
+	PACKET_ORIGDEV                   = 0x9
+	PACKET_OTHERHOST                 = 0x3
+	PACKET_OUTGOING                  = 0x4
+	PACKET_RECV_OUTPUT               = 0x3
+	PACKET_RESERVE                   = 0xc
+	PACKET_RX_RING                   = 0x5
+	PACKET_STATISTICS                = 0x6
+	PACKET_TIMESTAMP                 = 0x11
+	PACKET_TX_HAS_OFF                = 0x13
+	PACKET_TX_RING                   = 0xd
+	PACKET_TX_TIMESTAMP              = 0x10
+	PACKET_VERSION                   = 0xa
+	PACKET_VNET_HDR                  = 0xf
+	PARENB                           = 0x100
+	PARITY_CRC16_PR0                 = 0x2
+	PARITY_CRC16_PR0_CCITT           = 0x4
+	PARITY_CRC16_PR1                 = 0x3
+	PARITY_CRC16_PR1_CCITT           = 0x5
+	PARITY_CRC32_PR0_CCITT           = 0x6
+	PARITY_CRC32_PR1_CCITT           = 0x7
+	PARITY_DEFAULT                   = 0x0
+	PARITY_NONE                      = 0x1
+	PARMRK                           = 0x8
+	PARODD                           = 0x200
+	PENDIN                           = 0x4000
+	PRIO_PGRP                        = 0x1
+	PRIO_PROCESS                     = 0x0
+	PRIO_USER                        = 0x2
+	PROT_EXEC                        = 0x4
+	PROT_GROWSDOWN                   = 0x1000000
+	PROT_GROWSUP                     = 0x2000000
+	PROT_NONE                        = 0x0
+	PROT_READ                        = 0x1
+	PROT_WRITE                       = 0x2
+	PR_CAPBSET_DROP                  = 0x18
+	PR_CAPBSET_READ                  = 0x17
+	PR_ENDIAN_BIG                    = 0x0
+	PR_ENDIAN_LITTLE                 = 0x1
+	PR_ENDIAN_PPC_LITTLE             = 0x2
+	PR_FPEMU_NOPRINT                 = 0x1
+	PR_FPEMU_SIGFPE                  = 0x2
+	PR_FP_EXC_ASYNC                  = 0x2
+	PR_FP_EXC_DISABLED               = 0x0
+	PR_FP_EXC_DIV                    = 0x10000
+	PR_FP_EXC_INV                    = 0x100000
+	PR_FP_EXC_NONRECOV               = 0x1
+	PR_FP_EXC_OVF                    = 0x20000
+	PR_FP_EXC_PRECISE                = 0x3
+	PR_FP_EXC_RES                    = 0x80000
+	PR_FP_EXC_SW_ENABLE              = 0x80
+	PR_FP_EXC_UND                    = 0x40000
+	PR_GET_CHILD_SUBREAPER           = 0x25
+	PR_GET_DUMPABLE                  = 0x3
+	PR_GET_ENDIAN                    = 0x13
+	PR_GET_FPEMU                     = 0x9
+	PR_GET_FPEXC                     = 0xb
+	PR_GET_KEEPCAPS                  = 0x7
+	PR_GET_NAME                      = 0x10
+	PR_GET_NO_NEW_PRIVS              = 0x27
+	PR_GET_PDEATHSIG                 = 0x2
+	PR_GET_SECCOMP                   = 0x15
+	PR_GET_SECUREBITS                = 0x1b
+	PR_GET_TID_ADDRESS               = 0x28
+	PR_GET_TIMERSLACK                = 0x1e
+	PR_GET_TIMING                    = 0xd
+	PR_GET_TSC                       = 0x19
+	PR_GET_UNALIGN                   = 0x5
+	PR_MCE_KILL                      = 0x21
+	PR_MCE_KILL_CLEAR                = 0x0
+	PR_MCE_KILL_DEFAULT              = 0x2
+	PR_MCE_KILL_EARLY                = 0x1
+	PR_MCE_KILL_GET                  = 0x22
+	PR_MCE_KILL_LATE                 = 0x0
+	PR_MCE_KILL_SET                  = 0x1
+	PR_SET_CHILD_SUBREAPER           = 0x24
+	PR_SET_DUMPABLE                  = 0x4
+	PR_SET_ENDIAN                    = 0x14
+	PR_SET_FPEMU                     = 0xa
+	PR_SET_FPEXC                     = 0xc
+	PR_SET_KEEPCAPS                  = 0x8
+	PR_SET_MM                        = 0x23
+	PR_SET_MM_ARG_END                = 0x9
+	PR_SET_MM_ARG_START              = 0x8
+	PR_SET_MM_AUXV                   = 0xc
+	PR_SET_MM_BRK                    = 0x7
+	PR_SET_MM_END_CODE               = 0x2
+	PR_SET_MM_END_DATA               = 0x4
+	PR_SET_MM_ENV_END                = 0xb
+	PR_SET_MM_ENV_START              = 0xa
+	PR_SET_MM_EXE_FILE               = 0xd
+	PR_SET_MM_START_BRK              = 0x6
+	PR_SET_MM_START_CODE             = 0x1
+	PR_SET_MM_START_DATA             = 0x3
+	PR_SET_MM_START_STACK            = 0x5
+	PR_SET_NAME                      = 0xf
+	PR_SET_NO_NEW_PRIVS              = 0x26
+	PR_SET_PDEATHSIG                 = 0x1
+	PR_SET_PTRACER                   = 0x59616d61
+	PR_SET_PTRACER_ANY               = -0x1
+	PR_SET_SECCOMP                   = 0x16
+	PR_SET_SECUREBITS                = 0x1c
+	PR_SET_TIMERSLACK                = 0x1d
+	PR_SET_TIMING                    = 0xe
+	PR_SET_TSC                       = 0x1a
+	PR_SET_UNALIGN                   = 0x6
+	PR_TASK_PERF_EVENTS_DISABLE      = 0x1f
+	PR_TASK_PERF_EVENTS_ENABLE       = 0x20
+	PR_TIMING_STATISTICAL            = 0x0
+	PR_TIMING_TIMESTAMP              = 0x1
+	PR_TSC_ENABLE                    = 0x1
+	PR_TSC_SIGSEGV                   = 0x2
+	PR_UNALIGN_NOPRINT               = 0x1
+	PR_UNALIGN_SIGBUS                = 0x2
+	PTRACE_ATTACH                    = 0x10
+	PTRACE_CONT                      = 0x7
+	PTRACE_DETACH                    = 0x11
+	PTRACE_EVENT_CLONE               = 0x3
+	PTRACE_EVENT_EXEC                = 0x4
+	PTRACE_EVENT_EXIT                = 0x6
+	PTRACE_EVENT_FORK                = 0x1
+	PTRACE_EVENT_SECCOMP             = 0x7
+	PTRACE_EVENT_STOP                = 0x80
+	PTRACE_EVENT_VFORK               = 0x2
+	PTRACE_EVENT_VFORK_DONE          = 0x5
+	PTRACE_GETEVENTMSG               = 0x4201
+	PTRACE_GETREGS                   = 0xc
+	PTRACE_GETREGSET                 = 0x4204
+	PTRACE_GETSIGINFO                = 0x4202
+	PTRACE_GETSIGMASK                = 0x420a
+	PTRACE_INTERRUPT                 = 0x4207
+	PTRACE_KILL                      = 0x8
+	PTRACE_LISTEN                    = 0x4208
+	PTRACE_O_EXITKILL                = 0x100000
+	PTRACE_O_MASK                    = 0x1000ff
+	PTRACE_O_TRACECLONE              = 0x8
+	PTRACE_O_TRACEEXEC               = 0x10
+	PTRACE_O_TRACEEXIT               = 0x40
+	PTRACE_O_TRACEFORK               = 0x2
+	PTRACE_O_TRACESECCOMP            = 0x80
+	PTRACE_O_TRACESYSGOOD            = 0x1
+	PTRACE_O_TRACEVFORK              = 0x4
+	PTRACE_O_TRACEVFORKDONE          = 0x20
+	PTRACE_PEEKDATA                  = 0x2
+	PTRACE_PEEKSIGINFO               = 0x4209
+	PTRACE_PEEKSIGINFO_SHARED        = 0x1
+	PTRACE_PEEKTEXT                  = 0x1
+	PTRACE_PEEKUSR                   = 0x3
+	PTRACE_POKEDATA                  = 0x5
+	PTRACE_POKETEXT                  = 0x4
+	PTRACE_POKEUSR                   = 0x6
+	PTRACE_SEIZE                     = 0x4206
+	PTRACE_SETOPTIONS                = 0x4200
+	PTRACE_SETREGS                   = 0xd
+	PTRACE_SETREGSET                 = 0x4205
+	PTRACE_SETSIGINFO                = 0x4203
+	PTRACE_SETSIGMASK                = 0x420b
+	PTRACE_SINGLESTEP                = 0x9
+	PTRACE_SYSCALL                   = 0x18
+	PTRACE_TRACEME                   = 0x0
+	RLIMIT_AS                        = 0x9
+	RLIMIT_CORE                      = 0x4
+	RLIMIT_CPU                       = 0x0
+	RLIMIT_DATA                      = 0x2
+	RLIMIT_FSIZE                     = 0x1
+	RLIMIT_NOFILE                    = 0x7
+	RLIMIT_STACK                     = 0x3
+	RLIM_INFINITY                    = -0x1
+	RTAX_ADVMSS                      = 0x8
+	RTAX_CWND                        = 0x7
+	RTAX_FEATURES                    = 0xc
+	RTAX_FEATURE_ALLFRAG             = 0x8
+	RTAX_FEATURE_ECN                 = 0x1
+	RTAX_FEATURE_SACK                = 0x2
+	RTAX_FEATURE_TIMESTAMP           = 0x4
+	RTAX_HOPLIMIT                    = 0xa
+	RTAX_INITCWND                    = 0xb
+	RTAX_INITRWND                    = 0xe
+	RTAX_LOCK                        = 0x1
+	RTAX_MAX                         = 0xf
+	RTAX_MTU                         = 0x2
+	RTAX_QUICKACK                    = 0xf
+	RTAX_REORDERING                  = 0x9
+	RTAX_RTO_MIN                     = 0xd
+	RTAX_RTT                         = 0x4
+	RTAX_RTTVAR                      = 0x5
+	RTAX_SSTHRESH                    = 0x6
+	RTAX_UNSPEC                      = 0x0
+	RTAX_WINDOW                      = 0x3
+	RTA_ALIGNTO                      = 0x4
+	RTA_MAX                          = 0x11
+	RTCF_DIRECTSRC                   = 0x4000000
+	RTCF_DOREDIRECT                  = 0x1000000
+	RTCF_LOG                         = 0x2000000
+	RTCF_MASQ                        = 0x400000
+	RTCF_NAT                         = 0x800000
+	RTCF_VALVE                       = 0x200000
+	RTF_ADDRCLASSMASK                = 0xf8000000
+	RTF_ADDRCONF                     = 0x40000
+	RTF_ALLONLINK                    = 0x20000
+	RTF_BROADCAST                    = 0x10000000
+	RTF_CACHE                        = 0x1000000
+	RTF_DEFAULT                      = 0x10000
+	RTF_DYNAMIC                      = 0x10
+	RTF_FLOW                         = 0x2000000
+	RTF_GATEWAY                      = 0x2
+	RTF_HOST                         = 0x4
+	RTF_INTERFACE                    = 0x40000000
+	RTF_IRTT                         = 0x100
+	RTF_LINKRT                       = 0x100000
+	RTF_LOCAL                        = 0x80000000
+	RTF_MODIFIED                     = 0x20
+	RTF_MSS                          = 0x40
+	RTF_MTU                          = 0x40
+	RTF_MULTICAST                    = 0x20000000
+	RTF_NAT                          = 0x8000000
+	RTF_NOFORWARD                    = 0x1000
+	RTF_NONEXTHOP                    = 0x200000
+	RTF_NOPMTUDISC                   = 0x4000
+	RTF_POLICY                       = 0x4000000
+	RTF_REINSTATE                    = 0x8
+	RTF_REJECT                       = 0x200
+	RTF_STATIC                       = 0x400
+	RTF_THROW                        = 0x2000
+	RTF_UP                           = 0x1
+	RTF_WINDOW                       = 0x80
+	RTF_XRESOLVE                     = 0x800
+	RTM_BASE                         = 0x10
+	RTM_DELACTION                    = 0x31
+	RTM_DELADDR                      = 0x15
+	RTM_DELADDRLABEL                 = 0x49
+	RTM_DELLINK                      = 0x11
+	RTM_DELMDB                       = 0x55
+	RTM_DELNEIGH                     = 0x1d
+	RTM_DELQDISC                     = 0x25
+	RTM_DELROUTE                     = 0x19
+	RTM_DELRULE                      = 0x21
+	RTM_DELTCLASS                    = 0x29
+	RTM_DELTFILTER                   = 0x2d
+	RTM_F_CLONED                     = 0x200
+	RTM_F_EQUALIZE                   = 0x400
+	RTM_F_NOTIFY                     = 0x100
+	RTM_F_PREFIX                     = 0x800
+	RTM_GETACTION                    = 0x32
+	RTM_GETADDR                      = 0x16
+	RTM_GETADDRLABEL                 = 0x4a
+	RTM_GETANYCAST                   = 0x3e
+	RTM_GETDCB                       = 0x4e
+	RTM_GETLINK                      = 0x12
+	RTM_GETMDB                       = 0x56
+	RTM_GETMULTICAST                 = 0x3a
+	RTM_GETNEIGH                     = 0x1e
+	RTM_GETNEIGHTBL                  = 0x42
+	RTM_GETNETCONF                   = 0x52
+	RTM_GETQDISC                     = 0x26
+	RTM_GETROUTE                     = 0x1a
+	RTM_GETRULE                      = 0x22
+	RTM_GETTCLASS                    = 0x2a
+	RTM_GETTFILTER                   = 0x2e
+	RTM_MAX                          = 0x57
+	RTM_NEWACTION                    = 0x30
+	RTM_NEWADDR                      = 0x14
+	RTM_NEWADDRLABEL                 = 0x48
+	RTM_NEWLINK                      = 0x10
+	RTM_NEWMDB                       = 0x54
+	RTM_NEWNDUSEROPT                 = 0x44
+	RTM_NEWNEIGH                     = 0x1c
+	RTM_NEWNEIGHTBL                  = 0x40
+	RTM_NEWNETCONF                   = 0x50
+	RTM_NEWPREFIX                    = 0x34
+	RTM_NEWQDISC                     = 0x24
+	RTM_NEWROUTE                     = 0x18
+	RTM_NEWRULE                      = 0x20
+	RTM_NEWTCLASS                    = 0x28
+	RTM_NEWTFILTER                   = 0x2c
+	RTM_NR_FAMILIES                  = 0x12
+	RTM_NR_MSGTYPES                  = 0x48
+	RTM_SETDCB                       = 0x4f
+	RTM_SETLINK                      = 0x13
+	RTM_SETNEIGHTBL                  = 0x43
+	RTNH_ALIGNTO                     = 0x4
+	RTNH_F_DEAD                      = 0x1
+	RTNH_F_ONLINK                    = 0x4
+	RTNH_F_PERVASIVE                 = 0x2
+	RTN_MAX                          = 0xb
+	RTPROT_BIRD                      = 0xc
+	RTPROT_BOOT                      = 0x3
+	RTPROT_DHCP                      = 0x10
+	RTPROT_DNROUTED                  = 0xd
+	RTPROT_GATED                     = 0x8
+	RTPROT_KERNEL                    = 0x2
+	RTPROT_MROUTED                   = 0x11
+	RTPROT_MRT                       = 0xa
+	RTPROT_NTK                       = 0xf
+	RTPROT_RA                        = 0x9
+	RTPROT_REDIRECT                  = 0x1
+	RTPROT_STATIC                    = 0x4
+	RTPROT_UNSPEC                    = 0x0
+	RTPROT_XORP                      = 0xe
+	RTPROT_ZEBRA                     = 0xb
+	RT_CLASS_DEFAULT                 = 0xfd
+	RT_CLASS_LOCAL                   = 0xff
+	RT_CLASS_MAIN                    = 0xfe
+	RT_CLASS_MAX                     = 0xff
+	RT_CLASS_UNSPEC                  = 0x0
+	RUSAGE_CHILDREN                  = -0x1
+	RUSAGE_SELF                      = 0x0
+	RUSAGE_THREAD                    = 0x1
+	SCM_CREDENTIALS                  = 0x2
+	SCM_RIGHTS                       = 0x1
+	SCM_TIMESTAMP                    = 0x1d
+	SCM_TIMESTAMPING                 = 0x25
+	SCM_TIMESTAMPNS                  = 0x23
+	SCM_WIFI_STATUS                  = 0x29
+	SHUT_RD                          = 0x0
+	SHUT_RDWR                        = 0x2
+	SHUT_WR                          = 0x1
+	SIOCADDDLCI                      = 0x8980
+	SIOCADDMULTI                     = 0x8931
+	SIOCADDRT                        = 0x890b
+	SIOCATMARK                       = 0x8905
+	SIOCDARP                         = 0x8953
+	SIOCDELDLCI                      = 0x8981
+	SIOCDELMULTI                     = 0x8932
+	SIOCDELRT                        = 0x890c
+	SIOCDEVPRIVATE                   = 0x89f0
+	SIOCDIFADDR                      = 0x8936
+	SIOCDRARP                        = 0x8960
+	SIOCGARP                         = 0x8954
+	SIOCGIFADDR                      = 0x8915
+	SIOCGIFBR                        = 0x8940
+	SIOCGIFBRDADDR                   = 0x8919
+	SIOCGIFCONF                      = 0x8912
+	SIOCGIFCOUNT                     = 0x8938
+	SIOCGIFDSTADDR                   = 0x8917
+	SIOCGIFENCAP                     = 0x8925
+	SIOCGIFFLAGS                     = 0x8913
+	SIOCGIFHWADDR                    = 0x8927
+	SIOCGIFINDEX                     = 0x8933
+	SIOCGIFMAP                       = 0x8970
+	SIOCGIFMEM                       = 0x891f
+	SIOCGIFMETRIC                    = 0x891d
+	SIOCGIFMTU                       = 0x8921
+	SIOCGIFNAME                      = 0x8910
+	SIOCGIFNETMASK                   = 0x891b
+	SIOCGIFPFLAGS                    = 0x8935
+	SIOCGIFSLAVE                     = 0x8929
+	SIOCGIFTXQLEN                    = 0x8942
+	SIOCGPGRP                        = 0x8904
+	SIOCGRARP                        = 0x8961
+	SIOCGSTAMP                       = 0x8906
+	SIOCGSTAMPNS                     = 0x8907
+	SIOCPROTOPRIVATE                 = 0x89e0
+	SIOCRTMSG                        = 0x890d
+	SIOCSARP                         = 0x8955
+	SIOCSIFADDR                      = 0x8916
+	SIOCSIFBR                        = 0x8941
+	SIOCSIFBRDADDR                   = 0x891a
+	SIOCSIFDSTADDR                   = 0x8918
+	SIOCSIFENCAP                     = 0x8926
+	SIOCSIFFLAGS                     = 0x8914
+	SIOCSIFHWADDR                    = 0x8924
+	SIOCSIFHWBROADCAST               = 0x8937
+	SIOCSIFLINK                      = 0x8911
+	SIOCSIFMAP                       = 0x8971
+	SIOCSIFMEM                       = 0x8920
+	SIOCSIFMETRIC                    = 0x891e
+	SIOCSIFMTU                       = 0x8922
+	SIOCSIFNAME                      = 0x8923
+	SIOCSIFNETMASK                   = 0x891c
+	SIOCSIFPFLAGS                    = 0x8934
+	SIOCSIFSLAVE                     = 0x8930
+	SIOCSIFTXQLEN                    = 0x8943
+	SIOCSPGRP                        = 0x8902
+	SIOCSRARP                        = 0x8962
+	SOCK_CLOEXEC                     = 0x80000
+	SOCK_DCCP                        = 0x6
+	SOCK_DGRAM                       = 0x2
+	SOCK_NONBLOCK                    = 0x800
+	SOCK_PACKET                      = 0xa
+	SOCK_RAW                         = 0x3
+	SOCK_RDM                         = 0x4
+	SOCK_SEQPACKET                   = 0x5
+	SOCK_STREAM                      = 0x1
+	SOL_AAL                          = 0x109
+	SOL_ATM                          = 0x108
+	SOL_DECNET                       = 0x105
+	SOL_ICMPV6                       = 0x3a
+	SOL_IP                           = 0x0
+	SOL_IPV6                         = 0x29
+	SOL_IRDA                         = 0x10a
+	SOL_PACKET                       = 0x107
+	SOL_RAW                          = 0xff
+	SOL_SOCKET                       = 0x1
+	SOL_TCP                          = 0x6
+	SOL_X25                          = 0x106
+	SOMAXCONN                        = 0x80
+	SO_ACCEPTCONN                    = 0x1e
+	SO_ATTACH_FILTER                 = 0x1a
+	SO_BINDTODEVICE                  = 0x19
+	SO_BROADCAST                     = 0x6
+	SO_BSDCOMPAT                     = 0xe
+	SO_BUSY_POLL                     = 0x2e
+	SO_DEBUG                         = 0x1
+	SO_DETACH_FILTER                 = 0x1b
+	SO_DOMAIN                        = 0x27
+	SO_DONTROUTE                     = 0x5
+	SO_ERROR                         = 0x4
+	SO_GET_FILTER                    = 0x1a
+	SO_KEEPALIVE                     = 0x9
+	SO_LINGER                        = 0xd
+	SO_LOCK_FILTER                   = 0x2c
+	SO_MARK                          = 0x24
+	SO_MAX_PACING_RATE               = 0x2f
+	SO_NOFCS                         = 0x2b
+	SO_NO_CHECK                      = 0xb
+	SO_OOBINLINE                     = 0xa
+	SO_PASSCRED                      = 0x10
+	SO_PASSSEC                       = 0x22
+	SO_PEEK_OFF                      = 0x2a
+	SO_PEERCRED                      = 0x11
+	SO_PEERNAME                      = 0x1c
+	SO_PEERSEC                       = 0x1f
+	SO_PRIORITY                      = 0xc
+	SO_PROTOCOL                      = 0x26
+	SO_RCVBUF                        = 0x8
+	SO_RCVBUFFORCE                   = 0x21
+	SO_RCVLOWAT                      = 0x12
+	SO_RCVTIMEO                      = 0x14
+	SO_REUSEADDR                     = 0x2
+	SO_REUSEPORT                     = 0xf
+	SO_RXQ_OVFL                      = 0x28
+	SO_SECURITY_AUTHENTICATION       = 0x16
+	SO_SECURITY_ENCRYPTION_NETWORK   = 0x18
+	SO_SECURITY_ENCRYPTION_TRANSPORT = 0x17
+	SO_SELECT_ERR_QUEUE              = 0x2d
+	SO_SNDBUF                        = 0x7
+	SO_SNDBUFFORCE                   = 0x20
+	SO_SNDLOWAT                      = 0x13
+	SO_SNDTIMEO                      = 0x15
+	SO_TIMESTAMP                     = 0x1d
+	SO_TIMESTAMPING                  = 0x25
+	SO_TIMESTAMPNS                   = 0x23
+	SO_TYPE                          = 0x3
+	SO_WIFI_STATUS                   = 0x29
+	S_BLKSIZE                        = 0x200
+	S_IEXEC                          = 0x40
+	S_IFBLK                          = 0x6000
+	S_IFCHR                          = 0x2000
+	S_IFDIR                          = 0x4000
+	S_IFIFO                          = 0x1000
+	S_IFLNK                          = 0xa000
+	S_IFMT                           = 0xf000
+	S_IFREG                          = 0x8000
+	S_IFSOCK                         = 0xc000
+	S_IREAD                          = 0x100
+	S_IRGRP                          = 0x20
+	S_IROTH                          = 0x4
+	S_IRUSR                          = 0x100
+	S_IRWXG                          = 0x38
+	S_IRWXO                          = 0x7
+	S_IRWXU                          = 0x1c0
+	S_ISGID                          = 0x400
+	S_ISUID                          = 0x800
+	S_ISVTX                          = 0x200
+	S_IWGRP                          = 0x10
+	S_IWOTH                          = 0x2
+	S_IWRITE                         = 0x80
+	S_IWUSR                          = 0x80
+	S_IXGRP                          = 0x8
+	S_IXOTH                          = 0x1
+	S_IXUSR                          = 0x40
+	TCFLSH                           = 0x540b
+	TCIFLUSH                         = 0x0
+	TCIOFLUSH                        = 0x2
+	TCOFLUSH                         = 0x1
+	TCP_CONGESTION                   = 0xd
+	TCP_COOKIE_IN_ALWAYS             = 0x1
+	TCP_COOKIE_MAX                   = 0x10
+	TCP_COOKIE_MIN                   = 0x8
+	TCP_COOKIE_OUT_NEVER             = 0x2
+	TCP_COOKIE_PAIR_SIZE             = 0x20
+	TCP_COOKIE_TRANSACTIONS          = 0xf
+	TCP_CORK                         = 0x3
+	TCP_DEFER_ACCEPT                 = 0x9
+	TCP_FASTOPEN                     = 0x17
+	TCP_INFO                         = 0xb
+	TCP_KEEPCNT                      = 0x6
+	TCP_KEEPIDLE                     = 0x4
+	TCP_KEEPINTVL                    = 0x5
+	TCP_LINGER2                      = 0x8
+	TCP_MAXSEG                       = 0x2
+	TCP_MAXWIN                       = 0xffff
+	TCP_MAX_WINSHIFT                 = 0xe
+	TCP_MD5SIG                       = 0xe
+	TCP_MD5SIG_MAXKEYLEN             = 0x50
+	TCP_MSS                          = 0x200
+	TCP_MSS_DEFAULT                  = 0x218
+	TCP_MSS_DESIRED                  = 0x4c4
+	TCP_NODELAY                      = 0x1
+	TCP_QUEUE_SEQ                    = 0x15
+	TCP_QUICKACK                     = 0xc
+	TCP_REPAIR                       = 0x13
+	TCP_REPAIR_OPTIONS               = 0x16
+	TCP_REPAIR_QUEUE                 = 0x14
+	TCP_SYNCNT                       = 0x7
+	TCP_S_DATA_IN                    = 0x4
+	TCP_S_DATA_OUT                   = 0x8
+	TCP_THIN_DUPACK                  = 0x11
+	TCP_THIN_LINEAR_TIMEOUTS         = 0x10
+	TCP_TIMESTAMP                    = 0x18
+	TCP_USER_TIMEOUT                 = 0x12
+	TCP_WINDOW_CLAMP                 = 0xa
+	TCSAFLUSH                        = 0x2
+	TIOCCBRK                         = 0x5428
+	TIOCCONS                         = 0x541d
+	TIOCEXCL                         = 0x540c
+	TIOCGDEV                         = 0x80045432
+	TIOCGETD                         = 0x5424
+	TIOCGEXCL                        = 0x80045440
+	TIOCGICOUNT                      = 0x545d
+	TIOCGLCKTRMIOS                   = 0x5456
+	TIOCGPGRP                        = 0x540f
+	TIOCGPKT                         = 0x80045438
+	TIOCGPTLCK                       = 0x80045439
+	TIOCGPTN                         = 0x80045430
+	TIOCGRS485                       = 0x542e
+	TIOCGSERIAL                      = 0x541e
+	TIOCGSID                         = 0x5429
+	TIOCGSOFTCAR                     = 0x5419
+	TIOCGWINSZ                       = 0x5413
+	TIOCINQ                          = 0x541b
+	TIOCLINUX                        = 0x541c
+	TIOCMBIC                         = 0x5417
+	TIOCMBIS                         = 0x5416
+	TIOCMGET                         = 0x5415
+	TIOCMIWAIT                       = 0x545c
+	TIOCMSET                         = 0x5418
+	TIOCM_CAR                        = 0x40
+	TIOCM_CD                         = 0x40
+	TIOCM_CTS                        = 0x20
+	TIOCM_DSR                        = 0x100
+	TIOCM_DTR                        = 0x2
+	TIOCM_LE                         = 0x1
+	TIOCM_RI                         = 0x80
+	TIOCM_RNG                        = 0x80
+	TIOCM_RTS                        = 0x4
+	TIOCM_SR                         = 0x10
+	TIOCM_ST                         = 0x8
+	TIOCNOTTY                        = 0x5422
+	TIOCNXCL                         = 0x540d
+	TIOCOUTQ                         = 0x5411
+	TIOCPKT                          = 0x5420
+	TIOCPKT_DATA                     = 0x0
+	TIOCPKT_DOSTOP                   = 0x20
+	TIOCPKT_FLUSHREAD                = 0x1
+	TIOCPKT_FLUSHWRITE               = 0x2
+	TIOCPKT_IOCTL                    = 0x40
+	TIOCPKT_NOSTOP                   = 0x10
+	TIOCPKT_START                    = 0x8
+	TIOCPKT_STOP                     = 0x4
+	TIOCSBRK                         = 0x5427
+	TIOCSCTTY                        = 0x540e
+	TIOCSERCONFIG                    = 0x5453
+	TIOCSERGETLSR                    = 0x5459
+	TIOCSERGETMULTI                  = 0x545a
+	TIOCSERGSTRUCT                   = 0x5458
+	TIOCSERGWILD                     = 0x5454
+	TIOCSERSETMULTI                  = 0x545b
+	TIOCSERSWILD                     = 0x5455
+	TIOCSER_TEMT                     = 0x1
+	TIOCSETD                         = 0x5423
+	TIOCSIG                          = 0x40045436
+	TIOCSLCKTRMIOS                   = 0x5457
+	TIOCSPGRP                        = 0x5410
+	TIOCSPTLCK                       = 0x40045431
+	TIOCSRS485                       = 0x542f
+	TIOCSSERIAL                      = 0x541f
+	TIOCSSOFTCAR                     = 0x541a
+	TIOCSTI                          = 0x5412
+	TIOCSWINSZ                       = 0x5414
+	TIOCVHANGUP                      = 0x5437
+	TOSTOP                           = 0x100
+	TUNATTACHFILTER                  = 0x401054d5
+	TUNDETACHFILTER                  = 0x401054d6
+	TUNGETFEATURES                   = 0x800454cf
+	TUNGETFILTER                     = 0x801054db
+	TUNGETIFF                        = 0x800454d2
+	TUNGETSNDBUF                     = 0x800454d3
+	TUNGETVNETHDRSZ                  = 0x800454d7
+	TUNSETDEBUG                      = 0x400454c9
+	TUNSETGROUP                      = 0x400454ce
+	TUNSETIFF                        = 0x400454ca
+	TUNSETIFINDEX                    = 0x400454da
+	TUNSETLINK                       = 0x400454cd
+	TUNSETNOCSUM                     = 0x400454c8
+	TUNSETOFFLOAD                    = 0x400454d0
+	TUNSETOWNER                      = 0x400454cc
+	TUNSETPERSIST                    = 0x400454cb
+	TUNSETQUEUE                      = 0x400454d9
+	TUNSETSNDBUF                     = 0x400454d4
+	TUNSETTXFILTER                   = 0x400454d1
+	TUNSETVNETHDRSZ                  = 0x400454d8
+	VDISCARD                         = 0xd
+	VEOF                             = 0x4
+	VEOL                             = 0xb
+	VEOL2                            = 0x10
+	VERASE                           = 0x2
+	VINTR                            = 0x0
+	VKILL                            = 0x3
+	VLNEXT                           = 0xf
+	VMIN                             = 0x6
+	VQUIT                            = 0x1
+	VREPRINT                         = 0xc
+	VSTART                           = 0x8
+	VSTOP                            = 0x9
+	VSUSP                            = 0xa
+	VSWTC                            = 0x7
+	VT0                              = 0x0
+	VT1                              = 0x4000
+	VTDLY                            = 0x4000
+	VTIME                            = 0x5
+	VWERASE                          = 0xe
+	WALL                             = 0x40000000
+	WCLONE                           = 0x80000000
+	WCONTINUED                       = 0x8
+	WEXITED                          = 0x4
+	WNOHANG                          = 0x1
+	WNOTHREAD                        = 0x20000000
+	WNOWAIT                          = 0x1000000
+	WORDSIZE                         = 0x40
+	WSTOPPED                         = 0x2
+	WUNTRACED                        = 0x2
+)
+
+// Errors
+const (
+	E2BIG           = Errno(0x7)
+	EACCES          = Errno(0xd)
+	EADDRINUSE      = Errno(0x62)
+	EADDRNOTAVAIL   = Errno(0x63)
+	EADV            = Errno(0x44)
+	EAFNOSUPPORT    = Errno(0x61)
+	EAGAIN          = Errno(0xb)
+	EALREADY        = Errno(0x72)
+	EBADE           = Errno(0x34)
+	EBADF           = Errno(0x9)
+	EBADFD          = Errno(0x4d)
+	EBADMSG         = Errno(0x4a)
+	EBADR           = Errno(0x35)
+	EBADRQC         = Errno(0x38)
+	EBADSLT         = Errno(0x39)
+	EBFONT          = Errno(0x3b)
+	EBUSY           = Errno(0x10)
+	ECANCELED       = Errno(0x7d)
+	ECHILD          = Errno(0xa)
+	ECHRNG          = Errno(0x2c)
+	ECOMM           = Errno(0x46)
+	ECONNABORTED    = Errno(0x67)
+	ECONNREFUSED    = Errno(0x6f)
+	ECONNRESET      = Errno(0x68)
+	EDEADLK         = Errno(0x23)
+	EDEADLOCK       = Errno(0x23)
+	EDESTADDRREQ    = Errno(0x59)
+	EDOM            = Errno(0x21)
+	EDOTDOT         = Errno(0x49)
+	EDQUOT          = Errno(0x7a)
+	EEXIST          = Errno(0x11)
+	EFAULT          = Errno(0xe)
+	EFBIG           = Errno(0x1b)
+	EHOSTDOWN       = Errno(0x70)
+	EHOSTUNREACH    = Errno(0x71)
+	EHWPOISON       = Errno(0x85)
+	EIDRM           = Errno(0x2b)
+	EILSEQ          = Errno(0x54)
+	EINPROGRESS     = Errno(0x73)
+	EINTR           = Errno(0x4)
+	EINVAL          = Errno(0x16)
+	EIO             = Errno(0x5)
+	EISCONN         = Errno(0x6a)
+	EISDIR          = Errno(0x15)
+	EISNAM          = Errno(0x78)
+	EKEYEXPIRED     = Errno(0x7f)
+	EKEYREJECTED    = Errno(0x81)
+	EKEYREVOKED     = Errno(0x80)
+	EL2HLT          = Errno(0x33)
+	EL2NSYNC        = Errno(0x2d)
+	EL3HLT          = Errno(0x2e)
+	EL3RST          = Errno(0x2f)
+	ELIBACC         = Errno(0x4f)
+	ELIBBAD         = Errno(0x50)
+	ELIBEXEC        = Errno(0x53)
+	ELIBMAX         = Errno(0x52)
+	ELIBSCN         = Errno(0x51)
+	ELNRNG          = Errno(0x30)
+	ELOOP           = Errno(0x28)
+	EMEDIUMTYPE     = Errno(0x7c)
+	EMFILE          = Errno(0x18)
+	EMLINK          = Errno(0x1f)
+	EMSGSIZE        = Errno(0x5a)
+	EMULTIHOP       = Errno(0x48)
+	ENAMETOOLONG    = Errno(0x24)
+	ENAVAIL         = Errno(0x77)
+	ENETDOWN        = Errno(0x64)
+	ENETRESET       = Errno(0x66)
+	ENETUNREACH     = Errno(0x65)
+	ENFILE          = Errno(0x17)
+	ENOANO          = Errno(0x37)
+	ENOBUFS         = Errno(0x69)
+	ENOCSI          = Errno(0x32)
+	ENODATA         = Errno(0x3d)
+	ENODEV          = Errno(0x13)
+	ENOENT          = Errno(0x2)
+	ENOEXEC         = Errno(0x8)
+	ENOKEY          = Errno(0x7e)
+	ENOLCK          = Errno(0x25)
+	ENOLINK         = Errno(0x43)
+	ENOMEDIUM       = Errno(0x7b)
+	ENOMEM          = Errno(0xc)
+	ENOMSG          = Errno(0x2a)
+	ENONET          = Errno(0x40)
+	ENOPKG          = Errno(0x41)
+	ENOPROTOOPT     = Errno(0x5c)
+	ENOSPC          = Errno(0x1c)
+	ENOSR           = Errno(0x3f)
+	ENOSTR          = Errno(0x3c)
+	ENOSYS          = Errno(0x26)
+	ENOTBLK         = Errno(0xf)
+	ENOTCONN        = Errno(0x6b)
+	ENOTDIR         = Errno(0x14)
+	ENOTEMPTY       = Errno(0x27)
+	ENOTNAM         = Errno(0x76)
+	ENOTRECOVERABLE = Errno(0x83)
+	ENOTSOCK        = Errno(0x58)
+	ENOTSUP         = Errno(0x5f)
+	ENOTTY          = Errno(0x19)
+	ENOTUNIQ        = Errno(0x4c)
+	ENXIO           = Errno(0x6)
+	EOPNOTSUPP      = Errno(0x5f)
+	EOVERFLOW       = Errno(0x4b)
+	EOWNERDEAD      = Errno(0x82)
+	EPERM           = Errno(0x1)
+	EPFNOSUPPORT    = Errno(0x60)
+	EPIPE           = Errno(0x20)
+	EPROTO          = Errno(0x47)
+	EPROTONOSUPPORT = Errno(0x5d)
+	EPROTOTYPE      = Errno(0x5b)
+	ERANGE          = Errno(0x22)
+	EREMCHG         = Errno(0x4e)
+	EREMOTE         = Errno(0x42)
+	EREMOTEIO       = Errno(0x79)
+	ERESTART        = Errno(0x55)
+	ERFKILL         = Errno(0x84)
+	EROFS           = Errno(0x1e)
+	ESHUTDOWN       = Errno(0x6c)
+	ESOCKTNOSUPPORT = Errno(0x5e)
+	ESPIPE          = Errno(0x1d)
+	ESRCH           = Errno(0x3)
+	ESRMNT          = Errno(0x45)
+	ESTALE          = Errno(0x74)
+	ESTRPIPE        = Errno(0x56)
+	ETIME           = Errno(0x3e)
+	ETIMEDOUT       = Errno(0x6e)
+	ETOOMANYREFS    = Errno(0x6d)
+	ETXTBSY         = Errno(0x1a)
+	EUCLEAN         = Errno(0x75)
+	EUNATCH         = Errno(0x31)
+	EUSERS          = Errno(0x57)
+	EWOULDBLOCK     = Errno(0xb)
+	EXDEV           = Errno(0x12)
+	EXFULL          = Errno(0x36)
+)
+
+// Signals
+const (
+	SIGABRT   = Signal(0x6)
+	SIGALRM   = Signal(0xe)
+	SIGBUS    = Signal(0x7)
+	SIGCHLD   = Signal(0x11)
+	SIGCLD    = Signal(0x11)
+	SIGCONT   = Signal(0x12)
+	SIGFPE    = Signal(0x8)
+	SIGHUP    = Signal(0x1)
+	SIGILL    = Signal(0x4)
+	SIGINT    = Signal(0x2)
+	SIGIO     = Signal(0x1d)
+	SIGIOT    = Signal(0x6)
+	SIGKILL   = Signal(0x9)
+	SIGPIPE   = Signal(0xd)
+	SIGPOLL   = Signal(0x1d)
+	SIGPROF   = Signal(0x1b)
+	SIGPWR    = Signal(0x1e)
+	SIGQUIT   = Signal(0x3)
+	SIGSEGV   = Signal(0xb)
+	SIGSTKFLT = Signal(0x10)
+	SIGSTOP   = Signal(0x13)
+	SIGSYS    = Signal(0x1f)
+	SIGTERM   = Signal(0xf)
+	SIGTRAP   = Signal(0x5)
+	SIGTSTP   = Signal(0x14)
+	SIGTTIN   = Signal(0x15)
+	SIGTTOU   = Signal(0x16)
+	SIGUNUSED = Signal(0x1f)
+	SIGURG    = Signal(0x17)
+	SIGUSR1   = Signal(0xa)
+	SIGUSR2   = Signal(0xc)
+	SIGVTALRM = Signal(0x1a)
+	SIGWINCH  = Signal(0x1c)
+	SIGXCPU   = Signal(0x18)
+	SIGXFSZ   = Signal(0x19)
+)
+
+// Error table
+var errors = [...]string{
+	1:   "operation not permitted",
+	2:   "no such file or directory",
+	3:   "no such process",
+	4:   "interrupted system call",
+	5:   "input/output error",
+	6:   "no such device or address",
+	7:   "argument list too long",
+	8:   "exec format error",
+	9:   "bad file descriptor",
+	10:  "no child processes",
+	11:  "resource temporarily unavailable",
+	12:  "cannot allocate memory",
+	13:  "permission denied",
+	14:  "bad address",
+	15:  "block device required",
+	16:  "device or resource busy",
+	17:  "file exists",
+	18:  "invalid cross-device link",
+	19:  "no such device",
+	20:  "not a directory",
+	21:  "is a directory",
+	22:  "invalid argument",
+	23:  "too many open files in system",
+	24:  "too many open files",
+	25:  "inappropriate ioctl for device",
+	26:  "text file busy",
+	27:  "file too large",
+	28:  "no space left on device",
+	29:  "illegal seek",
+	30:  "read-only file system",
+	31:  "too many links",
+	32:  "broken pipe",
+	33:  "numerical argument out of domain",
+	34:  "numerical result out of range",
+	35:  "resource deadlock avoided",
+	36:  "file name too long",
+	37:  "no locks available",
+	38:  "function not implemented",
+	39:  "directory not empty",
+	40:  "too many levels of symbolic links",
+	42:  "no message of desired type",
+	43:  "identifier removed",
+	44:  "channel number out of range",
+	45:  "level 2 not synchronized",
+	46:  "level 3 halted",
+	47:  "level 3 reset",
+	48:  "link number out of range",
+	49:  "protocol driver not attached",
+	50:  "no CSI structure available",
+	51:  "level 2 halted",
+	52:  "invalid exchange",
+	53:  "invalid request descriptor",
+	54:  "exchange full",
+	55:  "no anode",
+	56:  "invalid request code",
+	57:  "invalid slot",
+	59:  "bad font file format",
+	60:  "device not a stream",
+	61:  "no data available",
+	62:  "timer expired",
+	63:  "out of streams resources",
+	64:  "machine is not on the network",
+	65:  "package not installed",
+	66:  "object is remote",
+	67:  "link has been severed",
+	68:  "advertise error",
+	69:  "srmount error",
+	70:  "communication error on send",
+	71:  "protocol error",
+	72:  "multihop attempted",
+	73:  "RFS specific error",
+	74:  "bad message",
+	75:  "value too large for defined data type",
+	76:  "name not unique on network",
+	77:  "file descriptor in bad state",
+	78:  "remote address changed",
+	79:  "can not access a needed shared library",
+	80:  "accessing a corrupted shared library",
+	81:  ".lib section in a.out corrupted",
+	82:  "attempting to link in too many shared libraries",
+	83:  "cannot exec a shared library directly",
+	84:  "invalid or incomplete multibyte or wide character",
+	85:  "interrupted system call should be restarted",
+	86:  "streams pipe error",
+	87:  "too many users",
+	88:  "socket operation on non-socket",
+	89:  "destination address required",
+	90:  "message too long",
+	91:  "protocol wrong type for socket",
+	92:  "protocol not available",
+	93:  "protocol not supported",
+	94:  "socket type not supported",
+	95:  "operation not supported",
+	96:  "protocol family not supported",
+	97:  "address family not supported by protocol",
+	98:  "address already in use",
+	99:  "cannot assign requested address",
+	100: "network is down",
+	101: "network is unreachable",
+	102: "network dropped connection on reset",
+	103: "software caused connection abort",
+	104: "connection reset by peer",
+	105: "no buffer space available",
+	106: "transport endpoint is already connected",
+	107: "transport endpoint is not connected",
+	108: "cannot send after transport endpoint shutdown",
+	109: "too many references: cannot splice",
+	110: "connection timed out",
+	111: "connection refused",
+	112: "host is down",
+	113: "no route to host",
+	114: "operation already in progress",
+	115: "operation now in progress",
+	116: "stale file handle",
+	117: "structure needs cleaning",
+	118: "not a XENIX named type file",
+	119: "no XENIX semaphores available",
+	120: "is a named type file",
+	121: "remote I/O error",
+	122: "disk quota exceeded",
+	123: "no medium found",
+	124: "wrong medium type",
+	125: "operation canceled",
+	126: "required key not available",
+	127: "key has expired",
+	128: "key has been revoked",
+	129: "key was rejected by service",
+	130: "owner died",
+	131: "state not recoverable",
+	132: "operation not possible due to RF-kill",
+	133: "memory page has hardware error",
+}
+
+// Signal table
+var signals = [...]string{
+	1:  "hangup",
+	2:  "interrupt",
+	3:  "quit",
+	4:  "illegal instruction",
+	5:  "trace/breakpoint trap",
+	6:  "aborted",
+	7:  "bus error",
+	8:  "floating point exception",
+	9:  "killed",
+	10: "user defined signal 1",
+	11: "segmentation fault",
+	12: "user defined signal 2",
+	13: "broken pipe",
+	14: "alarm clock",
+	15: "terminated",
+	16: "stack fault",
+	17: "child exited",
+	18: "continued",
+	19: "stopped (signal)",
+	20: "stopped",
+	21: "stopped (tty input)",
+	22: "stopped (tty output)",
+	23: "urgent I/O condition",
+	24: "CPU time limit exceeded",
+	25: "file size limit exceeded",
+	26: "virtual timer expired",
+	27: "profiling timer expired",
+	28: "window changed",
+	29: "I/O possible",
+	30: "power failure",
+	31: "bad system call",
+}
diff --git a/src/syscall/zerrors_dragonfly_386.go b/src/syscall/zerrors_openbsd_arm.go
similarity index 65%
rename from src/syscall/zerrors_dragonfly_386.go
rename to src/syscall/zerrors_openbsd_arm.go
index 701a1c3..5376fe6 100644
--- a/src/syscall/zerrors_dragonfly_386.go
+++ b/src/syscall/zerrors_openbsd_arm.go
@@ -1,15 +1,14 @@
-// mkerrors.sh -m32
+// mkerrors.sh
 // MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
 
 // Created by cgo -godefs - DO NOT EDIT
-// cgo -godefs -- -m32 _const.go
+// cgo -godefs -- _const.go
 
 package syscall
 
 const (
 	AF_APPLETALK                      = 0x10
-	AF_ATM                            = 0x1e
-	AF_BLUETOOTH                      = 0x21
+	AF_BLUETOOTH                      = 0x20
 	AF_CCITT                          = 0xa
 	AF_CHAOS                          = 0x5
 	AF_CNT                            = 0x15
@@ -19,29 +18,33 @@
 	AF_DLI                            = 0xd
 	AF_E164                           = 0x1a
 	AF_ECMA                           = 0x8
+	AF_ENCAP                          = 0x1c
 	AF_HYLINK                         = 0xf
-	AF_IEEE80211                      = 0x23
 	AF_IMPLINK                        = 0x3
 	AF_INET                           = 0x2
-	AF_INET6                          = 0x1c
+	AF_INET6                          = 0x18
 	AF_IPX                            = 0x17
 	AF_ISDN                           = 0x1a
 	AF_ISO                            = 0x7
+	AF_KEY                            = 0x1e
 	AF_LAT                            = 0xe
 	AF_LINK                           = 0x12
 	AF_LOCAL                          = 0x1
 	AF_MAX                            = 0x24
-	AF_MPLS                           = 0x22
-	AF_NATM                           = 0x1d
-	AF_NETGRAPH                       = 0x20
+	AF_MPLS                           = 0x21
+	AF_NATM                           = 0x1b
 	AF_NS                             = 0x6
 	AF_OSI                            = 0x7
 	AF_PUP                            = 0x4
 	AF_ROUTE                          = 0x11
-	AF_SIP                            = 0x18
+	AF_SIP                            = 0x1d
 	AF_SNA                            = 0xb
 	AF_UNIX                           = 0x1
 	AF_UNSPEC                         = 0x0
+	ARPHRD_ETHER                      = 0x1
+	ARPHRD_FRELAY                     = 0xf
+	ARPHRD_IEEE1394                   = 0x18
+	ARPHRD_IEEE802                    = 0x6
 	B0                                = 0x0
 	B110                              = 0x6e
 	B115200                           = 0x1c200
@@ -67,26 +70,28 @@
 	B9600                             = 0x2580
 	BIOCFLUSH                         = 0x20004268
 	BIOCGBLEN                         = 0x40044266
+	BIOCGDIRFILT                      = 0x4004427c
 	BIOCGDLT                          = 0x4004426a
-	BIOCGDLTLIST                      = 0xc0084279
+	BIOCGDLTLIST                      = 0xc008427b
 	BIOCGETIF                         = 0x4020426b
+	BIOCGFILDROP                      = 0x40044278
 	BIOCGHDRCMPLT                     = 0x40044274
-	BIOCGRSIG                         = 0x40044272
-	BIOCGRTIMEOUT                     = 0x4008426e
-	BIOCGSEESENT                      = 0x40044276
+	BIOCGRSIG                         = 0x40044273
+	BIOCGRTIMEOUT                     = 0x400c426e
 	BIOCGSTATS                        = 0x4008426f
 	BIOCIMMEDIATE                     = 0x80044270
-	BIOCLOCK                          = 0x2000427a
+	BIOCLOCK                          = 0x20004276
 	BIOCPROMISC                       = 0x20004269
 	BIOCSBLEN                         = 0xc0044266
-	BIOCSDLT                          = 0x80044278
+	BIOCSDIRFILT                      = 0x8004427d
+	BIOCSDLT                          = 0x8004427a
 	BIOCSETF                          = 0x80084267
 	BIOCSETIF                         = 0x8020426c
-	BIOCSETWF                         = 0x8008427b
+	BIOCSETWF                         = 0x80084277
+	BIOCSFILDROP                      = 0x80044279
 	BIOCSHDRCMPLT                     = 0x80044275
-	BIOCSRSIG                         = 0x80044273
-	BIOCSRTIMEOUT                     = 0x8008426d
-	BIOCSSEESENT                      = 0x80044277
+	BIOCSRSIG                         = 0x80044272
+	BIOCSRTIMEOUT                     = 0x800c426d
 	BIOCVERSION                       = 0x40044271
 	BPF_A                             = 0x10
 	BPF_ABS                           = 0x20
@@ -95,7 +100,8 @@
 	BPF_ALU                           = 0x4
 	BPF_AND                           = 0x50
 	BPF_B                             = 0x10
-	BPF_DEFAULTBUFSIZE                = 0x1000
+	BPF_DIRECTION_IN                  = 0x1
+	BPF_DIRECTION_OUT                 = 0x2
 	BPF_DIV                           = 0x30
 	BPF_H                             = 0x8
 	BPF_IMM                           = 0x0
@@ -112,9 +118,8 @@
 	BPF_LEN                           = 0x80
 	BPF_LSH                           = 0x60
 	BPF_MAJOR_VERSION                 = 0x1
-	BPF_MAXBUFSIZE                    = 0x80000
+	BPF_MAXBUFSIZE                    = 0x200000
 	BPF_MAXINSNS                      = 0x200
-	BPF_MAX_CLONES                    = 0x80
 	BPF_MEM                           = 0x60
 	BPF_MEMWORDS                      = 0x10
 	BPF_MINBUFSIZE                    = 0x20
@@ -144,135 +149,46 @@
 	CS8                               = 0x300
 	CSIZE                             = 0x300
 	CSTART                            = 0x11
-	CSTATUS                           = 0x14
+	CSTATUS                           = 0xff
 	CSTOP                             = 0x13
 	CSTOPB                            = 0x400
 	CSUSP                             = 0x1a
 	CTL_MAXNAME                       = 0xc
 	CTL_NET                           = 0x4
-	DLT_A429                          = 0xb8
-	DLT_A653_ICM                      = 0xb9
-	DLT_AIRONET_HEADER                = 0x78
-	DLT_APPLE_IP_OVER_IEEE1394        = 0x8a
+	DIOCOSFPFLUSH                     = 0x2000444e
 	DLT_ARCNET                        = 0x7
-	DLT_ARCNET_LINUX                  = 0x81
-	DLT_ATM_CLIP                      = 0x13
 	DLT_ATM_RFC1483                   = 0xb
-	DLT_AURORA                        = 0x7e
 	DLT_AX25                          = 0x3
-	DLT_AX25_KISS                     = 0xca
-	DLT_BACNET_MS_TP                  = 0xa5
-	DLT_BLUETOOTH_HCI_H4              = 0xbb
-	DLT_BLUETOOTH_HCI_H4_WITH_PHDR    = 0xc9
-	DLT_CAN20B                        = 0xbe
 	DLT_CHAOS                         = 0x5
-	DLT_CHDLC                         = 0x68
-	DLT_CISCO_IOS                     = 0x76
 	DLT_C_HDLC                        = 0x68
-	DLT_C_HDLC_WITH_DIR               = 0xcd
-	DLT_DOCSIS                        = 0x8f
-	DLT_ECONET                        = 0x73
 	DLT_EN10MB                        = 0x1
 	DLT_EN3MB                         = 0x2
-	DLT_ENC                           = 0x6d
-	DLT_ERF                           = 0xc5
-	DLT_ERF_ETH                       = 0xaf
-	DLT_ERF_POS                       = 0xb0
+	DLT_ENC                           = 0xd
 	DLT_FDDI                          = 0xa
-	DLT_FLEXRAY                       = 0xd2
-	DLT_FRELAY                        = 0x6b
-	DLT_FRELAY_WITH_DIR               = 0xce
-	DLT_GCOM_SERIAL                   = 0xad
-	DLT_GCOM_T1E1                     = 0xac
-	DLT_GPF_F                         = 0xab
-	DLT_GPF_T                         = 0xaa
-	DLT_GPRS_LLC                      = 0xa9
-	DLT_HHDLC                         = 0x79
-	DLT_IBM_SN                        = 0x92
-	DLT_IBM_SP                        = 0x91
 	DLT_IEEE802                       = 0x6
 	DLT_IEEE802_11                    = 0x69
 	DLT_IEEE802_11_RADIO              = 0x7f
-	DLT_IEEE802_11_RADIO_AVS          = 0xa3
-	DLT_IEEE802_15_4                  = 0xc3
-	DLT_IEEE802_15_4_LINUX            = 0xbf
-	DLT_IEEE802_15_4_NONASK_PHY       = 0xd7
-	DLT_IEEE802_16_MAC_CPS            = 0xbc
-	DLT_IEEE802_16_MAC_CPS_RADIO      = 0xc1
-	DLT_IPFILTER                      = 0x74
-	DLT_IPMB                          = 0xc7
-	DLT_IPMB_LINUX                    = 0xd1
-	DLT_IP_OVER_FC                    = 0x7a
-	DLT_JUNIPER_ATM1                  = 0x89
-	DLT_JUNIPER_ATM2                  = 0x87
-	DLT_JUNIPER_CHDLC                 = 0xb5
-	DLT_JUNIPER_ES                    = 0x84
-	DLT_JUNIPER_ETHER                 = 0xb2
-	DLT_JUNIPER_FRELAY                = 0xb4
-	DLT_JUNIPER_GGSN                  = 0x85
-	DLT_JUNIPER_ISM                   = 0xc2
-	DLT_JUNIPER_MFR                   = 0x86
-	DLT_JUNIPER_MLFR                  = 0x83
-	DLT_JUNIPER_MLPPP                 = 0x82
-	DLT_JUNIPER_MONITOR               = 0xa4
-	DLT_JUNIPER_PIC_PEER              = 0xae
-	DLT_JUNIPER_PPP                   = 0xb3
-	DLT_JUNIPER_PPPOE                 = 0xa7
-	DLT_JUNIPER_PPPOE_ATM             = 0xa8
-	DLT_JUNIPER_SERVICES              = 0x88
-	DLT_JUNIPER_ST                    = 0xc8
-	DLT_JUNIPER_VP                    = 0xb7
-	DLT_LAPB_WITH_DIR                 = 0xcf
-	DLT_LAPD                          = 0xcb
-	DLT_LIN                           = 0xd4
-	DLT_LINUX_IRDA                    = 0x90
-	DLT_LINUX_LAPD                    = 0xb1
-	DLT_LINUX_SLL                     = 0x71
-	DLT_LOOP                          = 0x6c
-	DLT_LTALK                         = 0x72
-	DLT_MFR                           = 0xb6
-	DLT_MOST                          = 0xd3
-	DLT_MTP2                          = 0x8c
-	DLT_MTP2_WITH_PHDR                = 0x8b
-	DLT_MTP3                          = 0x8d
+	DLT_LOOP                          = 0xc
+	DLT_MPLS                          = 0xdb
 	DLT_NULL                          = 0x0
-	DLT_PCI_EXP                       = 0x7d
 	DLT_PFLOG                         = 0x75
 	DLT_PFSYNC                        = 0x12
-	DLT_PPI                           = 0xc0
 	DLT_PPP                           = 0x9
 	DLT_PPP_BSDOS                     = 0x10
 	DLT_PPP_ETHER                     = 0x33
-	DLT_PPP_PPPD                      = 0xa6
 	DLT_PPP_SERIAL                    = 0x32
-	DLT_PPP_WITH_DIR                  = 0xcc
-	DLT_PRISM_HEADER                  = 0x77
 	DLT_PRONET                        = 0x4
-	DLT_RAIF1                         = 0xc6
-	DLT_RAW                           = 0xc
-	DLT_REDBACK_SMARTEDGE             = 0x20
-	DLT_RIO                           = 0x7c
-	DLT_SCCP                          = 0x8e
-	DLT_SITA                          = 0xc4
+	DLT_RAW                           = 0xe
 	DLT_SLIP                          = 0x8
 	DLT_SLIP_BSDOS                    = 0xf
-	DLT_SUNATM                        = 0x7b
-	DLT_SYMANTEC_FIREWALL             = 0x63
-	DLT_TZSP                          = 0x80
-	DLT_USB                           = 0xba
-	DLT_USB_LINUX                     = 0xbd
-	DLT_X2E_SERIAL                    = 0xd5
-	DLT_X2E_XORAYA                    = 0xd6
 	DT_BLK                            = 0x6
 	DT_CHR                            = 0x2
-	DT_DBF                            = 0xf
 	DT_DIR                            = 0x4
 	DT_FIFO                           = 0x1
 	DT_LNK                            = 0xa
 	DT_REG                            = 0x8
 	DT_SOCK                           = 0xc
 	DT_UNKNOWN                        = 0x0
-	DT_WHT                            = 0xe
 	ECHO                              = 0x8
 	ECHOCTL                           = 0x40
 	ECHOE                             = 0x2
@@ -280,13 +196,213 @@
 	ECHOKE                            = 0x1
 	ECHONL                            = 0x10
 	ECHOPRT                           = 0x20
+	EMT_TAGOVF                        = 0x1
+	EMUL_ENABLED                      = 0x1
+	EMUL_NATIVE                       = 0x2
+	ENDRUNDISC                        = 0x9
+	ETHERMIN                          = 0x2e
+	ETHERMTU                          = 0x5dc
+	ETHERTYPE_8023                    = 0x4
+	ETHERTYPE_AARP                    = 0x80f3
+	ETHERTYPE_ACCTON                  = 0x8390
+	ETHERTYPE_AEONIC                  = 0x8036
+	ETHERTYPE_ALPHA                   = 0x814a
+	ETHERTYPE_AMBER                   = 0x6008
+	ETHERTYPE_AMOEBA                  = 0x8145
+	ETHERTYPE_AOE                     = 0x88a2
+	ETHERTYPE_APOLLO                  = 0x80f7
+	ETHERTYPE_APOLLODOMAIN            = 0x8019
+	ETHERTYPE_APPLETALK               = 0x809b
+	ETHERTYPE_APPLITEK                = 0x80c7
+	ETHERTYPE_ARGONAUT                = 0x803a
+	ETHERTYPE_ARP                     = 0x806
+	ETHERTYPE_AT                      = 0x809b
+	ETHERTYPE_ATALK                   = 0x809b
+	ETHERTYPE_ATOMIC                  = 0x86df
+	ETHERTYPE_ATT                     = 0x8069
+	ETHERTYPE_ATTSTANFORD             = 0x8008
+	ETHERTYPE_AUTOPHON                = 0x806a
+	ETHERTYPE_AXIS                    = 0x8856
+	ETHERTYPE_BCLOOP                  = 0x9003
+	ETHERTYPE_BOFL                    = 0x8102
+	ETHERTYPE_CABLETRON               = 0x7034
+	ETHERTYPE_CHAOS                   = 0x804
+	ETHERTYPE_COMDESIGN               = 0x806c
+	ETHERTYPE_COMPUGRAPHIC            = 0x806d
+	ETHERTYPE_COUNTERPOINT            = 0x8062
+	ETHERTYPE_CRONUS                  = 0x8004
+	ETHERTYPE_CRONUSVLN               = 0x8003
+	ETHERTYPE_DCA                     = 0x1234
+	ETHERTYPE_DDE                     = 0x807b
+	ETHERTYPE_DEBNI                   = 0xaaaa
+	ETHERTYPE_DECAM                   = 0x8048
+	ETHERTYPE_DECCUST                 = 0x6006
+	ETHERTYPE_DECDIAG                 = 0x6005
+	ETHERTYPE_DECDNS                  = 0x803c
+	ETHERTYPE_DECDTS                  = 0x803e
+	ETHERTYPE_DECEXPER                = 0x6000
+	ETHERTYPE_DECLAST                 = 0x8041
+	ETHERTYPE_DECLTM                  = 0x803f
+	ETHERTYPE_DECMUMPS                = 0x6009
+	ETHERTYPE_DECNETBIOS              = 0x8040
+	ETHERTYPE_DELTACON                = 0x86de
+	ETHERTYPE_DIDDLE                  = 0x4321
+	ETHERTYPE_DLOG1                   = 0x660
+	ETHERTYPE_DLOG2                   = 0x661
+	ETHERTYPE_DN                      = 0x6003
+	ETHERTYPE_DOGFIGHT                = 0x1989
+	ETHERTYPE_DSMD                    = 0x8039
+	ETHERTYPE_ECMA                    = 0x803
+	ETHERTYPE_ENCRYPT                 = 0x803d
+	ETHERTYPE_ES                      = 0x805d
+	ETHERTYPE_EXCELAN                 = 0x8010
+	ETHERTYPE_EXPERDATA               = 0x8049
+	ETHERTYPE_FLIP                    = 0x8146
+	ETHERTYPE_FLOWCONTROL             = 0x8808
+	ETHERTYPE_FRARP                   = 0x808
+	ETHERTYPE_GENDYN                  = 0x8068
+	ETHERTYPE_HAYES                   = 0x8130
+	ETHERTYPE_HIPPI_FP                = 0x8180
+	ETHERTYPE_HITACHI                 = 0x8820
+	ETHERTYPE_HP                      = 0x8005
+	ETHERTYPE_IEEEPUP                 = 0xa00
+	ETHERTYPE_IEEEPUPAT               = 0xa01
+	ETHERTYPE_IMLBL                   = 0x4c42
+	ETHERTYPE_IMLBLDIAG               = 0x424c
+	ETHERTYPE_IP                      = 0x800
+	ETHERTYPE_IPAS                    = 0x876c
+	ETHERTYPE_IPV6                    = 0x86dd
+	ETHERTYPE_IPX                     = 0x8137
+	ETHERTYPE_IPXNEW                  = 0x8037
+	ETHERTYPE_KALPANA                 = 0x8582
+	ETHERTYPE_LANBRIDGE               = 0x8038
+	ETHERTYPE_LANPROBE                = 0x8888
+	ETHERTYPE_LAT                     = 0x6004
+	ETHERTYPE_LBACK                   = 0x9000
+	ETHERTYPE_LITTLE                  = 0x8060
+	ETHERTYPE_LLDP                    = 0x88cc
+	ETHERTYPE_LOGICRAFT               = 0x8148
+	ETHERTYPE_LOOPBACK                = 0x9000
+	ETHERTYPE_MATRA                   = 0x807a
+	ETHERTYPE_MAX                     = 0xffff
+	ETHERTYPE_MERIT                   = 0x807c
+	ETHERTYPE_MICP                    = 0x873a
+	ETHERTYPE_MOPDL                   = 0x6001
+	ETHERTYPE_MOPRC                   = 0x6002
+	ETHERTYPE_MOTOROLA                = 0x818d
+	ETHERTYPE_MPLS                    = 0x8847
+	ETHERTYPE_MPLS_MCAST              = 0x8848
+	ETHERTYPE_MUMPS                   = 0x813f
+	ETHERTYPE_NBPCC                   = 0x3c04
+	ETHERTYPE_NBPCLAIM                = 0x3c09
+	ETHERTYPE_NBPCLREQ                = 0x3c05
+	ETHERTYPE_NBPCLRSP                = 0x3c06
+	ETHERTYPE_NBPCREQ                 = 0x3c02
+	ETHERTYPE_NBPCRSP                 = 0x3c03
+	ETHERTYPE_NBPDG                   = 0x3c07
+	ETHERTYPE_NBPDGB                  = 0x3c08
+	ETHERTYPE_NBPDLTE                 = 0x3c0a
+	ETHERTYPE_NBPRAR                  = 0x3c0c
+	ETHERTYPE_NBPRAS                  = 0x3c0b
+	ETHERTYPE_NBPRST                  = 0x3c0d
+	ETHERTYPE_NBPSCD                  = 0x3c01
+	ETHERTYPE_NBPVCD                  = 0x3c00
+	ETHERTYPE_NBS                     = 0x802
+	ETHERTYPE_NCD                     = 0x8149
+	ETHERTYPE_NESTAR                  = 0x8006
+	ETHERTYPE_NETBEUI                 = 0x8191
+	ETHERTYPE_NOVELL                  = 0x8138
+	ETHERTYPE_NS                      = 0x600
+	ETHERTYPE_NSAT                    = 0x601
+	ETHERTYPE_NSCOMPAT                = 0x807
+	ETHERTYPE_NTRAILER                = 0x10
+	ETHERTYPE_OS9                     = 0x7007
+	ETHERTYPE_OS9NET                  = 0x7009
+	ETHERTYPE_PACER                   = 0x80c6
+	ETHERTYPE_PAE                     = 0x888e
+	ETHERTYPE_PCS                     = 0x4242
+	ETHERTYPE_PLANNING                = 0x8044
+	ETHERTYPE_PPP                     = 0x880b
+	ETHERTYPE_PPPOE                   = 0x8864
+	ETHERTYPE_PPPOEDISC               = 0x8863
+	ETHERTYPE_PRIMENTS                = 0x7031
+	ETHERTYPE_PUP                     = 0x200
+	ETHERTYPE_PUPAT                   = 0x200
+	ETHERTYPE_QINQ                    = 0x88a8
+	ETHERTYPE_RACAL                   = 0x7030
+	ETHERTYPE_RATIONAL                = 0x8150
+	ETHERTYPE_RAWFR                   = 0x6559
+	ETHERTYPE_RCL                     = 0x1995
+	ETHERTYPE_RDP                     = 0x8739
+	ETHERTYPE_RETIX                   = 0x80f2
+	ETHERTYPE_REVARP                  = 0x8035
+	ETHERTYPE_SCA                     = 0x6007
+	ETHERTYPE_SECTRA                  = 0x86db
+	ETHERTYPE_SECUREDATA              = 0x876d
+	ETHERTYPE_SGITW                   = 0x817e
+	ETHERTYPE_SG_BOUNCE               = 0x8016
+	ETHERTYPE_SG_DIAG                 = 0x8013
+	ETHERTYPE_SG_NETGAMES             = 0x8014
+	ETHERTYPE_SG_RESV                 = 0x8015
+	ETHERTYPE_SIMNET                  = 0x5208
+	ETHERTYPE_SLOW                    = 0x8809
+	ETHERTYPE_SNA                     = 0x80d5
+	ETHERTYPE_SNMP                    = 0x814c
+	ETHERTYPE_SONIX                   = 0xfaf5
+	ETHERTYPE_SPIDER                  = 0x809f
+	ETHERTYPE_SPRITE                  = 0x500
+	ETHERTYPE_STP                     = 0x8181
+	ETHERTYPE_TALARIS                 = 0x812b
+	ETHERTYPE_TALARISMC               = 0x852b
+	ETHERTYPE_TCPCOMP                 = 0x876b
+	ETHERTYPE_TCPSM                   = 0x9002
+	ETHERTYPE_TEC                     = 0x814f
+	ETHERTYPE_TIGAN                   = 0x802f
+	ETHERTYPE_TRAIL                   = 0x1000
+	ETHERTYPE_TRANSETHER              = 0x6558
+	ETHERTYPE_TYMSHARE                = 0x802e
+	ETHERTYPE_UBBST                   = 0x7005
+	ETHERTYPE_UBDEBUG                 = 0x900
+	ETHERTYPE_UBDIAGLOOP              = 0x7002
+	ETHERTYPE_UBDL                    = 0x7000
+	ETHERTYPE_UBNIU                   = 0x7001
+	ETHERTYPE_UBNMC                   = 0x7003
+	ETHERTYPE_VALID                   = 0x1600
+	ETHERTYPE_VARIAN                  = 0x80dd
+	ETHERTYPE_VAXELN                  = 0x803b
+	ETHERTYPE_VEECO                   = 0x8067
+	ETHERTYPE_VEXP                    = 0x805b
+	ETHERTYPE_VGLAB                   = 0x8131
+	ETHERTYPE_VINES                   = 0xbad
+	ETHERTYPE_VINESECHO               = 0xbaf
+	ETHERTYPE_VINESLOOP               = 0xbae
+	ETHERTYPE_VITAL                   = 0xff00
+	ETHERTYPE_VLAN                    = 0x8100
+	ETHERTYPE_VLTLMAN                 = 0x8080
+	ETHERTYPE_VPROD                   = 0x805c
+	ETHERTYPE_VURESERVED              = 0x8147
+	ETHERTYPE_WATERLOO                = 0x8130
+	ETHERTYPE_WELLFLEET               = 0x8103
+	ETHERTYPE_X25                     = 0x805
+	ETHERTYPE_X75                     = 0x801
+	ETHERTYPE_XNSSM                   = 0x9001
+	ETHERTYPE_XTP                     = 0x817d
+	ETHER_ADDR_LEN                    = 0x6
+	ETHER_ALIGN                       = 0x2
+	ETHER_CRC_LEN                     = 0x4
+	ETHER_CRC_POLY_BE                 = 0x4c11db6
+	ETHER_CRC_POLY_LE                 = 0xedb88320
+	ETHER_HDR_LEN                     = 0xe
+	ETHER_MAX_DIX_LEN                 = 0x600
+	ETHER_MAX_LEN                     = 0x5ee
+	ETHER_MIN_LEN                     = 0x40
+	ETHER_TYPE_LEN                    = 0x2
+	ETHER_VLAN_ENCAP_LEN              = 0x4
 	EVFILT_AIO                        = -0x3
-	EVFILT_EXCEPT                     = -0x8
-	EVFILT_MARKER                     = 0xf
 	EVFILT_PROC                       = -0x5
 	EVFILT_READ                       = -0x1
 	EVFILT_SIGNAL                     = -0x6
-	EVFILT_SYSCOUNT                   = 0x8
+	EVFILT_SYSCOUNT                   = 0x7
 	EVFILT_TIMER                      = -0x7
 	EVFILT_VNODE                      = -0x4
 	EVFILT_WRITE                      = -0x2
@@ -298,28 +414,20 @@
 	EV_EOF                            = 0x8000
 	EV_ERROR                          = 0x4000
 	EV_FLAG1                          = 0x2000
-	EV_NODATA                         = 0x1000
 	EV_ONESHOT                        = 0x10
 	EV_SYSFLAGS                       = 0xf000
 	EXTA                              = 0x4b00
 	EXTB                              = 0x9600
-	EXTEXIT_LWP                       = 0x10000
-	EXTEXIT_PROC                      = 0x0
-	EXTEXIT_SETINT                    = 0x1
-	EXTEXIT_SIMPLE                    = 0x0
 	EXTPROC                           = 0x800
 	FD_CLOEXEC                        = 0x1
 	FD_SETSIZE                        = 0x400
 	FLUSHO                            = 0x800000
-	F_DUP2FD                          = 0xa
-	F_DUP2FD_CLOEXEC                  = 0x12
 	F_DUPFD                           = 0x0
-	F_DUPFD_CLOEXEC                   = 0x11
+	F_DUPFD_CLOEXEC                   = 0xa
 	F_GETFD                           = 0x1
 	F_GETFL                           = 0x3
 	F_GETLK                           = 0x7
 	F_GETOWN                          = 0x5
-	F_OK                              = 0x0
 	F_RDLCK                           = 0x1
 	F_SETFD                           = 0x2
 	F_SETFL                           = 0x4
@@ -335,30 +443,23 @@
 	IEXTEN                            = 0x400
 	IFAN_ARRIVAL                      = 0x0
 	IFAN_DEPARTURE                    = 0x1
+	IFA_ROUTE                         = 0x1
 	IFF_ALLMULTI                      = 0x200
-	IFF_ALTPHYS                       = 0x4000
 	IFF_BROADCAST                     = 0x2
-	IFF_CANTCHANGE                    = 0x118e72
+	IFF_CANTCHANGE                    = 0x8e52
 	IFF_DEBUG                         = 0x4
 	IFF_LINK0                         = 0x1000
 	IFF_LINK1                         = 0x2000
 	IFF_LINK2                         = 0x4000
 	IFF_LOOPBACK                      = 0x8
-	IFF_MONITOR                       = 0x40000
 	IFF_MULTICAST                     = 0x8000
 	IFF_NOARP                         = 0x80
-	IFF_NPOLLING                      = 0x100000
+	IFF_NOTRAILERS                    = 0x20
 	IFF_OACTIVE                       = 0x400
-	IFF_OACTIVE_COMPAT                = 0x400
 	IFF_POINTOPOINT                   = 0x10
-	IFF_POLLING                       = 0x10000
-	IFF_POLLING_COMPAT                = 0x10000
-	IFF_PPROMISC                      = 0x20000
 	IFF_PROMISC                       = 0x100
 	IFF_RUNNING                       = 0x40
 	IFF_SIMPLEX                       = 0x800
-	IFF_SMART                         = 0x20
-	IFF_STATICARP                     = 0x80000
 	IFF_UP                            = 0x1
 	IFNAMSIZ                          = 0x10
 	IFT_1822                          = 0x2
@@ -382,9 +483,10 @@
 	IFT_ATMVCIENDPT                   = 0xc2
 	IFT_ATMVIRTUAL                    = 0x95
 	IFT_BGPPOLICYACCOUNTING           = 0xa2
+	IFT_BLUETOOTH                     = 0xf8
 	IFT_BRIDGE                        = 0xd1
 	IFT_BSC                           = 0x53
-	IFT_CARP                          = 0xf8
+	IFT_CARP                          = 0xf7
 	IFT_CCTEMUL                       = 0x3d
 	IFT_CEPT                          = 0x13
 	IFT_CES                           = 0x85
@@ -399,22 +501,25 @@
 	IFT_DOCSCABLEDOWNSTREAM           = 0x80
 	IFT_DOCSCABLEMACLAYER             = 0x7f
 	IFT_DOCSCABLEUPSTREAM             = 0x81
+	IFT_DOCSCABLEUPSTREAMCHANNEL      = 0xcd
 	IFT_DS0                           = 0x51
 	IFT_DS0BUNDLE                     = 0x52
 	IFT_DS1FDL                        = 0xaa
 	IFT_DS3                           = 0x1e
 	IFT_DTM                           = 0x8c
+	IFT_DUMMY                         = 0xf1
 	IFT_DVBASILN                      = 0xac
 	IFT_DVBASIOUT                     = 0xad
 	IFT_DVBRCCDOWNSTREAM              = 0x93
 	IFT_DVBRCCMACLAYER                = 0x92
 	IFT_DVBRCCUPSTREAM                = 0x94
+	IFT_ECONET                        = 0xce
 	IFT_ENC                           = 0xf4
 	IFT_EON                           = 0x19
 	IFT_EPLRS                         = 0x57
 	IFT_ESCON                         = 0x49
 	IFT_ETHER                         = 0x6
-	IFT_FAITH                         = 0xf2
+	IFT_FAITH                         = 0xf3
 	IFT_FAST                          = 0x7d
 	IFT_FASTETHER                     = 0x3e
 	IFT_FASTETHERFX                   = 0x45
@@ -452,6 +557,7 @@
 	IFT_IEEE8023ADLAG                 = 0xa1
 	IFT_IFGSN                         = 0x91
 	IFT_IMT                           = 0xbe
+	IFT_INFINIBAND                    = 0xc7
 	IFT_INTERLEAVE                    = 0x7c
 	IFT_IP                            = 0x7e
 	IFT_IPFORWARD                     = 0x8e
@@ -479,6 +585,7 @@
 	IFT_LAPB                          = 0x10
 	IFT_LAPD                          = 0x4d
 	IFT_LAPF                          = 0x77
+	IFT_LINEGROUP                     = 0xd2
 	IFT_LOCALTALK                     = 0x2a
 	IFT_LOOP                          = 0x18
 	IFT_MEDIAMAILOVERIP               = 0x8b
@@ -500,11 +607,15 @@
 	IFT_P80                           = 0xd
 	IFT_PARA                          = 0x22
 	IFT_PFLOG                         = 0xf5
+	IFT_PFLOW                         = 0xf9
 	IFT_PFSYNC                        = 0xf6
 	IFT_PLC                           = 0xae
+	IFT_PON155                        = 0xcf
+	IFT_PON622                        = 0xd0
 	IFT_POS                           = 0xab
 	IFT_PPP                           = 0x17
 	IFT_PPPMULTILINKBUNDLE            = 0x6c
+	IFT_PROPATM                       = 0xc5
 	IFT_PROPBWAP2MP                   = 0xb8
 	IFT_PROPCNLS                      = 0x59
 	IFT_PROPDOCSWIRELESSDOWNSTREAM    = 0xb5
@@ -514,7 +625,8 @@
 	IFT_PROPVIRTUAL                   = 0x35
 	IFT_PROPWIRELESSP2P               = 0x9d
 	IFT_PTPSERIAL                     = 0x16
-	IFT_PVC                           = 0xf1
+	IFT_PVC                           = 0xf2
+	IFT_Q2931                         = 0xc9
 	IFT_QLLC                          = 0x44
 	IFT_RADIOMAC                      = 0xbc
 	IFT_RADSL                         = 0x5f
@@ -526,6 +638,8 @@
 	IFT_SDSL                          = 0x60
 	IFT_SHDSL                         = 0xa9
 	IFT_SIP                           = 0x1f
+	IFT_SIPSIG                        = 0xcc
+	IFT_SIPTG                         = 0xcb
 	IFT_SLIP                          = 0x1c
 	IFT_SMDSDXI                       = 0x2b
 	IFT_SMDSICIP                      = 0x34
@@ -537,9 +651,9 @@
 	IFT_SS7SIGLINK                    = 0x9c
 	IFT_STACKTOSTACK                  = 0x6f
 	IFT_STARLAN                       = 0xb
-	IFT_STF                           = 0xf3
 	IFT_T1                            = 0x12
 	IFT_TDLC                          = 0x74
+	IFT_TELINK                        = 0xc8
 	IFT_TERMPAD                       = 0x5b
 	IFT_TR008                         = 0xb0
 	IFT_TRANSPHDLC                    = 0x7b
@@ -552,11 +666,16 @@
 	IFT_V37                           = 0x78
 	IFT_VDSL                          = 0x61
 	IFT_VIRTUALIPADDRESS              = 0x70
+	IFT_VIRTUALTG                     = 0xca
+	IFT_VOICEDID                      = 0xd5
 	IFT_VOICEEM                       = 0x64
+	IFT_VOICEEMFGD                    = 0xd3
 	IFT_VOICEENCAP                    = 0x67
+	IFT_VOICEFGDEANA                  = 0xd4
 	IFT_VOICEFXO                      = 0x65
 	IFT_VOICEFXS                      = 0x66
 	IFT_VOICEOVERATM                  = 0x98
+	IFT_VOICEOVERCABLE                = 0xc6
 	IFT_VOICEOVERFRAMERELAY           = 0x99
 	IFT_VOICEOVERIP                   = 0x68
 	IFT_X213                          = 0x5d
@@ -587,166 +706,92 @@
 	IN_CLASSD_NET                     = 0xf0000000
 	IN_CLASSD_NSHIFT                  = 0x1c
 	IN_LOOPBACKNET                    = 0x7f
-	IPPROTO_3PC                       = 0x22
-	IPPROTO_ADFS                      = 0x44
+	IN_RFC3021_HOST                   = 0x1
+	IN_RFC3021_NET                    = 0xfffffffe
+	IN_RFC3021_NSHIFT                 = 0x1f
 	IPPROTO_AH                        = 0x33
-	IPPROTO_AHIP                      = 0x3d
-	IPPROTO_APES                      = 0x63
-	IPPROTO_ARGUS                     = 0xd
-	IPPROTO_AX25                      = 0x5d
-	IPPROTO_BHA                       = 0x31
-	IPPROTO_BLT                       = 0x1e
-	IPPROTO_BRSATMON                  = 0x4c
 	IPPROTO_CARP                      = 0x70
-	IPPROTO_CFTP                      = 0x3e
-	IPPROTO_CHAOS                     = 0x10
-	IPPROTO_CMTP                      = 0x26
-	IPPROTO_CPHB                      = 0x49
-	IPPROTO_CPNX                      = 0x48
-	IPPROTO_DDP                       = 0x25
-	IPPROTO_DGP                       = 0x56
-	IPPROTO_DIVERT                    = 0xfe
+	IPPROTO_DIVERT                    = 0x102
+	IPPROTO_DIVERT_INIT               = 0x2
+	IPPROTO_DIVERT_RESP               = 0x1
 	IPPROTO_DONE                      = 0x101
 	IPPROTO_DSTOPTS                   = 0x3c
 	IPPROTO_EGP                       = 0x8
-	IPPROTO_EMCON                     = 0xe
 	IPPROTO_ENCAP                     = 0x62
 	IPPROTO_EON                       = 0x50
 	IPPROTO_ESP                       = 0x32
 	IPPROTO_ETHERIP                   = 0x61
 	IPPROTO_FRAGMENT                  = 0x2c
 	IPPROTO_GGP                       = 0x3
-	IPPROTO_GMTP                      = 0x64
 	IPPROTO_GRE                       = 0x2f
-	IPPROTO_HELLO                     = 0x3f
-	IPPROTO_HMP                       = 0x14
 	IPPROTO_HOPOPTS                   = 0x0
 	IPPROTO_ICMP                      = 0x1
 	IPPROTO_ICMPV6                    = 0x3a
 	IPPROTO_IDP                       = 0x16
-	IPPROTO_IDPR                      = 0x23
-	IPPROTO_IDRP                      = 0x2d
 	IPPROTO_IGMP                      = 0x2
-	IPPROTO_IGP                       = 0x55
-	IPPROTO_IGRP                      = 0x58
-	IPPROTO_IL                        = 0x28
-	IPPROTO_INLSP                     = 0x34
-	IPPROTO_INP                       = 0x20
 	IPPROTO_IP                        = 0x0
 	IPPROTO_IPCOMP                    = 0x6c
-	IPPROTO_IPCV                      = 0x47
-	IPPROTO_IPEIP                     = 0x5e
 	IPPROTO_IPIP                      = 0x4
-	IPPROTO_IPPC                      = 0x43
 	IPPROTO_IPV4                      = 0x4
 	IPPROTO_IPV6                      = 0x29
-	IPPROTO_IRTP                      = 0x1c
-	IPPROTO_KRYPTOLAN                 = 0x41
-	IPPROTO_LARP                      = 0x5b
-	IPPROTO_LEAF1                     = 0x19
-	IPPROTO_LEAF2                     = 0x1a
 	IPPROTO_MAX                       = 0x100
-	IPPROTO_MAXID                     = 0x34
-	IPPROTO_MEAS                      = 0x13
-	IPPROTO_MHRP                      = 0x30
-	IPPROTO_MICP                      = 0x5f
+	IPPROTO_MAXID                     = 0x103
 	IPPROTO_MOBILE                    = 0x37
-	IPPROTO_MTP                       = 0x5c
-	IPPROTO_MUX                       = 0x12
-	IPPROTO_ND                        = 0x4d
-	IPPROTO_NHRP                      = 0x36
+	IPPROTO_MPLS                      = 0x89
 	IPPROTO_NONE                      = 0x3b
-	IPPROTO_NSP                       = 0x1f
-	IPPROTO_NVPII                     = 0xb
-	IPPROTO_OSPFIGP                   = 0x59
 	IPPROTO_PFSYNC                    = 0xf0
-	IPPROTO_PGM                       = 0x71
-	IPPROTO_PIGP                      = 0x9
 	IPPROTO_PIM                       = 0x67
-	IPPROTO_PRM                       = 0x15
 	IPPROTO_PUP                       = 0xc
-	IPPROTO_PVP                       = 0x4b
 	IPPROTO_RAW                       = 0xff
-	IPPROTO_RCCMON                    = 0xa
-	IPPROTO_RDP                       = 0x1b
 	IPPROTO_ROUTING                   = 0x2b
 	IPPROTO_RSVP                      = 0x2e
-	IPPROTO_RVD                       = 0x42
-	IPPROTO_SATEXPAK                  = 0x40
-	IPPROTO_SATMON                    = 0x45
-	IPPROTO_SCCSP                     = 0x60
-	IPPROTO_SCTP                      = 0x84
-	IPPROTO_SDRP                      = 0x2a
-	IPPROTO_SEP                       = 0x21
-	IPPROTO_SKIP                      = 0x39
-	IPPROTO_SRPC                      = 0x5a
-	IPPROTO_ST                        = 0x7
-	IPPROTO_SVMTP                     = 0x52
-	IPPROTO_SWIPE                     = 0x35
-	IPPROTO_TCF                       = 0x57
 	IPPROTO_TCP                       = 0x6
-	IPPROTO_TLSP                      = 0x38
 	IPPROTO_TP                        = 0x1d
-	IPPROTO_TPXX                      = 0x27
-	IPPROTO_TRUNK1                    = 0x17
-	IPPROTO_TRUNK2                    = 0x18
-	IPPROTO_TTP                       = 0x54
 	IPPROTO_UDP                       = 0x11
-	IPPROTO_UNKNOWN                   = 0x102
-	IPPROTO_VINES                     = 0x53
-	IPPROTO_VISA                      = 0x46
-	IPPROTO_VMTP                      = 0x51
-	IPPROTO_WBEXPAK                   = 0x4f
-	IPPROTO_WBMON                     = 0x4e
-	IPPROTO_WSN                       = 0x4a
-	IPPROTO_XNET                      = 0xf
-	IPPROTO_XTP                       = 0x24
+	IPV6_AUTH_LEVEL                   = 0x35
 	IPV6_AUTOFLOWLABEL                = 0x3b
-	IPV6_BINDV6ONLY                   = 0x1b
 	IPV6_CHECKSUM                     = 0x1a
 	IPV6_DEFAULT_MULTICAST_HOPS       = 0x1
 	IPV6_DEFAULT_MULTICAST_LOOP       = 0x1
 	IPV6_DEFHLIM                      = 0x40
 	IPV6_DONTFRAG                     = 0x3e
 	IPV6_DSTOPTS                      = 0x32
+	IPV6_ESP_NETWORK_LEVEL            = 0x37
+	IPV6_ESP_TRANS_LEVEL              = 0x36
 	IPV6_FAITH                        = 0x1d
 	IPV6_FLOWINFO_MASK                = 0xffffff0f
 	IPV6_FLOWLABEL_MASK               = 0xffff0f00
 	IPV6_FRAGTTL                      = 0x78
-	IPV6_FW_ADD                       = 0x1e
-	IPV6_FW_DEL                       = 0x1f
-	IPV6_FW_FLUSH                     = 0x20
-	IPV6_FW_GET                       = 0x22
-	IPV6_FW_ZERO                      = 0x21
 	IPV6_HLIMDEC                      = 0x1
 	IPV6_HOPLIMIT                     = 0x2f
 	IPV6_HOPOPTS                      = 0x31
-	IPV6_IPSEC_POLICY                 = 0x1c
+	IPV6_IPCOMP_LEVEL                 = 0x3c
 	IPV6_JOIN_GROUP                   = 0xc
 	IPV6_LEAVE_GROUP                  = 0xd
 	IPV6_MAXHLIM                      = 0xff
 	IPV6_MAXPACKET                    = 0xffff
 	IPV6_MMTU                         = 0x500
-	IPV6_MSFILTER                     = 0x4a
 	IPV6_MULTICAST_HOPS               = 0xa
 	IPV6_MULTICAST_IF                 = 0x9
 	IPV6_MULTICAST_LOOP               = 0xb
 	IPV6_NEXTHOP                      = 0x30
+	IPV6_OPTIONS                      = 0x1
 	IPV6_PATHMTU                      = 0x2c
+	IPV6_PIPEX                        = 0x3f
 	IPV6_PKTINFO                      = 0x2e
-	IPV6_PKTOPTIONS                   = 0x34
 	IPV6_PORTRANGE                    = 0xe
 	IPV6_PORTRANGE_DEFAULT            = 0x0
 	IPV6_PORTRANGE_HIGH               = 0x1
 	IPV6_PORTRANGE_LOW                = 0x2
-	IPV6_PREFER_TEMPADDR              = 0x3f
 	IPV6_RECVDSTOPTS                  = 0x28
+	IPV6_RECVDSTPORT                  = 0x40
 	IPV6_RECVHOPLIMIT                 = 0x25
 	IPV6_RECVHOPOPTS                  = 0x27
 	IPV6_RECVPATHMTU                  = 0x2b
 	IPV6_RECVPKTINFO                  = 0x24
 	IPV6_RECVRTHDR                    = 0x26
 	IPV6_RECVTCLASS                   = 0x39
+	IPV6_RTABLE                       = 0x1021
 	IPV6_RTHDR                        = 0x33
 	IPV6_RTHDRDSTOPTS                 = 0x23
 	IPV6_RTHDR_LOOSE                  = 0x0
@@ -760,49 +805,49 @@
 	IPV6_VERSION                      = 0x60
 	IPV6_VERSION_MASK                 = 0xf0
 	IP_ADD_MEMBERSHIP                 = 0xc
+	IP_AUTH_LEVEL                     = 0x14
 	IP_DEFAULT_MULTICAST_LOOP         = 0x1
 	IP_DEFAULT_MULTICAST_TTL          = 0x1
 	IP_DF                             = 0x4000
+	IP_DIVERTFL                       = 0x1022
 	IP_DROP_MEMBERSHIP                = 0xd
-	IP_DUMMYNET_CONFIGURE             = 0x3c
-	IP_DUMMYNET_DEL                   = 0x3d
-	IP_DUMMYNET_FLUSH                 = 0x3e
-	IP_DUMMYNET_GET                   = 0x40
-	IP_FAITH                          = 0x16
-	IP_FW_ADD                         = 0x32
-	IP_FW_DEL                         = 0x33
-	IP_FW_FLUSH                       = 0x34
-	IP_FW_GET                         = 0x36
-	IP_FW_RESETLOG                    = 0x37
-	IP_FW_ZERO                        = 0x35
+	IP_ESP_NETWORK_LEVEL              = 0x16
+	IP_ESP_TRANS_LEVEL                = 0x15
 	IP_HDRINCL                        = 0x2
-	IP_IPSEC_POLICY                   = 0x15
+	IP_IPCOMP_LEVEL                   = 0x1d
+	IP_IPSECFLOWINFO                  = 0x24
+	IP_IPSEC_LOCAL_AUTH               = 0x1b
+	IP_IPSEC_LOCAL_CRED               = 0x19
+	IP_IPSEC_LOCAL_ID                 = 0x17
+	IP_IPSEC_REMOTE_AUTH              = 0x1c
+	IP_IPSEC_REMOTE_CRED              = 0x1a
+	IP_IPSEC_REMOTE_ID                = 0x18
 	IP_MAXPACKET                      = 0xffff
-	IP_MAX_MEMBERSHIPS                = 0x14
+	IP_MAX_MEMBERSHIPS                = 0xfff
 	IP_MF                             = 0x2000
-	IP_MINTTL                         = 0x42
+	IP_MINTTL                         = 0x20
+	IP_MIN_MEMBERSHIPS                = 0xf
 	IP_MSS                            = 0x240
 	IP_MULTICAST_IF                   = 0x9
 	IP_MULTICAST_LOOP                 = 0xb
 	IP_MULTICAST_TTL                  = 0xa
-	IP_MULTICAST_VIF                  = 0xe
 	IP_OFFMASK                        = 0x1fff
 	IP_OPTIONS                        = 0x1
+	IP_PIPEX                          = 0x22
 	IP_PORTRANGE                      = 0x13
 	IP_PORTRANGE_DEFAULT              = 0x0
 	IP_PORTRANGE_HIGH                 = 0x1
 	IP_PORTRANGE_LOW                  = 0x2
 	IP_RECVDSTADDR                    = 0x7
-	IP_RECVIF                         = 0x14
+	IP_RECVDSTPORT                    = 0x21
+	IP_RECVIF                         = 0x1e
 	IP_RECVOPTS                       = 0x5
 	IP_RECVRETOPTS                    = 0x6
-	IP_RECVTTL                        = 0x41
+	IP_RECVRTABLE                     = 0x23
+	IP_RECVTTL                        = 0x1f
 	IP_RETOPTS                        = 0x8
 	IP_RF                             = 0x8000
-	IP_RSVP_OFF                       = 0x10
-	IP_RSVP_ON                        = 0xf
-	IP_RSVP_VIF_OFF                   = 0x12
-	IP_RSVP_VIF_ON                    = 0x11
+	IP_RTABLE                         = 0x1021
 	IP_TOS                            = 0x3
 	IP_TTL                            = 0x4
 	ISIG                              = 0x80
@@ -810,116 +855,102 @@
 	IXANY                             = 0x800
 	IXOFF                             = 0x400
 	IXON                              = 0x200
+	LCNT_OVERLOAD_FLUSH               = 0x6
 	LOCK_EX                           = 0x2
 	LOCK_NB                           = 0x4
 	LOCK_SH                           = 0x1
 	LOCK_UN                           = 0x8
-	MADV_AUTOSYNC                     = 0x7
-	MADV_CONTROL_END                  = 0xb
-	MADV_CONTROL_START                = 0xa
-	MADV_CORE                         = 0x9
 	MADV_DONTNEED                     = 0x4
-	MADV_FREE                         = 0x5
-	MADV_INVAL                        = 0xa
-	MADV_NOCORE                       = 0x8
+	MADV_FREE                         = 0x6
 	MADV_NORMAL                       = 0x0
-	MADV_NOSYNC                       = 0x6
 	MADV_RANDOM                       = 0x1
 	MADV_SEQUENTIAL                   = 0x2
-	MADV_SETMAP                       = 0xb
+	MADV_SPACEAVAIL                   = 0x5
 	MADV_WILLNEED                     = 0x3
 	MAP_ANON                          = 0x1000
+	MAP_ANONYMOUS                     = 0x1000
 	MAP_COPY                          = 0x2
 	MAP_FILE                          = 0x0
 	MAP_FIXED                         = 0x10
-	MAP_HASSEMAPHORE                  = 0x200
-	MAP_INHERIT                       = 0x80
-	MAP_NOCORE                        = 0x20000
-	MAP_NOEXTEND                      = 0x100
-	MAP_NORESERVE                     = 0x40
-	MAP_NOSYNC                        = 0x800
+	MAP_FLAGMASK                      = 0x3ff7
+	MAP_HASSEMAPHORE                  = 0x0
+	MAP_INHERIT                       = 0x0
+	MAP_INHERIT_COPY                  = 0x1
+	MAP_INHERIT_NONE                  = 0x2
+	MAP_INHERIT_SHARE                 = 0x0
+	MAP_INHERIT_ZERO                  = 0x3
+	MAP_NOEXTEND                      = 0x0
+	MAP_NORESERVE                     = 0x0
 	MAP_PRIVATE                       = 0x2
-	MAP_RENAME                        = 0x20
+	MAP_RENAME                        = 0x0
 	MAP_SHARED                        = 0x1
-	MAP_SIZEALIGN                     = 0x40000
-	MAP_STACK                         = 0x400
-	MAP_TRYFIXED                      = 0x10000
-	MAP_VPAGETABLE                    = 0x2000
+	MAP_TRYFIXED                      = 0x0
 	MCL_CURRENT                       = 0x1
 	MCL_FUTURE                        = 0x2
+	MSG_BCAST                         = 0x100
+	MSG_CMSG_CLOEXEC                  = 0x800
 	MSG_CTRUNC                        = 0x20
 	MSG_DONTROUTE                     = 0x4
 	MSG_DONTWAIT                      = 0x80
-	MSG_EOF                           = 0x100
 	MSG_EOR                           = 0x8
-	MSG_FBLOCKING                     = 0x10000
-	MSG_FMASK                         = 0xffff0000
-	MSG_FNONBLOCKING                  = 0x20000
+	MSG_MCAST                         = 0x200
 	MSG_NOSIGNAL                      = 0x400
-	MSG_NOTIFICATION                  = 0x200
 	MSG_OOB                           = 0x1
 	MSG_PEEK                          = 0x2
-	MSG_SYNC                          = 0x800
 	MSG_TRUNC                         = 0x10
 	MSG_WAITALL                       = 0x40
 	MS_ASYNC                          = 0x1
-	MS_INVALIDATE                     = 0x2
-	MS_SYNC                           = 0x0
+	MS_INVALIDATE                     = 0x4
+	MS_SYNC                           = 0x2
 	NAME_MAX                          = 0xff
 	NET_RT_DUMP                       = 0x1
 	NET_RT_FLAGS                      = 0x2
 	NET_RT_IFLIST                     = 0x3
-	NET_RT_MAXID                      = 0x4
+	NET_RT_MAXID                      = 0x6
+	NET_RT_STATS                      = 0x4
+	NET_RT_TABLE                      = 0x5
 	NOFLSH                            = 0x80000000
 	NOTE_ATTRIB                       = 0x8
 	NOTE_CHILD                        = 0x4
 	NOTE_DELETE                       = 0x1
+	NOTE_EOF                          = 0x2
 	NOTE_EXEC                         = 0x20000000
 	NOTE_EXIT                         = 0x80000000
 	NOTE_EXTEND                       = 0x4
 	NOTE_FORK                         = 0x40000000
 	NOTE_LINK                         = 0x10
 	NOTE_LOWAT                        = 0x1
-	NOTE_OOB                          = 0x2
 	NOTE_PCTRLMASK                    = 0xf0000000
 	NOTE_PDATAMASK                    = 0xfffff
 	NOTE_RENAME                       = 0x20
 	NOTE_REVOKE                       = 0x40
 	NOTE_TRACK                        = 0x1
 	NOTE_TRACKERR                     = 0x2
+	NOTE_TRUNCATE                     = 0x80
 	NOTE_WRITE                        = 0x2
 	OCRNL                             = 0x10
 	ONLCR                             = 0x2
-	ONLRET                            = 0x40
-	ONOCR                             = 0x20
+	ONLRET                            = 0x80
+	ONOCR                             = 0x40
 	ONOEOT                            = 0x8
 	OPOST                             = 0x1
 	O_ACCMODE                         = 0x3
 	O_APPEND                          = 0x8
 	O_ASYNC                           = 0x40
-	O_CLOEXEC                         = 0x20000
+	O_CLOEXEC                         = 0x10000
 	O_CREAT                           = 0x200
-	O_DIRECT                          = 0x10000
-	O_DIRECTORY                       = 0x8000000
+	O_DIRECTORY                       = 0x20000
+	O_DSYNC                           = 0x80
 	O_EXCL                            = 0x800
 	O_EXLOCK                          = 0x20
-	O_FAPPEND                         = 0x100000
-	O_FASYNCWRITE                     = 0x800000
-	O_FBLOCKING                       = 0x40000
-	O_FBUFFERED                       = 0x2000000
-	O_FMASK                           = 0x7fc0000
-	O_FNONBLOCKING                    = 0x80000
-	O_FOFFSET                         = 0x200000
 	O_FSYNC                           = 0x80
-	O_FSYNCWRITE                      = 0x400000
-	O_FUNBUFFERED                     = 0x1000000
-	O_MAPONREAD                       = 0x4000000
 	O_NDELAY                          = 0x4
 	O_NOCTTY                          = 0x8000
 	O_NOFOLLOW                        = 0x100
 	O_NONBLOCK                        = 0x4
 	O_RDONLY                          = 0x0
 	O_RDWR                            = 0x2
+	O_RSYNC                           = 0x80
 	O_SHLOCK                          = 0x10
 	O_SYNC                            = 0x80
 	O_TRUNC                           = 0x400
@@ -928,6 +959,7 @@
 	PARMRK                            = 0x8
 	PARODD                            = 0x2000
 	PENDIN                            = 0x20000000
+	PF_FLUSH                          = 0x1
 	PRIO_PGRP                         = 0x1
 	PRIO_PROCESS                      = 0x0
 	PRIO_USER                         = 0x2
@@ -935,7 +967,6 @@
 	PROT_NONE                         = 0x0
 	PROT_READ                         = 0x1
 	PROT_WRITE                        = 0x2
-	RLIMIT_AS                         = 0xa
 	RLIMIT_CORE                       = 0x4
 	RLIMIT_CPU                        = 0x0
 	RLIMIT_DATA                       = 0x2
@@ -950,11 +981,11 @@
 	RTAX_GENMASK                      = 0x3
 	RTAX_IFA                          = 0x5
 	RTAX_IFP                          = 0x4
+	RTAX_LABEL                        = 0xa
 	RTAX_MAX                          = 0xb
-	RTAX_MPLS1                        = 0x8
-	RTAX_MPLS2                        = 0x9
-	RTAX_MPLS3                        = 0xa
 	RTAX_NETMASK                      = 0x2
+	RTAX_SRC                          = 0x8
+	RTAX_SRCMASK                      = 0x9
 	RTA_AUTHOR                        = 0x40
 	RTA_BRD                           = 0x80
 	RTA_DST                           = 0x1
@@ -962,138 +993,192 @@
 	RTA_GENMASK                       = 0x8
 	RTA_IFA                           = 0x20
 	RTA_IFP                           = 0x10
-	RTA_MPLS1                         = 0x100
-	RTA_MPLS2                         = 0x200
-	RTA_MPLS3                         = 0x400
+	RTA_LABEL                         = 0x400
 	RTA_NETMASK                       = 0x4
+	RTA_SRC                           = 0x100
+	RTA_SRCMASK                       = 0x200
+	RTF_ANNOUNCE                      = 0x4000
 	RTF_BLACKHOLE                     = 0x1000
 	RTF_BROADCAST                     = 0x400000
+	RTF_CLONED                        = 0x10000
 	RTF_CLONING                       = 0x100
 	RTF_DONE                          = 0x40
 	RTF_DYNAMIC                       = 0x10
+	RTF_FMASK                         = 0x70f808
 	RTF_GATEWAY                       = 0x2
 	RTF_HOST                          = 0x4
 	RTF_LLINFO                        = 0x400
 	RTF_LOCAL                         = 0x200000
+	RTF_MASK                          = 0x80
 	RTF_MODIFIED                      = 0x20
-	RTF_MPLSOPS                       = 0x1000000
-	RTF_MULTICAST                     = 0x800000
-	RTF_PINNED                        = 0x100000
-	RTF_PRCLONING                     = 0x10000
+	RTF_MPATH                         = 0x40000
+	RTF_MPLS                          = 0x100000
+	RTF_PERMANENT_ARP                 = 0x2000
 	RTF_PROTO1                        = 0x8000
 	RTF_PROTO2                        = 0x4000
-	RTF_PROTO3                        = 0x40000
+	RTF_PROTO3                        = 0x2000
 	RTF_REJECT                        = 0x8
 	RTF_STATIC                        = 0x800
 	RTF_UP                            = 0x1
-	RTF_WASCLONED                     = 0x20000
+	RTF_USETRAILERS                   = 0x8000
 	RTF_XRESOLVE                      = 0x200
 	RTM_ADD                           = 0x1
 	RTM_CHANGE                        = 0x3
 	RTM_DELADDR                       = 0xd
 	RTM_DELETE                        = 0x2
-	RTM_DELMADDR                      = 0x10
+	RTM_DESYNC                        = 0x10
 	RTM_GET                           = 0x4
-	RTM_IEEE80211                     = 0x12
-	RTM_IFANNOUNCE                    = 0x11
+	RTM_IFANNOUNCE                    = 0xf
 	RTM_IFINFO                        = 0xe
 	RTM_LOCK                          = 0x8
 	RTM_LOSING                        = 0x5
+	RTM_MAXSIZE                       = 0x800
 	RTM_MISS                          = 0x7
 	RTM_NEWADDR                       = 0xc
-	RTM_NEWMADDR                      = 0xf
-	RTM_OLDADD                        = 0x9
-	RTM_OLDDEL                        = 0xa
 	RTM_REDIRECT                      = 0x6
 	RTM_RESOLVE                       = 0xb
 	RTM_RTTUNIT                       = 0xf4240
-	RTM_VERSION                       = 0x6
+	RTM_VERSION                       = 0x5
 	RTV_EXPIRE                        = 0x4
 	RTV_HOPCOUNT                      = 0x2
-	RTV_IWCAPSEGS                     = 0x400
-	RTV_IWMAXSEGS                     = 0x200
-	RTV_MSL                           = 0x100
 	RTV_MTU                           = 0x1
 	RTV_RPIPE                         = 0x8
 	RTV_RTT                           = 0x40
 	RTV_RTTVAR                        = 0x80
 	RTV_SPIPE                         = 0x10
 	RTV_SSTHRESH                      = 0x20
+	RT_TABLEID_MAX                    = 0xff
 	RUSAGE_CHILDREN                   = -0x1
 	RUSAGE_SELF                       = 0x0
-	SCM_CREDS                         = 0x3
+	RUSAGE_THREAD                     = 0x1
 	SCM_RIGHTS                        = 0x1
-	SCM_TIMESTAMP                     = 0x2
+	SCM_TIMESTAMP                     = 0x4
 	SHUT_RD                           = 0x0
 	SHUT_RDWR                         = 0x2
 	SHUT_WR                           = 0x1
 	SIOCADDMULTI                      = 0x80206931
-	SIOCADDRT                         = 0x8030720a
 	SIOCAIFADDR                       = 0x8040691a
-	SIOCALIFADDR                      = 0x8118691b
+	SIOCAIFGROUP                      = 0x80246987
+	SIOCALIFADDR                      = 0x8218691c
 	SIOCATMARK                        = 0x40047307
+	SIOCBRDGADD                       = 0x8054693c
+	SIOCBRDGADDS                      = 0x80546941
+	SIOCBRDGARL                       = 0x806e694d
+	SIOCBRDGDADDR                     = 0x81286947
+	SIOCBRDGDEL                       = 0x8054693d
+	SIOCBRDGDELS                      = 0x80546942
+	SIOCBRDGFLUSH                     = 0x80546948
+	SIOCBRDGFRL                       = 0x806e694e
+	SIOCBRDGGCACHE                    = 0xc0146941
+	SIOCBRDGGFD                       = 0xc0146952
+	SIOCBRDGGHT                       = 0xc0146951
+	SIOCBRDGGIFFLGS                   = 0xc054693e
+	SIOCBRDGGMA                       = 0xc0146953
+	SIOCBRDGGPARAM                    = 0xc03c6958
+	SIOCBRDGGPRI                      = 0xc0146950
+	SIOCBRDGGRL                       = 0xc028694f
+	SIOCBRDGGSIFS                     = 0xc054693c
+	SIOCBRDGGTO                       = 0xc0146946
+	SIOCBRDGIFS                       = 0xc0546942
+	SIOCBRDGRTS                       = 0xc0186943
+	SIOCBRDGSADDR                     = 0xc1286944
+	SIOCBRDGSCACHE                    = 0x80146940
+	SIOCBRDGSFD                       = 0x80146952
+	SIOCBRDGSHT                       = 0x80146951
+	SIOCBRDGSIFCOST                   = 0x80546955
+	SIOCBRDGSIFFLGS                   = 0x8054693f
+	SIOCBRDGSIFPRIO                   = 0x80546954
+	SIOCBRDGSMA                       = 0x80146953
+	SIOCBRDGSPRI                      = 0x80146950
+	SIOCBRDGSPROTO                    = 0x8014695a
+	SIOCBRDGSTO                       = 0x80146945
+	SIOCBRDGSTXHC                     = 0x80146959
 	SIOCDELMULTI                      = 0x80206932
-	SIOCDELRT                         = 0x8030720b
 	SIOCDIFADDR                       = 0x80206919
+	SIOCDIFGROUP                      = 0x80246989
 	SIOCDIFPHYADDR                    = 0x80206949
-	SIOCDLIFADDR                      = 0x8118691d
-	SIOCGDRVSPEC                      = 0xc01c697b
-	SIOCGETSGCNT                      = 0xc0147210
-	SIOCGETVIFCNT                     = 0xc014720f
+	SIOCDLIFADDR                      = 0x8218691e
+	SIOCGETKALIVE                     = 0xc01869a4
+	SIOCGETLABEL                      = 0x8020699a
+	SIOCGETPFLOW                      = 0xc02069fe
+	SIOCGETPFSYNC                     = 0xc02069f8
+	SIOCGETSGCNT                      = 0xc0147534
+	SIOCGETVIFCNT                     = 0xc0147533
+	SIOCGETVLAN                       = 0xc0206990
 	SIOCGHIWAT                        = 0x40047301
 	SIOCGIFADDR                       = 0xc0206921
+	SIOCGIFASYNCMAP                   = 0xc020697c
 	SIOCGIFBRDADDR                    = 0xc0206923
-	SIOCGIFCAP                        = 0xc020691f
 	SIOCGIFCONF                       = 0xc0086924
-	SIOCGIFDATA                       = 0xc0206926
+	SIOCGIFDATA                       = 0xc020691b
+	SIOCGIFDESCR                      = 0xc0206981
 	SIOCGIFDSTADDR                    = 0xc0206922
 	SIOCGIFFLAGS                      = 0xc0206911
+	SIOCGIFGATTR                      = 0xc024698b
 	SIOCGIFGENERIC                    = 0xc020693a
 	SIOCGIFGMEMB                      = 0xc024698a
-	SIOCGIFINDEX                      = 0xc0206920
-	SIOCGIFMEDIA                      = 0xc0286938
+	SIOCGIFGROUP                      = 0xc0246988
+	SIOCGIFHARDMTU                    = 0xc02069a5
+	SIOCGIFMEDIA                      = 0xc0286936
 	SIOCGIFMETRIC                     = 0xc0206917
-	SIOCGIFMTU                        = 0xc0206933
+	SIOCGIFMTU                        = 0xc020697e
 	SIOCGIFNETMASK                    = 0xc0206925
 	SIOCGIFPDSTADDR                   = 0xc0206948
-	SIOCGIFPHYS                       = 0xc0206935
-	SIOCGIFPOLLCPU                    = 0xc020697e
+	SIOCGIFPRIORITY                   = 0xc020699c
 	SIOCGIFPSRCADDR                   = 0xc0206947
-	SIOCGIFSTATUS                     = 0xc331693b
-	SIOCGIFTSOLEN                     = 0xc0206980
-	SIOCGLIFADDR                      = 0xc118691c
-	SIOCGLIFPHYADDR                   = 0xc118694b
+	SIOCGIFRDOMAIN                    = 0xc02069a0
+	SIOCGIFRTLABEL                    = 0xc0206983
+	SIOCGIFRXR                        = 0x802069aa
+	SIOCGIFTIMESLOT                   = 0xc0206986
+	SIOCGIFXFLAGS                     = 0xc020699e
+	SIOCGLIFADDR                      = 0xc218691d
+	SIOCGLIFPHYADDR                   = 0xc218694b
+	SIOCGLIFPHYRTABLE                 = 0xc02069a2
+	SIOCGLIFPHYTTL                    = 0xc02069a9
 	SIOCGLOWAT                        = 0x40047303
 	SIOCGPGRP                         = 0x40047309
-	SIOCGPRIVATE_0                    = 0xc0206950
-	SIOCGPRIVATE_1                    = 0xc0206951
-	SIOCIFCREATE                      = 0xc020697a
-	SIOCIFCREATE2                     = 0xc020697c
+	SIOCGSPPPPARAMS                   = 0xc0206994
+	SIOCGVH                           = 0xc02069f6
+	SIOCGVNETID                       = 0xc02069a7
+	SIOCIFCREATE                      = 0x8020697a
 	SIOCIFDESTROY                     = 0x80206979
 	SIOCIFGCLONERS                    = 0xc00c6978
-	SIOCSDRVSPEC                      = 0x801c697b
+	SIOCSETKALIVE                     = 0x801869a3
+	SIOCSETLABEL                      = 0x80206999
+	SIOCSETPFLOW                      = 0x802069fd
+	SIOCSETPFSYNC                     = 0x802069f7
+	SIOCSETVLAN                       = 0x8020698f
 	SIOCSHIWAT                        = 0x80047300
 	SIOCSIFADDR                       = 0x8020690c
+	SIOCSIFASYNCMAP                   = 0x8020697d
 	SIOCSIFBRDADDR                    = 0x80206913
-	SIOCSIFCAP                        = 0x8020691e
+	SIOCSIFDESCR                      = 0x80206980
 	SIOCSIFDSTADDR                    = 0x8020690e
 	SIOCSIFFLAGS                      = 0x80206910
+	SIOCSIFGATTR                      = 0x8024698c
 	SIOCSIFGENERIC                    = 0x80206939
-	SIOCSIFLLADDR                     = 0x8020693c
-	SIOCSIFMEDIA                      = 0xc0206937
+	SIOCSIFLLADDR                     = 0x8020691f
+	SIOCSIFMEDIA                      = 0xc0206935
 	SIOCSIFMETRIC                     = 0x80206918
-	SIOCSIFMTU                        = 0x80206934
-	SIOCSIFNAME                       = 0x80206928
+	SIOCSIFMTU                        = 0x8020697f
 	SIOCSIFNETMASK                    = 0x80206916
 	SIOCSIFPHYADDR                    = 0x80406946
-	SIOCSIFPHYS                       = 0x80206936
-	SIOCSIFPOLLCPU                    = 0x8020697d
-	SIOCSIFTSOLEN                     = 0x8020697f
-	SIOCSLIFPHYADDR                   = 0x8118694a
+	SIOCSIFPRIORITY                   = 0x8020699b
+	SIOCSIFRDOMAIN                    = 0x8020699f
+	SIOCSIFRTLABEL                    = 0x80206982
+	SIOCSIFTIMESLOT                   = 0x80206985
+	SIOCSIFXFLAGS                     = 0x8020699d
+	SIOCSLIFPHYADDR                   = 0x8218694a
+	SIOCSLIFPHYRTABLE                 = 0x802069a1
+	SIOCSLIFPHYTTL                    = 0x802069a8
 	SIOCSLOWAT                        = 0x80047302
 	SIOCSPGRP                         = 0x80047308
+	SIOCSSPPPPARAMS                   = 0x80206993
+	SIOCSVH                           = 0xc02069f5
+	SIOCSVNETID                       = 0x802069a6
+	SOCK_CLOEXEC                      = 0x8000
 	SOCK_DGRAM                        = 0x2
-	SOCK_MAXADDRLEN                   = 0xff
+	SOCK_NONBLOCK                     = 0x4000
 	SOCK_RAW                          = 0x3
 	SOCK_RDM                          = 0x4
 	SOCK_SEQPACKET                    = 0x5
@@ -1101,72 +1186,68 @@
 	SOL_SOCKET                        = 0xffff
 	SOMAXCONN                         = 0x80
 	SO_ACCEPTCONN                     = 0x2
-	SO_ACCEPTFILTER                   = 0x1000
+	SO_BINDANY                        = 0x1000
 	SO_BROADCAST                      = 0x20
 	SO_DEBUG                          = 0x1
 	SO_DONTROUTE                      = 0x10
 	SO_ERROR                          = 0x1007
 	SO_KEEPALIVE                      = 0x8
 	SO_LINGER                         = 0x80
-	SO_NOSIGPIPE                      = 0x800
+	SO_NETPROC                        = 0x1020
 	SO_OOBINLINE                      = 0x100
+	SO_PEERCRED                       = 0x1022
 	SO_RCVBUF                         = 0x1002
 	SO_RCVLOWAT                       = 0x1004
 	SO_RCVTIMEO                       = 0x1006
 	SO_REUSEADDR                      = 0x4
 	SO_REUSEPORT                      = 0x200
+	SO_RTABLE                         = 0x1021
 	SO_SNDBUF                         = 0x1001
 	SO_SNDLOWAT                       = 0x1003
-	SO_SNDSPACE                       = 0x100a
 	SO_SNDTIMEO                       = 0x1005
-	SO_TIMESTAMP                      = 0x400
+	SO_SPLICE                         = 0x1023
+	SO_TIMESTAMP                      = 0x800
 	SO_TYPE                           = 0x1008
 	SO_USELOOPBACK                    = 0x40
 	TCIFLUSH                          = 0x1
 	TCIOFLUSH                         = 0x3
 	TCOFLUSH                          = 0x2
-	TCP_FASTKEEP                      = 0x80
-	TCP_KEEPCNT                       = 0x400
-	TCP_KEEPIDLE                      = 0x100
-	TCP_KEEPINIT                      = 0x20
-	TCP_KEEPINTVL                     = 0x200
 	TCP_MAXBURST                      = 0x4
-	TCP_MAXHLEN                       = 0x3c
-	TCP_MAXOLEN                       = 0x28
 	TCP_MAXSEG                        = 0x2
 	TCP_MAXWIN                        = 0xffff
+	TCP_MAX_SACK                      = 0x3
 	TCP_MAX_WINSHIFT                  = 0xe
-	TCP_MINMSS                        = 0x100
-	TCP_MIN_WINSHIFT                  = 0x5
+	TCP_MD5SIG                        = 0x4
 	TCP_MSS                           = 0x200
 	TCP_NODELAY                       = 0x1
-	TCP_NOOPT                         = 0x8
-	TCP_NOPUSH                        = 0x4
-	TCP_SIGNATURE_ENABLE              = 0x10
+	TCP_NOPUSH                        = 0x10
+	TCP_NSTATES                       = 0xb
+	TCP_SACK_ENABLE                   = 0x8
 	TCSAFLUSH                         = 0x2
 	TIOCCBRK                          = 0x2000747a
 	TIOCCDTR                          = 0x20007478
 	TIOCCONS                          = 0x80047462
-	TIOCDCDTIMESTAMP                  = 0x40087458
 	TIOCDRAIN                         = 0x2000745e
 	TIOCEXCL                          = 0x2000740d
 	TIOCEXT                           = 0x80047460
+	TIOCFLAG_CLOCAL                   = 0x2
+	TIOCFLAG_CRTSCTS                  = 0x4
+	TIOCFLAG_MDMBUF                   = 0x8
+	TIOCFLAG_PPS                      = 0x10
+	TIOCFLAG_SOFTCAR                  = 0x1
 	TIOCFLUSH                         = 0x80047410
-	TIOCGDRAINWAIT                    = 0x40047456
 	TIOCGETA                          = 0x402c7413
 	TIOCGETD                          = 0x4004741a
+	TIOCGFLAGS                        = 0x4004745d
 	TIOCGPGRP                         = 0x40047477
 	TIOCGSID                          = 0x40047463
-	TIOCGSIZE                         = 0x40087468
+	TIOCGTSTAMP                       = 0x400c745b
 	TIOCGWINSZ                        = 0x40087468
-	TIOCISPTMASTER                    = 0x20007455
 	TIOCMBIC                          = 0x8004746b
 	TIOCMBIS                          = 0x8004746c
-	TIOCMGDTRWAIT                     = 0x4004745a
 	TIOCMGET                          = 0x4004746a
-	TIOCMODG                          = 0x40047403
-	TIOCMODS                          = 0x80047404
-	TIOCMSDTRWAIT                     = 0x8004745b
+	TIOCMODG                          = 0x4004746a
+	TIOCMODS                          = 0x8004746d
 	TIOCMSET                          = 0x8004746d
 	TIOCM_CAR                         = 0x40
 	TIOCM_CD                          = 0x40
@@ -1194,31 +1275,28 @@
 	TIOCREMOTE                        = 0x80047469
 	TIOCSBRK                          = 0x2000747b
 	TIOCSCTTY                         = 0x20007461
-	TIOCSDRAINWAIT                    = 0x80047457
 	TIOCSDTR                          = 0x20007479
 	TIOCSETA                          = 0x802c7414
 	TIOCSETAF                         = 0x802c7416
 	TIOCSETAW                         = 0x802c7415
 	TIOCSETD                          = 0x8004741b
-	TIOCSIG                           = 0x2000745f
+	TIOCSFLAGS                        = 0x8004745c
+	TIOCSIG                           = 0x8004745f
 	TIOCSPGRP                         = 0x80047476
-	TIOCSSIZE                         = 0x80087467
 	TIOCSTART                         = 0x2000746e
-	TIOCSTAT                          = 0x20007465
+	TIOCSTAT                          = 0x80047465
 	TIOCSTI                           = 0x80017472
 	TIOCSTOP                          = 0x2000746f
+	TIOCSTSTAMP                       = 0x8008745a
 	TIOCSWINSZ                        = 0x80087467
-	TIOCTIMESTAMP                     = 0x40087459
 	TIOCUCNTL                         = 0x80047466
 	TOSTOP                            = 0x400000
-	VCHECKPT                          = 0x13
 	VDISCARD                          = 0xf
 	VDSUSP                            = 0xb
 	VEOF                              = 0x0
 	VEOL                              = 0x1
 	VEOL2                             = 0x2
 	VERASE                            = 0x3
-	VERASE2                           = 0x7
 	VINTR                             = 0x8
 	VKILL                             = 0x5
 	VLNEXT                            = 0xe
@@ -1231,11 +1309,10 @@
 	VSUSP                             = 0xa
 	VTIME                             = 0x11
 	VWERASE                           = 0x4
-	WCONTINUED                        = 0x4
+	WALTSIG                           = 0x4
+	WCONTINUED                        = 0x8
 	WCOREFLAG                         = 0x80
-	WLINUXCLONE                       = 0x80000000
 	WNOHANG                           = 0x1
-	WSTOPPED                          = 0x7f
 	WUNTRACED                         = 0x2
 )
 
@@ -1248,13 +1325,11 @@
 	EAFNOSUPPORT    = Errno(0x2f)
 	EAGAIN          = Errno(0x23)
 	EALREADY        = Errno(0x25)
-	EASYNC          = Errno(0x63)
 	EAUTH           = Errno(0x50)
 	EBADF           = Errno(0x9)
-	EBADMSG         = Errno(0x59)
 	EBADRPC         = Errno(0x48)
 	EBUSY           = Errno(0x10)
-	ECANCELED       = Errno(0x55)
+	ECANCELED       = Errno(0x58)
 	ECHILD          = Errno(0xa)
 	ECONNABORTED    = Errno(0x35)
 	ECONNREFUSED    = Errno(0x3d)
@@ -1262,7 +1337,6 @@
 	EDEADLK         = Errno(0xb)
 	EDESTADDRREQ    = Errno(0x27)
 	EDOM            = Errno(0x21)
-	EDOOFUS         = Errno(0x58)
 	EDQUOT          = Errno(0x45)
 	EEXIST          = Errno(0x11)
 	EFAULT          = Errno(0xe)
@@ -1270,36 +1344,36 @@
 	EFTYPE          = Errno(0x4f)
 	EHOSTDOWN       = Errno(0x40)
 	EHOSTUNREACH    = Errno(0x41)
-	EIDRM           = Errno(0x52)
-	EILSEQ          = Errno(0x56)
+	EIDRM           = Errno(0x59)
+	EILSEQ          = Errno(0x54)
 	EINPROGRESS     = Errno(0x24)
 	EINTR           = Errno(0x4)
 	EINVAL          = Errno(0x16)
 	EIO             = Errno(0x5)
+	EIPSEC          = Errno(0x52)
 	EISCONN         = Errno(0x38)
 	EISDIR          = Errno(0x15)
-	ELAST           = Errno(0x63)
+	ELAST           = Errno(0x5b)
 	ELOOP           = Errno(0x3e)
+	EMEDIUMTYPE     = Errno(0x56)
 	EMFILE          = Errno(0x18)
 	EMLINK          = Errno(0x1f)
 	EMSGSIZE        = Errno(0x28)
-	EMULTIHOP       = Errno(0x5a)
 	ENAMETOOLONG    = Errno(0x3f)
 	ENEEDAUTH       = Errno(0x51)
 	ENETDOWN        = Errno(0x32)
 	ENETRESET       = Errno(0x34)
 	ENETUNREACH     = Errno(0x33)
 	ENFILE          = Errno(0x17)
-	ENOATTR         = Errno(0x57)
+	ENOATTR         = Errno(0x53)
 	ENOBUFS         = Errno(0x37)
 	ENODEV          = Errno(0x13)
 	ENOENT          = Errno(0x2)
 	ENOEXEC         = Errno(0x8)
 	ENOLCK          = Errno(0x4d)
-	ENOLINK         = Errno(0x5b)
-	ENOMEDIUM       = Errno(0x5d)
+	ENOMEDIUM       = Errno(0x55)
 	ENOMEM          = Errno(0xc)
-	ENOMSG          = Errno(0x53)
+	ENOMSG          = Errno(0x5a)
 	ENOPROTOOPT     = Errno(0x2a)
 	ENOSPC          = Errno(0x1c)
 	ENOSYS          = Errno(0x4e)
@@ -1308,11 +1382,11 @@
 	ENOTDIR         = Errno(0x14)
 	ENOTEMPTY       = Errno(0x42)
 	ENOTSOCK        = Errno(0x26)
-	ENOTSUP         = Errno(0x2d)
+	ENOTSUP         = Errno(0x5b)
 	ENOTTY          = Errno(0x19)
 	ENXIO           = Errno(0x6)
 	EOPNOTSUPP      = Errno(0x2d)
-	EOVERFLOW       = Errno(0x54)
+	EOVERFLOW       = Errno(0x57)
 	EPERM           = Errno(0x1)
 	EPFNOSUPPORT    = Errno(0x2e)
 	EPIPE           = Errno(0x20)
@@ -1320,7 +1394,6 @@
 	EPROCUNAVAIL    = Errno(0x4c)
 	EPROGMISMATCH   = Errno(0x4b)
 	EPROGUNAVAIL    = Errno(0x4a)
-	EPROTO          = Errno(0x5c)
 	EPROTONOSUPPORT = Errno(0x2b)
 	EPROTOTYPE      = Errno(0x29)
 	ERANGE          = Errno(0x22)
@@ -1335,11 +1408,6 @@
 	ETIMEDOUT       = Errno(0x3c)
 	ETOOMANYREFS    = Errno(0x3b)
 	ETXTBSY         = Errno(0x1a)
-	EUNUSED94       = Errno(0x5e)
-	EUNUSED95       = Errno(0x5f)
-	EUNUSED96       = Errno(0x60)
-	EUNUSED97       = Errno(0x61)
-	EUNUSED98       = Errno(0x62)
 	EUSERS          = Errno(0x44)
 	EWOULDBLOCK     = Errno(0x23)
 	EXDEV           = Errno(0x12)
@@ -1347,41 +1415,39 @@
 
 // Signals
 const (
-	SIGABRT     = Signal(0x6)
-	SIGALRM     = Signal(0xe)
-	SIGBUS      = Signal(0xa)
-	SIGCHLD     = Signal(0x14)
-	SIGCKPT     = Signal(0x21)
-	SIGCKPTEXIT = Signal(0x22)
-	SIGCONT     = Signal(0x13)
-	SIGEMT      = Signal(0x7)
-	SIGFPE      = Signal(0x8)
-	SIGHUP      = Signal(0x1)
-	SIGILL      = Signal(0x4)
-	SIGINFO     = Signal(0x1d)
-	SIGINT      = Signal(0x2)
-	SIGIO       = Signal(0x17)
-	SIGIOT      = Signal(0x6)
-	SIGKILL     = Signal(0x9)
-	SIGPIPE     = Signal(0xd)
-	SIGPROF     = Signal(0x1b)
-	SIGQUIT     = Signal(0x3)
-	SIGSEGV     = Signal(0xb)
-	SIGSTOP     = Signal(0x11)
-	SIGSYS      = Signal(0xc)
-	SIGTERM     = Signal(0xf)
-	SIGTHR      = Signal(0x20)
-	SIGTRAP     = Signal(0x5)
-	SIGTSTP     = Signal(0x12)
-	SIGTTIN     = Signal(0x15)
-	SIGTTOU     = Signal(0x16)
-	SIGURG      = Signal(0x10)
-	SIGUSR1     = Signal(0x1e)
-	SIGUSR2     = Signal(0x1f)
-	SIGVTALRM   = Signal(0x1a)
-	SIGWINCH    = Signal(0x1c)
-	SIGXCPU     = Signal(0x18)
-	SIGXFSZ     = Signal(0x19)
+	SIGABRT   = Signal(0x6)
+	SIGALRM   = Signal(0xe)
+	SIGBUS    = Signal(0xa)
+	SIGCHLD   = Signal(0x14)
+	SIGCONT   = Signal(0x13)
+	SIGEMT    = Signal(0x7)
+	SIGFPE    = Signal(0x8)
+	SIGHUP    = Signal(0x1)
+	SIGILL    = Signal(0x4)
+	SIGINFO   = Signal(0x1d)
+	SIGINT    = Signal(0x2)
+	SIGIO     = Signal(0x17)
+	SIGIOT    = Signal(0x6)
+	SIGKILL   = Signal(0x9)
+	SIGPIPE   = Signal(0xd)
+	SIGPROF   = Signal(0x1b)
+	SIGQUIT   = Signal(0x3)
+	SIGSEGV   = Signal(0xb)
+	SIGSTOP   = Signal(0x11)
+	SIGSYS    = Signal(0xc)
+	SIGTERM   = Signal(0xf)
+	SIGTHR    = Signal(0x20)
+	SIGTRAP   = Signal(0x5)
+	SIGTSTP   = Signal(0x12)
+	SIGTTIN   = Signal(0x15)
+	SIGTTOU   = Signal(0x16)
+	SIGURG    = Signal(0x10)
+	SIGUSR1   = Signal(0x1e)
+	SIGUSR2   = Signal(0x1f)
+	SIGVTALRM = Signal(0x1a)
+	SIGWINCH  = Signal(0x1c)
+	SIGXCPU   = Signal(0x18)
+	SIGXFSZ   = Signal(0x19)
 )
 
 // Error table
@@ -1445,7 +1511,7 @@
 	57: "socket is not connected",
 	58: "can't send after socket shutdown",
 	59: "too many references: can't splice",
-	60: "operation timed out",
+	60: "connection timed out",
 	61: "connection refused",
 	62: "too many levels of symbolic links",
 	63: "file name too long",
@@ -1467,24 +1533,16 @@
 	79: "inappropriate file type or format",
 	80: "authentication error",
 	81: "need authenticator",
-	82: "identifier removed",
-	83: "no message of desired type",
-	84: "value too large to be stored in data type",
-	85: "operation canceled",
-	86: "illegal byte sequence",
-	87: "attribute not found",
-	88: "programming error",
-	89: "bad message",
-	90: "multihop attempted",
-	91: "link has been severed",
-	92: "protocol error",
-	93: "no medium found",
-	94: "unknown error: 94",
-	95: "unknown error: 95",
-	96: "unknown error: 96",
-	97: "unknown error: 97",
-	98: "unknown error: 98",
-	99: "unknown error: 99",
+	82: "IPsec processing failure",
+	83: "attribute not found",
+	84: "illegal byte sequence",
+	85: "no medium found",
+	86: "wrong medium type",
+	87: "value too large to be stored in data type",
+	88: "operation canceled",
+	89: "identifier removed",
+	90: "no message of desired type",
+	91: "not supported",
 }
 
 // Signal table
@@ -1505,8 +1563,8 @@
 	14: "alarm clock",
 	15: "terminated",
 	16: "urgent I/O condition",
-	17: "suspended (signal)",
-	18: "suspended",
+	17: "stopped (signal)",
+	18: "stopped",
 	19: "continued",
 	20: "child exited",
 	21: "stopped (tty input)",
@@ -1520,7 +1578,5 @@
 	29: "information request",
 	30: "user defined signal 1",
 	31: "user defined signal 2",
-	32: "thread Scheduler",
-	33: "checkPoint",
-	34: "checkPointExit",
+	32: "thread AST",
 }
diff --git a/src/syscall/zsyscall_darwin_386.go b/src/syscall/zsyscall_darwin_386.go
index 934565f..0ce383f 100644
--- a/src/syscall/zsyscall_darwin_386.go
+++ b/src/syscall/zsyscall_darwin_386.go
@@ -11,7 +11,7 @@
 	r0, _, e1 := RawSyscall(SYS_GETGROUPS, uintptr(ngid), uintptr(unsafe.Pointer(gid)), 0)
 	n = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -21,7 +21,7 @@
 func setgroups(ngid int, gid *_Gid_t) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETGROUPS, uintptr(ngid), uintptr(unsafe.Pointer(gid)), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -32,7 +32,7 @@
 	r0, _, e1 := Syscall6(SYS_WAIT4, uintptr(pid), uintptr(unsafe.Pointer(wstatus)), uintptr(options), uintptr(unsafe.Pointer(rusage)), 0, 0)
 	wpid = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -43,7 +43,7 @@
 	r0, _, e1 := Syscall(SYS_ACCEPT, uintptr(s), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)))
 	fd = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -53,7 +53,7 @@
 func bind(s int, addr unsafe.Pointer, addrlen _Socklen) (err error) {
 	_, _, e1 := Syscall(SYS_BIND, uintptr(s), uintptr(addr), uintptr(addrlen))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -63,7 +63,7 @@
 func connect(s int, addr unsafe.Pointer, addrlen _Socklen) (err error) {
 	_, _, e1 := Syscall(SYS_CONNECT, uintptr(s), uintptr(addr), uintptr(addrlen))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -74,7 +74,7 @@
 	r0, _, e1 := RawSyscall(SYS_SOCKET, uintptr(domain), uintptr(typ), uintptr(proto))
 	fd = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -84,7 +84,7 @@
 func getsockopt(s int, level int, name int, val unsafe.Pointer, vallen *_Socklen) (err error) {
 	_, _, e1 := Syscall6(SYS_GETSOCKOPT, uintptr(s), uintptr(level), uintptr(name), uintptr(val), uintptr(unsafe.Pointer(vallen)), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -94,7 +94,7 @@
 func setsockopt(s int, level int, name int, val unsafe.Pointer, vallen uintptr) (err error) {
 	_, _, e1 := Syscall6(SYS_SETSOCKOPT, uintptr(s), uintptr(level), uintptr(name), uintptr(val), uintptr(vallen), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -104,7 +104,7 @@
 func getpeername(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (err error) {
 	_, _, e1 := RawSyscall(SYS_GETPEERNAME, uintptr(fd), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -114,7 +114,7 @@
 func getsockname(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (err error) {
 	_, _, e1 := RawSyscall(SYS_GETSOCKNAME, uintptr(fd), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -124,7 +124,7 @@
 func Shutdown(s int, how int) (err error) {
 	_, _, e1 := Syscall(SYS_SHUTDOWN, uintptr(s), uintptr(how), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -134,7 +134,7 @@
 func socketpair(domain int, typ int, proto int, fd *[2]int32) (err error) {
 	_, _, e1 := RawSyscall6(SYS_SOCKETPAIR, uintptr(domain), uintptr(typ), uintptr(proto), uintptr(unsafe.Pointer(fd)), 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -151,7 +151,7 @@
 	r0, _, e1 := Syscall6(SYS_RECVFROM, uintptr(fd), uintptr(_p0), uintptr(len(p)), uintptr(flags), uintptr(unsafe.Pointer(from)), uintptr(unsafe.Pointer(fromlen)))
 	n = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -167,7 +167,7 @@
 	}
 	_, _, e1 := Syscall6(SYS_SENDTO, uintptr(s), uintptr(_p0), uintptr(len(buf)), uintptr(flags), uintptr(to), uintptr(addrlen))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -178,7 +178,7 @@
 	r0, _, e1 := Syscall(SYS_RECVMSG, uintptr(s), uintptr(unsafe.Pointer(msg)), uintptr(flags))
 	n = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -189,7 +189,7 @@
 	r0, _, e1 := Syscall(SYS_SENDMSG, uintptr(s), uintptr(unsafe.Pointer(msg)), uintptr(flags))
 	n = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -200,7 +200,7 @@
 	r0, _, e1 := Syscall6(SYS_KEVENT, uintptr(kq), uintptr(change), uintptr(nchange), uintptr(event), uintptr(nevent), uintptr(unsafe.Pointer(timeout)))
 	n = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -216,7 +216,7 @@
 	}
 	_, _, e1 := Syscall6(SYS___SYSCTL, uintptr(_p0), uintptr(len(mib)), uintptr(unsafe.Pointer(old)), uintptr(unsafe.Pointer(oldlen)), uintptr(unsafe.Pointer(new)), uintptr(newlen))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -232,7 +232,7 @@
 	_, _, e1 := Syscall(SYS_UTIMES, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(timeval)), 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -242,7 +242,7 @@
 func futimes(fd int, timeval *[2]Timeval) (err error) {
 	_, _, e1 := Syscall(SYS_FUTIMES, uintptr(fd), uintptr(unsafe.Pointer(timeval)), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -253,7 +253,7 @@
 	r0, _, e1 := Syscall(SYS_FCNTL, uintptr(fd), uintptr(cmd), uintptr(arg))
 	val = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -263,7 +263,7 @@
 func ptrace(request int, pid int, addr uintptr, data uintptr) (err error) {
 	_, _, e1 := Syscall6(SYS_PTRACE, uintptr(request), uintptr(pid), uintptr(addr), uintptr(data), 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -275,7 +275,7 @@
 	r = int(r0)
 	w = int(r1)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -285,7 +285,7 @@
 func kill(pid int, signum int, posix int) (err error) {
 	_, _, e1 := Syscall(SYS_KILL, uintptr(pid), uintptr(signum), uintptr(posix))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -301,7 +301,7 @@
 	_, _, e1 := Syscall(SYS_ACCESS, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -311,7 +311,7 @@
 func Adjtime(delta *Timeval, olddelta *Timeval) (err error) {
 	_, _, e1 := Syscall(SYS_ADJTIME, uintptr(unsafe.Pointer(delta)), uintptr(unsafe.Pointer(olddelta)), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -327,7 +327,7 @@
 	_, _, e1 := Syscall(SYS_CHDIR, uintptr(unsafe.Pointer(_p0)), 0, 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -343,7 +343,7 @@
 	_, _, e1 := Syscall(SYS_CHFLAGS, uintptr(unsafe.Pointer(_p0)), uintptr(flags), 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -359,7 +359,7 @@
 	_, _, e1 := Syscall(SYS_CHMOD, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -375,7 +375,7 @@
 	_, _, e1 := Syscall(SYS_CHOWN, uintptr(unsafe.Pointer(_p0)), uintptr(uid), uintptr(gid))
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -391,7 +391,7 @@
 	_, _, e1 := Syscall(SYS_CHROOT, uintptr(unsafe.Pointer(_p0)), 0, 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -401,7 +401,7 @@
 func Close(fd int) (err error) {
 	_, _, e1 := Syscall(SYS_CLOSE, uintptr(fd), 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -409,10 +409,10 @@
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
 func Dup(fd int) (nfd int, err error) {
-	r0, _, e1 := RawSyscall(SYS_DUP, uintptr(fd), 0, 0)
+	r0, _, e1 := Syscall(SYS_DUP, uintptr(fd), 0, 0)
 	nfd = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -420,9 +420,9 @@
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
 func Dup2(from int, to int) (err error) {
-	_, _, e1 := RawSyscall(SYS_DUP2, uintptr(from), uintptr(to), 0)
+	_, _, e1 := Syscall(SYS_DUP2, uintptr(from), uintptr(to), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -444,7 +444,7 @@
 	use(unsafe.Pointer(_p0))
 	use(unsafe.Pointer(_p1))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -461,7 +461,7 @@
 func Fchdir(fd int) (err error) {
 	_, _, e1 := Syscall(SYS_FCHDIR, uintptr(fd), 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -471,7 +471,7 @@
 func Fchflags(fd int, flags int) (err error) {
 	_, _, e1 := Syscall(SYS_FCHFLAGS, uintptr(fd), uintptr(flags), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -481,7 +481,7 @@
 func Fchmod(fd int, mode uint32) (err error) {
 	_, _, e1 := Syscall(SYS_FCHMOD, uintptr(fd), uintptr(mode), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -491,7 +491,7 @@
 func Fchown(fd int, uid int, gid int) (err error) {
 	_, _, e1 := Syscall(SYS_FCHOWN, uintptr(fd), uintptr(uid), uintptr(gid))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -501,7 +501,7 @@
 func Flock(fd int, how int) (err error) {
 	_, _, e1 := Syscall(SYS_FLOCK, uintptr(fd), uintptr(how), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -512,7 +512,7 @@
 	r0, _, e1 := Syscall(SYS_FPATHCONF, uintptr(fd), uintptr(name), 0)
 	val = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -522,7 +522,7 @@
 func Fstat(fd int, stat *Stat_t) (err error) {
 	_, _, e1 := Syscall(SYS_FSTAT64, uintptr(fd), uintptr(unsafe.Pointer(stat)), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -532,7 +532,7 @@
 func Fstatfs(fd int, stat *Statfs_t) (err error) {
 	_, _, e1 := Syscall(SYS_FSTATFS64, uintptr(fd), uintptr(unsafe.Pointer(stat)), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -542,7 +542,7 @@
 func Fsync(fd int) (err error) {
 	_, _, e1 := Syscall(SYS_FSYNC, uintptr(fd), 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -552,7 +552,7 @@
 func Ftruncate(fd int, length int64) (err error) {
 	_, _, e1 := Syscall(SYS_FTRUNCATE, uintptr(fd), uintptr(length), uintptr(length>>32))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -569,7 +569,7 @@
 	r0, _, e1 := Syscall6(SYS_GETDIRENTRIES64, uintptr(fd), uintptr(_p0), uintptr(len(buf)), uintptr(unsafe.Pointer(basep)), 0, 0)
 	n = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -612,7 +612,7 @@
 	r0, _, e1 := RawSyscall(SYS_GETPGID, uintptr(pid), 0, 0)
 	pgid = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -647,7 +647,7 @@
 	r0, _, e1 := Syscall(SYS_GETPRIORITY, uintptr(which), uintptr(who), 0)
 	prio = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -657,7 +657,7 @@
 func Getrlimit(which int, lim *Rlimit) (err error) {
 	_, _, e1 := RawSyscall(SYS_GETRLIMIT, uintptr(which), uintptr(unsafe.Pointer(lim)), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -667,7 +667,7 @@
 func Getrusage(who int, rusage *Rusage) (err error) {
 	_, _, e1 := RawSyscall(SYS_GETRUSAGE, uintptr(who), uintptr(unsafe.Pointer(rusage)), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -678,7 +678,7 @@
 	r0, _, e1 := RawSyscall(SYS_GETSID, uintptr(pid), 0, 0)
 	sid = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -705,7 +705,7 @@
 	r0, _, e1 := Syscall(SYS_KQUEUE, 0, 0, 0)
 	fd = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -721,7 +721,7 @@
 	_, _, e1 := Syscall(SYS_LCHOWN, uintptr(unsafe.Pointer(_p0)), uintptr(uid), uintptr(gid))
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -743,7 +743,7 @@
 	use(unsafe.Pointer(_p0))
 	use(unsafe.Pointer(_p1))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -753,7 +753,7 @@
 func Listen(s int, backlog int) (err error) {
 	_, _, e1 := Syscall(SYS_LISTEN, uintptr(s), uintptr(backlog), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -769,7 +769,7 @@
 	_, _, e1 := Syscall(SYS_LSTAT64, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -785,7 +785,7 @@
 	_, _, e1 := Syscall(SYS_MKDIR, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -801,7 +801,7 @@
 	_, _, e1 := Syscall(SYS_MKFIFO, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -817,7 +817,7 @@
 	_, _, e1 := Syscall(SYS_MKNOD, uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(dev))
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -833,7 +833,7 @@
 	}
 	_, _, e1 := Syscall(SYS_MLOCK, uintptr(_p0), uintptr(len(b)), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -843,7 +843,7 @@
 func Mlockall(flags int) (err error) {
 	_, _, e1 := Syscall(SYS_MLOCKALL, uintptr(flags), 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -859,7 +859,7 @@
 	}
 	_, _, e1 := Syscall(SYS_MPROTECT, uintptr(_p0), uintptr(len(b)), uintptr(prot))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -875,7 +875,7 @@
 	}
 	_, _, e1 := Syscall(SYS_MUNLOCK, uintptr(_p0), uintptr(len(b)), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -885,7 +885,7 @@
 func Munlockall() (err error) {
 	_, _, e1 := Syscall(SYS_MUNLOCKALL, 0, 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -902,7 +902,7 @@
 	use(unsafe.Pointer(_p0))
 	fd = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -919,7 +919,7 @@
 	use(unsafe.Pointer(_p0))
 	val = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -936,7 +936,7 @@
 	r0, _, e1 := Syscall6(SYS_PREAD, uintptr(fd), uintptr(_p0), uintptr(len(p)), uintptr(offset), uintptr(offset>>32), 0)
 	n = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -953,7 +953,7 @@
 	r0, _, e1 := Syscall6(SYS_PWRITE, uintptr(fd), uintptr(_p0), uintptr(len(p)), uintptr(offset), uintptr(offset>>32), 0)
 	n = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -970,7 +970,7 @@
 	r0, _, e1 := Syscall(SYS_READ, uintptr(fd), uintptr(_p0), uintptr(len(p)))
 	n = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -993,7 +993,7 @@
 	use(unsafe.Pointer(_p0))
 	n = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1015,7 +1015,7 @@
 	use(unsafe.Pointer(_p0))
 	use(unsafe.Pointer(_p1))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1031,7 +1031,7 @@
 	_, _, e1 := Syscall(SYS_REVOKE, uintptr(unsafe.Pointer(_p0)), 0, 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1047,7 +1047,7 @@
 	_, _, e1 := Syscall(SYS_RMDIR, uintptr(unsafe.Pointer(_p0)), 0, 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1058,7 +1058,7 @@
 	r0, r1, e1 := Syscall6(SYS_LSEEK, uintptr(fd), uintptr(offset), uintptr(offset>>32), uintptr(whence), 0, 0)
 	newoffset = int64(int64(r1)<<32 | int64(r0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1068,7 +1068,7 @@
 func Select(n int, r *FdSet, w *FdSet, e *FdSet, timeout *Timeval) (err error) {
 	_, _, e1 := Syscall6(SYS_SELECT, uintptr(n), uintptr(unsafe.Pointer(r)), uintptr(unsafe.Pointer(w)), uintptr(unsafe.Pointer(e)), uintptr(unsafe.Pointer(timeout)), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1078,7 +1078,7 @@
 func Setegid(egid int) (err error) {
 	_, _, e1 := Syscall(SYS_SETEGID, uintptr(egid), 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1088,7 +1088,7 @@
 func Seteuid(euid int) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETEUID, uintptr(euid), 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1098,7 +1098,7 @@
 func Setgid(gid int) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETGID, uintptr(gid), 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1114,7 +1114,7 @@
 	_, _, e1 := Syscall(SYS_SETLOGIN, uintptr(unsafe.Pointer(_p0)), 0, 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1124,7 +1124,7 @@
 func Setpgid(pid int, pgid int) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETPGID, uintptr(pid), uintptr(pgid), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1134,7 +1134,7 @@
 func Setpriority(which int, who int, prio int) (err error) {
 	_, _, e1 := Syscall(SYS_SETPRIORITY, uintptr(which), uintptr(who), uintptr(prio))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1144,7 +1144,7 @@
 func Setprivexec(flag int) (err error) {
 	_, _, e1 := Syscall(SYS_SETPRIVEXEC, uintptr(flag), 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1154,7 +1154,7 @@
 func Setregid(rgid int, egid int) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETREGID, uintptr(rgid), uintptr(egid), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1164,7 +1164,7 @@
 func Setreuid(ruid int, euid int) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETREUID, uintptr(ruid), uintptr(euid), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1174,7 +1174,7 @@
 func Setrlimit(which int, lim *Rlimit) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETRLIMIT, uintptr(which), uintptr(unsafe.Pointer(lim)), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1185,7 +1185,7 @@
 	r0, _, e1 := RawSyscall(SYS_SETSID, 0, 0, 0)
 	pid = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1195,7 +1195,7 @@
 func Settimeofday(tp *Timeval) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETTIMEOFDAY, uintptr(unsafe.Pointer(tp)), 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1205,7 +1205,7 @@
 func Setuid(uid int) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETUID, uintptr(uid), 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1221,7 +1221,7 @@
 	_, _, e1 := Syscall(SYS_STAT64, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1237,7 +1237,7 @@
 	_, _, e1 := Syscall(SYS_STATFS64, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1259,7 +1259,7 @@
 	use(unsafe.Pointer(_p0))
 	use(unsafe.Pointer(_p1))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1269,7 +1269,7 @@
 func Sync() (err error) {
 	_, _, e1 := Syscall(SYS_SYNC, 0, 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1285,7 +1285,7 @@
 	_, _, e1 := Syscall(SYS_TRUNCATE, uintptr(unsafe.Pointer(_p0)), uintptr(length), uintptr(length>>32))
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1309,7 +1309,7 @@
 	_, _, e1 := Syscall(SYS_UNDELETE, uintptr(unsafe.Pointer(_p0)), 0, 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1325,7 +1325,7 @@
 	_, _, e1 := Syscall(SYS_UNLINK, uintptr(unsafe.Pointer(_p0)), 0, 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1341,7 +1341,7 @@
 	_, _, e1 := Syscall(SYS_UNMOUNT, uintptr(unsafe.Pointer(_p0)), uintptr(flags), 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1358,7 +1358,7 @@
 	r0, _, e1 := Syscall(SYS_WRITE, uintptr(fd), uintptr(_p0), uintptr(len(p)))
 	n = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1369,7 +1369,7 @@
 	r0, _, e1 := Syscall9(SYS_MMAP, uintptr(addr), uintptr(length), uintptr(prot), uintptr(flag), uintptr(fd), uintptr(pos), uintptr(pos>>32), 0, 0)
 	ret = uintptr(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1379,7 +1379,7 @@
 func munmap(addr uintptr, length uintptr) (err error) {
 	_, _, e1 := Syscall(SYS_MUNMAP, uintptr(addr), uintptr(length), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1390,7 +1390,7 @@
 	r0, _, e1 := Syscall(SYS_READ, uintptr(fd), uintptr(unsafe.Pointer(buf)), uintptr(nbuf))
 	n = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1401,7 +1401,7 @@
 	r0, _, e1 := Syscall(SYS_WRITE, uintptr(fd), uintptr(unsafe.Pointer(buf)), uintptr(nbuf))
 	n = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1413,7 +1413,7 @@
 	sec = int32(r0)
 	usec = int32(r1)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
diff --git a/src/syscall/zsyscall_darwin_amd64.go b/src/syscall/zsyscall_darwin_amd64.go
index 75cf251..2370630 100644
--- a/src/syscall/zsyscall_darwin_amd64.go
+++ b/src/syscall/zsyscall_darwin_amd64.go
@@ -11,7 +11,7 @@
 	r0, _, e1 := RawSyscall(SYS_GETGROUPS, uintptr(ngid), uintptr(unsafe.Pointer(gid)), 0)
 	n = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -21,7 +21,7 @@
 func setgroups(ngid int, gid *_Gid_t) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETGROUPS, uintptr(ngid), uintptr(unsafe.Pointer(gid)), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -32,7 +32,7 @@
 	r0, _, e1 := Syscall6(SYS_WAIT4, uintptr(pid), uintptr(unsafe.Pointer(wstatus)), uintptr(options), uintptr(unsafe.Pointer(rusage)), 0, 0)
 	wpid = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -43,7 +43,7 @@
 	r0, _, e1 := Syscall(SYS_ACCEPT, uintptr(s), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)))
 	fd = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -53,7 +53,7 @@
 func bind(s int, addr unsafe.Pointer, addrlen _Socklen) (err error) {
 	_, _, e1 := Syscall(SYS_BIND, uintptr(s), uintptr(addr), uintptr(addrlen))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -63,7 +63,7 @@
 func connect(s int, addr unsafe.Pointer, addrlen _Socklen) (err error) {
 	_, _, e1 := Syscall(SYS_CONNECT, uintptr(s), uintptr(addr), uintptr(addrlen))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -74,7 +74,7 @@
 	r0, _, e1 := RawSyscall(SYS_SOCKET, uintptr(domain), uintptr(typ), uintptr(proto))
 	fd = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -84,7 +84,7 @@
 func getsockopt(s int, level int, name int, val unsafe.Pointer, vallen *_Socklen) (err error) {
 	_, _, e1 := Syscall6(SYS_GETSOCKOPT, uintptr(s), uintptr(level), uintptr(name), uintptr(val), uintptr(unsafe.Pointer(vallen)), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -94,7 +94,7 @@
 func setsockopt(s int, level int, name int, val unsafe.Pointer, vallen uintptr) (err error) {
 	_, _, e1 := Syscall6(SYS_SETSOCKOPT, uintptr(s), uintptr(level), uintptr(name), uintptr(val), uintptr(vallen), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -104,7 +104,7 @@
 func getpeername(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (err error) {
 	_, _, e1 := RawSyscall(SYS_GETPEERNAME, uintptr(fd), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -114,7 +114,7 @@
 func getsockname(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (err error) {
 	_, _, e1 := RawSyscall(SYS_GETSOCKNAME, uintptr(fd), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -124,7 +124,7 @@
 func Shutdown(s int, how int) (err error) {
 	_, _, e1 := Syscall(SYS_SHUTDOWN, uintptr(s), uintptr(how), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -134,7 +134,7 @@
 func socketpair(domain int, typ int, proto int, fd *[2]int32) (err error) {
 	_, _, e1 := RawSyscall6(SYS_SOCKETPAIR, uintptr(domain), uintptr(typ), uintptr(proto), uintptr(unsafe.Pointer(fd)), 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -151,7 +151,7 @@
 	r0, _, e1 := Syscall6(SYS_RECVFROM, uintptr(fd), uintptr(_p0), uintptr(len(p)), uintptr(flags), uintptr(unsafe.Pointer(from)), uintptr(unsafe.Pointer(fromlen)))
 	n = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -167,7 +167,7 @@
 	}
 	_, _, e1 := Syscall6(SYS_SENDTO, uintptr(s), uintptr(_p0), uintptr(len(buf)), uintptr(flags), uintptr(to), uintptr(addrlen))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -178,7 +178,7 @@
 	r0, _, e1 := Syscall(SYS_RECVMSG, uintptr(s), uintptr(unsafe.Pointer(msg)), uintptr(flags))
 	n = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -189,7 +189,7 @@
 	r0, _, e1 := Syscall(SYS_SENDMSG, uintptr(s), uintptr(unsafe.Pointer(msg)), uintptr(flags))
 	n = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -200,7 +200,7 @@
 	r0, _, e1 := Syscall6(SYS_KEVENT, uintptr(kq), uintptr(change), uintptr(nchange), uintptr(event), uintptr(nevent), uintptr(unsafe.Pointer(timeout)))
 	n = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -216,7 +216,7 @@
 	}
 	_, _, e1 := Syscall6(SYS___SYSCTL, uintptr(_p0), uintptr(len(mib)), uintptr(unsafe.Pointer(old)), uintptr(unsafe.Pointer(oldlen)), uintptr(unsafe.Pointer(new)), uintptr(newlen))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -232,7 +232,7 @@
 	_, _, e1 := Syscall(SYS_UTIMES, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(timeval)), 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -242,7 +242,7 @@
 func futimes(fd int, timeval *[2]Timeval) (err error) {
 	_, _, e1 := Syscall(SYS_FUTIMES, uintptr(fd), uintptr(unsafe.Pointer(timeval)), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -253,7 +253,7 @@
 	r0, _, e1 := Syscall(SYS_FCNTL, uintptr(fd), uintptr(cmd), uintptr(arg))
 	val = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -263,7 +263,7 @@
 func ptrace(request int, pid int, addr uintptr, data uintptr) (err error) {
 	_, _, e1 := Syscall6(SYS_PTRACE, uintptr(request), uintptr(pid), uintptr(addr), uintptr(data), 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -275,7 +275,7 @@
 	r = int(r0)
 	w = int(r1)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -285,7 +285,7 @@
 func kill(pid int, signum int, posix int) (err error) {
 	_, _, e1 := Syscall(SYS_KILL, uintptr(pid), uintptr(signum), uintptr(posix))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -301,7 +301,7 @@
 	_, _, e1 := Syscall(SYS_ACCESS, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -311,7 +311,7 @@
 func Adjtime(delta *Timeval, olddelta *Timeval) (err error) {
 	_, _, e1 := Syscall(SYS_ADJTIME, uintptr(unsafe.Pointer(delta)), uintptr(unsafe.Pointer(olddelta)), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -327,7 +327,7 @@
 	_, _, e1 := Syscall(SYS_CHDIR, uintptr(unsafe.Pointer(_p0)), 0, 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -343,7 +343,7 @@
 	_, _, e1 := Syscall(SYS_CHFLAGS, uintptr(unsafe.Pointer(_p0)), uintptr(flags), 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -359,7 +359,7 @@
 	_, _, e1 := Syscall(SYS_CHMOD, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -375,7 +375,7 @@
 	_, _, e1 := Syscall(SYS_CHOWN, uintptr(unsafe.Pointer(_p0)), uintptr(uid), uintptr(gid))
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -391,7 +391,7 @@
 	_, _, e1 := Syscall(SYS_CHROOT, uintptr(unsafe.Pointer(_p0)), 0, 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -401,7 +401,7 @@
 func Close(fd int) (err error) {
 	_, _, e1 := Syscall(SYS_CLOSE, uintptr(fd), 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -409,10 +409,10 @@
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
 func Dup(fd int) (nfd int, err error) {
-	r0, _, e1 := RawSyscall(SYS_DUP, uintptr(fd), 0, 0)
+	r0, _, e1 := Syscall(SYS_DUP, uintptr(fd), 0, 0)
 	nfd = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -420,9 +420,9 @@
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
 func Dup2(from int, to int) (err error) {
-	_, _, e1 := RawSyscall(SYS_DUP2, uintptr(from), uintptr(to), 0)
+	_, _, e1 := Syscall(SYS_DUP2, uintptr(from), uintptr(to), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -444,7 +444,7 @@
 	use(unsafe.Pointer(_p0))
 	use(unsafe.Pointer(_p1))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -461,7 +461,7 @@
 func Fchdir(fd int) (err error) {
 	_, _, e1 := Syscall(SYS_FCHDIR, uintptr(fd), 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -471,7 +471,7 @@
 func Fchflags(fd int, flags int) (err error) {
 	_, _, e1 := Syscall(SYS_FCHFLAGS, uintptr(fd), uintptr(flags), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -481,7 +481,7 @@
 func Fchmod(fd int, mode uint32) (err error) {
 	_, _, e1 := Syscall(SYS_FCHMOD, uintptr(fd), uintptr(mode), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -491,7 +491,7 @@
 func Fchown(fd int, uid int, gid int) (err error) {
 	_, _, e1 := Syscall(SYS_FCHOWN, uintptr(fd), uintptr(uid), uintptr(gid))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -501,7 +501,7 @@
 func Flock(fd int, how int) (err error) {
 	_, _, e1 := Syscall(SYS_FLOCK, uintptr(fd), uintptr(how), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -512,7 +512,7 @@
 	r0, _, e1 := Syscall(SYS_FPATHCONF, uintptr(fd), uintptr(name), 0)
 	val = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -522,7 +522,7 @@
 func Fstat(fd int, stat *Stat_t) (err error) {
 	_, _, e1 := Syscall(SYS_FSTAT64, uintptr(fd), uintptr(unsafe.Pointer(stat)), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -532,7 +532,7 @@
 func Fstatfs(fd int, stat *Statfs_t) (err error) {
 	_, _, e1 := Syscall(SYS_FSTATFS64, uintptr(fd), uintptr(unsafe.Pointer(stat)), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -542,7 +542,7 @@
 func Fsync(fd int) (err error) {
 	_, _, e1 := Syscall(SYS_FSYNC, uintptr(fd), 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -552,7 +552,7 @@
 func Ftruncate(fd int, length int64) (err error) {
 	_, _, e1 := Syscall(SYS_FTRUNCATE, uintptr(fd), uintptr(length), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -569,7 +569,7 @@
 	r0, _, e1 := Syscall6(SYS_GETDIRENTRIES64, uintptr(fd), uintptr(_p0), uintptr(len(buf)), uintptr(unsafe.Pointer(basep)), 0, 0)
 	n = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -612,7 +612,7 @@
 	r0, _, e1 := RawSyscall(SYS_GETPGID, uintptr(pid), 0, 0)
 	pgid = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -647,7 +647,7 @@
 	r0, _, e1 := Syscall(SYS_GETPRIORITY, uintptr(which), uintptr(who), 0)
 	prio = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -657,7 +657,7 @@
 func Getrlimit(which int, lim *Rlimit) (err error) {
 	_, _, e1 := RawSyscall(SYS_GETRLIMIT, uintptr(which), uintptr(unsafe.Pointer(lim)), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -667,7 +667,7 @@
 func Getrusage(who int, rusage *Rusage) (err error) {
 	_, _, e1 := RawSyscall(SYS_GETRUSAGE, uintptr(who), uintptr(unsafe.Pointer(rusage)), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -678,7 +678,7 @@
 	r0, _, e1 := RawSyscall(SYS_GETSID, uintptr(pid), 0, 0)
 	sid = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -705,7 +705,7 @@
 	r0, _, e1 := Syscall(SYS_KQUEUE, 0, 0, 0)
 	fd = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -721,7 +721,7 @@
 	_, _, e1 := Syscall(SYS_LCHOWN, uintptr(unsafe.Pointer(_p0)), uintptr(uid), uintptr(gid))
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -743,7 +743,7 @@
 	use(unsafe.Pointer(_p0))
 	use(unsafe.Pointer(_p1))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -753,7 +753,7 @@
 func Listen(s int, backlog int) (err error) {
 	_, _, e1 := Syscall(SYS_LISTEN, uintptr(s), uintptr(backlog), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -769,7 +769,7 @@
 	_, _, e1 := Syscall(SYS_LSTAT64, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -785,7 +785,7 @@
 	_, _, e1 := Syscall(SYS_MKDIR, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -801,7 +801,7 @@
 	_, _, e1 := Syscall(SYS_MKFIFO, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -817,7 +817,7 @@
 	_, _, e1 := Syscall(SYS_MKNOD, uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(dev))
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -833,7 +833,7 @@
 	}
 	_, _, e1 := Syscall(SYS_MLOCK, uintptr(_p0), uintptr(len(b)), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -843,7 +843,7 @@
 func Mlockall(flags int) (err error) {
 	_, _, e1 := Syscall(SYS_MLOCKALL, uintptr(flags), 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -859,7 +859,7 @@
 	}
 	_, _, e1 := Syscall(SYS_MPROTECT, uintptr(_p0), uintptr(len(b)), uintptr(prot))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -875,7 +875,7 @@
 	}
 	_, _, e1 := Syscall(SYS_MUNLOCK, uintptr(_p0), uintptr(len(b)), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -885,7 +885,7 @@
 func Munlockall() (err error) {
 	_, _, e1 := Syscall(SYS_MUNLOCKALL, 0, 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -902,7 +902,7 @@
 	use(unsafe.Pointer(_p0))
 	fd = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -919,7 +919,7 @@
 	use(unsafe.Pointer(_p0))
 	val = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -936,7 +936,7 @@
 	r0, _, e1 := Syscall6(SYS_PREAD, uintptr(fd), uintptr(_p0), uintptr(len(p)), uintptr(offset), 0, 0)
 	n = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -953,7 +953,7 @@
 	r0, _, e1 := Syscall6(SYS_PWRITE, uintptr(fd), uintptr(_p0), uintptr(len(p)), uintptr(offset), 0, 0)
 	n = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -970,7 +970,7 @@
 	r0, _, e1 := Syscall(SYS_READ, uintptr(fd), uintptr(_p0), uintptr(len(p)))
 	n = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -993,7 +993,7 @@
 	use(unsafe.Pointer(_p0))
 	n = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1015,7 +1015,7 @@
 	use(unsafe.Pointer(_p0))
 	use(unsafe.Pointer(_p1))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1031,7 +1031,7 @@
 	_, _, e1 := Syscall(SYS_REVOKE, uintptr(unsafe.Pointer(_p0)), 0, 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1047,7 +1047,7 @@
 	_, _, e1 := Syscall(SYS_RMDIR, uintptr(unsafe.Pointer(_p0)), 0, 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1058,7 +1058,7 @@
 	r0, _, e1 := Syscall(SYS_LSEEK, uintptr(fd), uintptr(offset), uintptr(whence))
 	newoffset = int64(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1068,7 +1068,7 @@
 func Select(n int, r *FdSet, w *FdSet, e *FdSet, timeout *Timeval) (err error) {
 	_, _, e1 := Syscall6(SYS_SELECT, uintptr(n), uintptr(unsafe.Pointer(r)), uintptr(unsafe.Pointer(w)), uintptr(unsafe.Pointer(e)), uintptr(unsafe.Pointer(timeout)), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1078,7 +1078,7 @@
 func Setegid(egid int) (err error) {
 	_, _, e1 := Syscall(SYS_SETEGID, uintptr(egid), 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1088,7 +1088,7 @@
 func Seteuid(euid int) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETEUID, uintptr(euid), 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1098,7 +1098,7 @@
 func Setgid(gid int) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETGID, uintptr(gid), 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1114,7 +1114,7 @@
 	_, _, e1 := Syscall(SYS_SETLOGIN, uintptr(unsafe.Pointer(_p0)), 0, 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1124,7 +1124,7 @@
 func Setpgid(pid int, pgid int) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETPGID, uintptr(pid), uintptr(pgid), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1134,7 +1134,7 @@
 func Setpriority(which int, who int, prio int) (err error) {
 	_, _, e1 := Syscall(SYS_SETPRIORITY, uintptr(which), uintptr(who), uintptr(prio))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1144,7 +1144,7 @@
 func Setprivexec(flag int) (err error) {
 	_, _, e1 := Syscall(SYS_SETPRIVEXEC, uintptr(flag), 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1154,7 +1154,7 @@
 func Setregid(rgid int, egid int) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETREGID, uintptr(rgid), uintptr(egid), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1164,7 +1164,7 @@
 func Setreuid(ruid int, euid int) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETREUID, uintptr(ruid), uintptr(euid), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1174,7 +1174,7 @@
 func Setrlimit(which int, lim *Rlimit) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETRLIMIT, uintptr(which), uintptr(unsafe.Pointer(lim)), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1185,7 +1185,7 @@
 	r0, _, e1 := RawSyscall(SYS_SETSID, 0, 0, 0)
 	pid = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1195,7 +1195,7 @@
 func Settimeofday(tp *Timeval) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETTIMEOFDAY, uintptr(unsafe.Pointer(tp)), 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1205,7 +1205,7 @@
 func Setuid(uid int) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETUID, uintptr(uid), 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1221,7 +1221,7 @@
 	_, _, e1 := Syscall(SYS_STAT64, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1237,7 +1237,7 @@
 	_, _, e1 := Syscall(SYS_STATFS64, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1259,7 +1259,7 @@
 	use(unsafe.Pointer(_p0))
 	use(unsafe.Pointer(_p1))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1269,7 +1269,7 @@
 func Sync() (err error) {
 	_, _, e1 := Syscall(SYS_SYNC, 0, 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1285,7 +1285,7 @@
 	_, _, e1 := Syscall(SYS_TRUNCATE, uintptr(unsafe.Pointer(_p0)), uintptr(length), 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1309,7 +1309,7 @@
 	_, _, e1 := Syscall(SYS_UNDELETE, uintptr(unsafe.Pointer(_p0)), 0, 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1325,7 +1325,7 @@
 	_, _, e1 := Syscall(SYS_UNLINK, uintptr(unsafe.Pointer(_p0)), 0, 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1341,7 +1341,7 @@
 	_, _, e1 := Syscall(SYS_UNMOUNT, uintptr(unsafe.Pointer(_p0)), uintptr(flags), 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1358,7 +1358,7 @@
 	r0, _, e1 := Syscall(SYS_WRITE, uintptr(fd), uintptr(_p0), uintptr(len(p)))
 	n = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1369,7 +1369,7 @@
 	r0, _, e1 := Syscall6(SYS_MMAP, uintptr(addr), uintptr(length), uintptr(prot), uintptr(flag), uintptr(fd), uintptr(pos))
 	ret = uintptr(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1379,7 +1379,7 @@
 func munmap(addr uintptr, length uintptr) (err error) {
 	_, _, e1 := Syscall(SYS_MUNMAP, uintptr(addr), uintptr(length), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1390,7 +1390,7 @@
 	r0, _, e1 := Syscall(SYS_READ, uintptr(fd), uintptr(unsafe.Pointer(buf)), uintptr(nbuf))
 	n = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1401,7 +1401,7 @@
 	r0, _, e1 := Syscall(SYS_WRITE, uintptr(fd), uintptr(unsafe.Pointer(buf)), uintptr(nbuf))
 	n = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1413,7 +1413,7 @@
 	sec = int64(r0)
 	usec = int32(r1)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
diff --git a/src/syscall/zsyscall_darwin_arm.go b/src/syscall/zsyscall_darwin_arm.go
index d851d69..c9426ee 100644
--- a/src/syscall/zsyscall_darwin_arm.go
+++ b/src/syscall/zsyscall_darwin_arm.go
@@ -11,7 +11,7 @@
 	r0, _, e1 := RawSyscall(SYS_GETGROUPS, uintptr(ngid), uintptr(unsafe.Pointer(gid)), 0)
 	n = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -21,7 +21,7 @@
 func setgroups(ngid int, gid *_Gid_t) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETGROUPS, uintptr(ngid), uintptr(unsafe.Pointer(gid)), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -32,7 +32,7 @@
 	r0, _, e1 := Syscall6(SYS_WAIT4, uintptr(pid), uintptr(unsafe.Pointer(wstatus)), uintptr(options), uintptr(unsafe.Pointer(rusage)), 0, 0)
 	wpid = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -43,7 +43,7 @@
 	r0, _, e1 := Syscall(SYS_ACCEPT, uintptr(s), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)))
 	fd = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -53,7 +53,7 @@
 func bind(s int, addr unsafe.Pointer, addrlen _Socklen) (err error) {
 	_, _, e1 := Syscall(SYS_BIND, uintptr(s), uintptr(addr), uintptr(addrlen))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -63,7 +63,7 @@
 func connect(s int, addr unsafe.Pointer, addrlen _Socklen) (err error) {
 	_, _, e1 := Syscall(SYS_CONNECT, uintptr(s), uintptr(addr), uintptr(addrlen))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -74,7 +74,7 @@
 	r0, _, e1 := RawSyscall(SYS_SOCKET, uintptr(domain), uintptr(typ), uintptr(proto))
 	fd = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -84,7 +84,7 @@
 func getsockopt(s int, level int, name int, val unsafe.Pointer, vallen *_Socklen) (err error) {
 	_, _, e1 := Syscall6(SYS_GETSOCKOPT, uintptr(s), uintptr(level), uintptr(name), uintptr(val), uintptr(unsafe.Pointer(vallen)), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -94,7 +94,7 @@
 func setsockopt(s int, level int, name int, val unsafe.Pointer, vallen uintptr) (err error) {
 	_, _, e1 := Syscall6(SYS_SETSOCKOPT, uintptr(s), uintptr(level), uintptr(name), uintptr(val), uintptr(vallen), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -104,7 +104,7 @@
 func getpeername(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (err error) {
 	_, _, e1 := RawSyscall(SYS_GETPEERNAME, uintptr(fd), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -114,7 +114,7 @@
 func getsockname(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (err error) {
 	_, _, e1 := RawSyscall(SYS_GETSOCKNAME, uintptr(fd), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -124,7 +124,7 @@
 func Shutdown(s int, how int) (err error) {
 	_, _, e1 := Syscall(SYS_SHUTDOWN, uintptr(s), uintptr(how), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -134,7 +134,7 @@
 func socketpair(domain int, typ int, proto int, fd *[2]int32) (err error) {
 	_, _, e1 := RawSyscall6(SYS_SOCKETPAIR, uintptr(domain), uintptr(typ), uintptr(proto), uintptr(unsafe.Pointer(fd)), 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -151,7 +151,7 @@
 	r0, _, e1 := Syscall6(SYS_RECVFROM, uintptr(fd), uintptr(_p0), uintptr(len(p)), uintptr(flags), uintptr(unsafe.Pointer(from)), uintptr(unsafe.Pointer(fromlen)))
 	n = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -167,7 +167,7 @@
 	}
 	_, _, e1 := Syscall6(SYS_SENDTO, uintptr(s), uintptr(_p0), uintptr(len(buf)), uintptr(flags), uintptr(to), uintptr(addrlen))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -178,7 +178,7 @@
 	r0, _, e1 := Syscall(SYS_RECVMSG, uintptr(s), uintptr(unsafe.Pointer(msg)), uintptr(flags))
 	n = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -189,7 +189,7 @@
 	r0, _, e1 := Syscall(SYS_SENDMSG, uintptr(s), uintptr(unsafe.Pointer(msg)), uintptr(flags))
 	n = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -200,7 +200,7 @@
 	r0, _, e1 := Syscall6(SYS_KEVENT, uintptr(kq), uintptr(change), uintptr(nchange), uintptr(event), uintptr(nevent), uintptr(unsafe.Pointer(timeout)))
 	n = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -216,7 +216,7 @@
 	}
 	_, _, e1 := Syscall6(SYS___SYSCTL, uintptr(_p0), uintptr(len(mib)), uintptr(unsafe.Pointer(old)), uintptr(unsafe.Pointer(oldlen)), uintptr(unsafe.Pointer(new)), uintptr(newlen))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -230,8 +230,9 @@
 		return
 	}
 	_, _, e1 := Syscall(SYS_UTIMES, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(timeval)), 0)
+	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -241,7 +242,7 @@
 func futimes(fd int, timeval *[2]Timeval) (err error) {
 	_, _, e1 := Syscall(SYS_FUTIMES, uintptr(fd), uintptr(unsafe.Pointer(timeval)), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -252,7 +253,7 @@
 	r0, _, e1 := Syscall(SYS_FCNTL, uintptr(fd), uintptr(cmd), uintptr(arg))
 	val = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -262,7 +263,7 @@
 func ptrace(request int, pid int, addr uintptr, data uintptr) (err error) {
 	_, _, e1 := Syscall6(SYS_PTRACE, uintptr(request), uintptr(pid), uintptr(addr), uintptr(data), 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -274,7 +275,7 @@
 	r = int(r0)
 	w = int(r1)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -284,7 +285,7 @@
 func kill(pid int, signum int, posix int) (err error) {
 	_, _, e1 := Syscall(SYS_KILL, uintptr(pid), uintptr(signum), uintptr(posix))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -298,8 +299,9 @@
 		return
 	}
 	_, _, e1 := Syscall(SYS_ACCESS, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0)
+	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -309,7 +311,7 @@
 func Adjtime(delta *Timeval, olddelta *Timeval) (err error) {
 	_, _, e1 := Syscall(SYS_ADJTIME, uintptr(unsafe.Pointer(delta)), uintptr(unsafe.Pointer(olddelta)), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -323,8 +325,9 @@
 		return
 	}
 	_, _, e1 := Syscall(SYS_CHDIR, uintptr(unsafe.Pointer(_p0)), 0, 0)
+	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -338,8 +341,9 @@
 		return
 	}
 	_, _, e1 := Syscall(SYS_CHFLAGS, uintptr(unsafe.Pointer(_p0)), uintptr(flags), 0)
+	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -353,8 +357,9 @@
 		return
 	}
 	_, _, e1 := Syscall(SYS_CHMOD, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0)
+	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -368,8 +373,9 @@
 		return
 	}
 	_, _, e1 := Syscall(SYS_CHOWN, uintptr(unsafe.Pointer(_p0)), uintptr(uid), uintptr(gid))
+	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -383,8 +389,9 @@
 		return
 	}
 	_, _, e1 := Syscall(SYS_CHROOT, uintptr(unsafe.Pointer(_p0)), 0, 0)
+	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -394,7 +401,7 @@
 func Close(fd int) (err error) {
 	_, _, e1 := Syscall(SYS_CLOSE, uintptr(fd), 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -402,10 +409,10 @@
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
 func Dup(fd int) (nfd int, err error) {
-	r0, _, e1 := RawSyscall(SYS_DUP, uintptr(fd), 0, 0)
+	r0, _, e1 := Syscall(SYS_DUP, uintptr(fd), 0, 0)
 	nfd = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -413,9 +420,9 @@
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
 func Dup2(from int, to int) (err error) {
-	_, _, e1 := RawSyscall(SYS_DUP2, uintptr(from), uintptr(to), 0)
+	_, _, e1 := Syscall(SYS_DUP2, uintptr(from), uintptr(to), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -434,8 +441,10 @@
 		return
 	}
 	_, _, e1 := Syscall(SYS_EXCHANGEDATA, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), uintptr(options))
+	use(unsafe.Pointer(_p0))
+	use(unsafe.Pointer(_p1))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -452,22 +461,17 @@
 func Fchdir(fd int) (err error) {
 	_, _, e1 := Syscall(SYS_FCHDIR, uintptr(fd), 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
-func Fchflags(path string, flags int) (err error) {
-	var _p0 *byte
-	_p0, err = BytePtrFromString(path)
-	if err != nil {
-		return
-	}
-	_, _, e1 := Syscall(SYS_FCHFLAGS, uintptr(unsafe.Pointer(_p0)), uintptr(flags), 0)
+func Fchflags(fd int, flags int) (err error) {
+	_, _, e1 := Syscall(SYS_FCHFLAGS, uintptr(fd), uintptr(flags), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -477,7 +481,7 @@
 func Fchmod(fd int, mode uint32) (err error) {
 	_, _, e1 := Syscall(SYS_FCHMOD, uintptr(fd), uintptr(mode), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -487,7 +491,7 @@
 func Fchown(fd int, uid int, gid int) (err error) {
 	_, _, e1 := Syscall(SYS_FCHOWN, uintptr(fd), uintptr(uid), uintptr(gid))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -497,7 +501,7 @@
 func Flock(fd int, how int) (err error) {
 	_, _, e1 := Syscall(SYS_FLOCK, uintptr(fd), uintptr(how), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -508,7 +512,7 @@
 	r0, _, e1 := Syscall(SYS_FPATHCONF, uintptr(fd), uintptr(name), 0)
 	val = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -518,7 +522,7 @@
 func Fstat(fd int, stat *Stat_t) (err error) {
 	_, _, e1 := Syscall(SYS_FSTAT64, uintptr(fd), uintptr(unsafe.Pointer(stat)), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -528,7 +532,7 @@
 func Fstatfs(fd int, stat *Statfs_t) (err error) {
 	_, _, e1 := Syscall(SYS_FSTATFS64, uintptr(fd), uintptr(unsafe.Pointer(stat)), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -538,7 +542,7 @@
 func Fsync(fd int) (err error) {
 	_, _, e1 := Syscall(SYS_FSYNC, uintptr(fd), 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -548,7 +552,7 @@
 func Ftruncate(fd int, length int64) (err error) {
 	_, _, e1 := Syscall(SYS_FTRUNCATE, uintptr(fd), uintptr(length), uintptr(length>>32))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -565,7 +569,7 @@
 	r0, _, e1 := Syscall6(SYS_GETDIRENTRIES64, uintptr(fd), uintptr(_p0), uintptr(len(buf)), uintptr(unsafe.Pointer(basep)), 0, 0)
 	n = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -608,7 +612,7 @@
 	r0, _, e1 := RawSyscall(SYS_GETPGID, uintptr(pid), 0, 0)
 	pgid = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -643,7 +647,7 @@
 	r0, _, e1 := Syscall(SYS_GETPRIORITY, uintptr(which), uintptr(who), 0)
 	prio = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -653,7 +657,7 @@
 func Getrlimit(which int, lim *Rlimit) (err error) {
 	_, _, e1 := RawSyscall(SYS_GETRLIMIT, uintptr(which), uintptr(unsafe.Pointer(lim)), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -663,7 +667,7 @@
 func Getrusage(who int, rusage *Rusage) (err error) {
 	_, _, e1 := RawSyscall(SYS_GETRUSAGE, uintptr(who), uintptr(unsafe.Pointer(rusage)), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -674,7 +678,7 @@
 	r0, _, e1 := RawSyscall(SYS_GETSID, uintptr(pid), 0, 0)
 	sid = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -701,7 +705,7 @@
 	r0, _, e1 := Syscall(SYS_KQUEUE, 0, 0, 0)
 	fd = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -715,8 +719,9 @@
 		return
 	}
 	_, _, e1 := Syscall(SYS_LCHOWN, uintptr(unsafe.Pointer(_p0)), uintptr(uid), uintptr(gid))
+	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -735,8 +740,10 @@
 		return
 	}
 	_, _, e1 := Syscall(SYS_LINK, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), 0)
+	use(unsafe.Pointer(_p0))
+	use(unsafe.Pointer(_p1))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -746,7 +753,7 @@
 func Listen(s int, backlog int) (err error) {
 	_, _, e1 := Syscall(SYS_LISTEN, uintptr(s), uintptr(backlog), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -760,8 +767,9 @@
 		return
 	}
 	_, _, e1 := Syscall(SYS_LSTAT64, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0)
+	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -775,8 +783,9 @@
 		return
 	}
 	_, _, e1 := Syscall(SYS_MKDIR, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0)
+	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -790,8 +799,9 @@
 		return
 	}
 	_, _, e1 := Syscall(SYS_MKFIFO, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0)
+	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -805,8 +815,77 @@
 		return
 	}
 	_, _, e1 := Syscall(SYS_MKNOD, uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(dev))
+	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Mlock(b []byte) (err error) {
+	var _p0 unsafe.Pointer
+	if len(b) > 0 {
+		_p0 = unsafe.Pointer(&b[0])
+	} else {
+		_p0 = unsafe.Pointer(&_zero)
+	}
+	_, _, e1 := Syscall(SYS_MLOCK, uintptr(_p0), uintptr(len(b)), 0)
+	if e1 != 0 {
+		err = errnoErr(e1)
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Mlockall(flags int) (err error) {
+	_, _, e1 := Syscall(SYS_MLOCKALL, uintptr(flags), 0, 0)
+	if e1 != 0 {
+		err = errnoErr(e1)
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Mprotect(b []byte, prot int) (err error) {
+	var _p0 unsafe.Pointer
+	if len(b) > 0 {
+		_p0 = unsafe.Pointer(&b[0])
+	} else {
+		_p0 = unsafe.Pointer(&_zero)
+	}
+	_, _, e1 := Syscall(SYS_MPROTECT, uintptr(_p0), uintptr(len(b)), uintptr(prot))
+	if e1 != 0 {
+		err = errnoErr(e1)
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Munlock(b []byte) (err error) {
+	var _p0 unsafe.Pointer
+	if len(b) > 0 {
+		_p0 = unsafe.Pointer(&b[0])
+	} else {
+		_p0 = unsafe.Pointer(&_zero)
+	}
+	_, _, e1 := Syscall(SYS_MUNLOCK, uintptr(_p0), uintptr(len(b)), 0)
+	if e1 != 0 {
+		err = errnoErr(e1)
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Munlockall() (err error) {
+	_, _, e1 := Syscall(SYS_MUNLOCKALL, 0, 0, 0)
+	if e1 != 0 {
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -820,9 +899,10 @@
 		return
 	}
 	r0, _, e1 := Syscall(SYS_OPEN, uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(perm))
+	use(unsafe.Pointer(_p0))
 	fd = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -836,9 +916,10 @@
 		return
 	}
 	r0, _, e1 := Syscall(SYS_PATHCONF, uintptr(unsafe.Pointer(_p0)), uintptr(name), 0)
+	use(unsafe.Pointer(_p0))
 	val = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -855,7 +936,7 @@
 	r0, _, e1 := Syscall6(SYS_PREAD, uintptr(fd), uintptr(_p0), uintptr(len(p)), uintptr(offset), uintptr(offset>>32), 0)
 	n = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -872,7 +953,7 @@
 	r0, _, e1 := Syscall6(SYS_PWRITE, uintptr(fd), uintptr(_p0), uintptr(len(p)), uintptr(offset), uintptr(offset>>32), 0)
 	n = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -889,7 +970,7 @@
 	r0, _, e1 := Syscall(SYS_READ, uintptr(fd), uintptr(_p0), uintptr(len(p)))
 	n = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -909,9 +990,10 @@
 		_p1 = unsafe.Pointer(&_zero)
 	}
 	r0, _, e1 := Syscall(SYS_READLINK, uintptr(unsafe.Pointer(_p0)), uintptr(_p1), uintptr(len(buf)))
+	use(unsafe.Pointer(_p0))
 	n = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -930,8 +1012,10 @@
 		return
 	}
 	_, _, e1 := Syscall(SYS_RENAME, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), 0)
+	use(unsafe.Pointer(_p0))
+	use(unsafe.Pointer(_p1))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -945,8 +1029,9 @@
 		return
 	}
 	_, _, e1 := Syscall(SYS_REVOKE, uintptr(unsafe.Pointer(_p0)), 0, 0)
+	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -960,8 +1045,9 @@
 		return
 	}
 	_, _, e1 := Syscall(SYS_RMDIR, uintptr(unsafe.Pointer(_p0)), 0, 0)
+	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -972,7 +1058,7 @@
 	r0, r1, e1 := Syscall6(SYS_LSEEK, uintptr(fd), uintptr(offset), uintptr(offset>>32), uintptr(whence), 0, 0)
 	newoffset = int64(int64(r1)<<32 | int64(r0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -982,7 +1068,7 @@
 func Select(n int, r *FdSet, w *FdSet, e *FdSet, timeout *Timeval) (err error) {
 	_, _, e1 := Syscall6(SYS_SELECT, uintptr(n), uintptr(unsafe.Pointer(r)), uintptr(unsafe.Pointer(w)), uintptr(unsafe.Pointer(e)), uintptr(unsafe.Pointer(timeout)), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -992,7 +1078,7 @@
 func Setegid(egid int) (err error) {
 	_, _, e1 := Syscall(SYS_SETEGID, uintptr(egid), 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1002,7 +1088,7 @@
 func Seteuid(euid int) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETEUID, uintptr(euid), 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1012,7 +1098,7 @@
 func Setgid(gid int) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETGID, uintptr(gid), 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1026,8 +1112,9 @@
 		return
 	}
 	_, _, e1 := Syscall(SYS_SETLOGIN, uintptr(unsafe.Pointer(_p0)), 0, 0)
+	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1037,7 +1124,7 @@
 func Setpgid(pid int, pgid int) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETPGID, uintptr(pid), uintptr(pgid), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1047,7 +1134,7 @@
 func Setpriority(which int, who int, prio int) (err error) {
 	_, _, e1 := Syscall(SYS_SETPRIORITY, uintptr(which), uintptr(who), uintptr(prio))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1057,7 +1144,7 @@
 func Setprivexec(flag int) (err error) {
 	_, _, e1 := Syscall(SYS_SETPRIVEXEC, uintptr(flag), 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1067,7 +1154,7 @@
 func Setregid(rgid int, egid int) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETREGID, uintptr(rgid), uintptr(egid), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1077,7 +1164,7 @@
 func Setreuid(ruid int, euid int) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETREUID, uintptr(ruid), uintptr(euid), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1087,7 +1174,7 @@
 func Setrlimit(which int, lim *Rlimit) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETRLIMIT, uintptr(which), uintptr(unsafe.Pointer(lim)), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1098,7 +1185,7 @@
 	r0, _, e1 := RawSyscall(SYS_SETSID, 0, 0, 0)
 	pid = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1108,7 +1195,7 @@
 func Settimeofday(tp *Timeval) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETTIMEOFDAY, uintptr(unsafe.Pointer(tp)), 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1118,7 +1205,7 @@
 func Setuid(uid int) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETUID, uintptr(uid), 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1132,8 +1219,9 @@
 		return
 	}
 	_, _, e1 := Syscall(SYS_STAT64, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0)
+	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1147,8 +1235,9 @@
 		return
 	}
 	_, _, e1 := Syscall(SYS_STATFS64, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0)
+	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1167,8 +1256,10 @@
 		return
 	}
 	_, _, e1 := Syscall(SYS_SYMLINK, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), 0)
+	use(unsafe.Pointer(_p0))
+	use(unsafe.Pointer(_p1))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1178,7 +1269,7 @@
 func Sync() (err error) {
 	_, _, e1 := Syscall(SYS_SYNC, 0, 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1192,8 +1283,9 @@
 		return
 	}
 	_, _, e1 := Syscall(SYS_TRUNCATE, uintptr(unsafe.Pointer(_p0)), uintptr(length), uintptr(length>>32))
+	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1215,8 +1307,9 @@
 		return
 	}
 	_, _, e1 := Syscall(SYS_UNDELETE, uintptr(unsafe.Pointer(_p0)), 0, 0)
+	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1230,8 +1323,9 @@
 		return
 	}
 	_, _, e1 := Syscall(SYS_UNLINK, uintptr(unsafe.Pointer(_p0)), 0, 0)
+	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1245,8 +1339,9 @@
 		return
 	}
 	_, _, e1 := Syscall(SYS_UNMOUNT, uintptr(unsafe.Pointer(_p0)), uintptr(flags), 0)
+	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1263,7 +1358,7 @@
 	r0, _, e1 := Syscall(SYS_WRITE, uintptr(fd), uintptr(_p0), uintptr(len(p)))
 	n = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1274,7 +1369,7 @@
 	r0, _, e1 := Syscall9(SYS_MMAP, uintptr(addr), uintptr(length), uintptr(prot), uintptr(flag), uintptr(fd), uintptr(pos), uintptr(pos>>32), 0, 0)
 	ret = uintptr(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1284,7 +1379,7 @@
 func munmap(addr uintptr, length uintptr) (err error) {
 	_, _, e1 := Syscall(SYS_MUNMAP, uintptr(addr), uintptr(length), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1295,7 +1390,7 @@
 	r0, _, e1 := Syscall(SYS_READ, uintptr(fd), uintptr(unsafe.Pointer(buf)), uintptr(nbuf))
 	n = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1306,7 +1401,7 @@
 	r0, _, e1 := Syscall(SYS_WRITE, uintptr(fd), uintptr(unsafe.Pointer(buf)), uintptr(nbuf))
 	n = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1318,7 +1413,7 @@
 	sec = int32(r0)
 	usec = int32(r1)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
diff --git a/src/syscall/zsyscall_dragonfly_amd64.go b/src/syscall/zsyscall_dragonfly_amd64.go
index 0121374..5eef138 100644
--- a/src/syscall/zsyscall_dragonfly_amd64.go
+++ b/src/syscall/zsyscall_dragonfly_amd64.go
@@ -11,7 +11,7 @@
 	r0, _, e1 := RawSyscall(SYS_GETGROUPS, uintptr(ngid), uintptr(unsafe.Pointer(gid)), 0)
 	n = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -21,7 +21,7 @@
 func setgroups(ngid int, gid *_Gid_t) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETGROUPS, uintptr(ngid), uintptr(unsafe.Pointer(gid)), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -32,7 +32,7 @@
 	r0, _, e1 := Syscall6(SYS_WAIT4, uintptr(pid), uintptr(unsafe.Pointer(wstatus)), uintptr(options), uintptr(unsafe.Pointer(rusage)), 0, 0)
 	wpid = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -43,7 +43,7 @@
 	r0, _, e1 := Syscall(SYS_ACCEPT, uintptr(s), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)))
 	fd = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -53,7 +53,7 @@
 func bind(s int, addr unsafe.Pointer, addrlen _Socklen) (err error) {
 	_, _, e1 := Syscall(SYS_BIND, uintptr(s), uintptr(addr), uintptr(addrlen))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -63,7 +63,7 @@
 func connect(s int, addr unsafe.Pointer, addrlen _Socklen) (err error) {
 	_, _, e1 := Syscall(SYS_CONNECT, uintptr(s), uintptr(addr), uintptr(addrlen))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -74,7 +74,7 @@
 	r0, _, e1 := RawSyscall(SYS_SOCKET, uintptr(domain), uintptr(typ), uintptr(proto))
 	fd = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -84,7 +84,7 @@
 func getsockopt(s int, level int, name int, val unsafe.Pointer, vallen *_Socklen) (err error) {
 	_, _, e1 := Syscall6(SYS_GETSOCKOPT, uintptr(s), uintptr(level), uintptr(name), uintptr(val), uintptr(unsafe.Pointer(vallen)), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -94,7 +94,7 @@
 func setsockopt(s int, level int, name int, val unsafe.Pointer, vallen uintptr) (err error) {
 	_, _, e1 := Syscall6(SYS_SETSOCKOPT, uintptr(s), uintptr(level), uintptr(name), uintptr(val), uintptr(vallen), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -104,7 +104,7 @@
 func getpeername(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (err error) {
 	_, _, e1 := RawSyscall(SYS_GETPEERNAME, uintptr(fd), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -114,7 +114,7 @@
 func getsockname(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (err error) {
 	_, _, e1 := RawSyscall(SYS_GETSOCKNAME, uintptr(fd), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -124,7 +124,7 @@
 func Shutdown(s int, how int) (err error) {
 	_, _, e1 := Syscall(SYS_SHUTDOWN, uintptr(s), uintptr(how), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -134,7 +134,7 @@
 func socketpair(domain int, typ int, proto int, fd *[2]int32) (err error) {
 	_, _, e1 := RawSyscall6(SYS_SOCKETPAIR, uintptr(domain), uintptr(typ), uintptr(proto), uintptr(unsafe.Pointer(fd)), 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -151,7 +151,7 @@
 	r0, _, e1 := Syscall6(SYS_RECVFROM, uintptr(fd), uintptr(_p0), uintptr(len(p)), uintptr(flags), uintptr(unsafe.Pointer(from)), uintptr(unsafe.Pointer(fromlen)))
 	n = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -167,7 +167,7 @@
 	}
 	_, _, e1 := Syscall6(SYS_SENDTO, uintptr(s), uintptr(_p0), uintptr(len(buf)), uintptr(flags), uintptr(to), uintptr(addrlen))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -178,7 +178,7 @@
 	r0, _, e1 := Syscall(SYS_RECVMSG, uintptr(s), uintptr(unsafe.Pointer(msg)), uintptr(flags))
 	n = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -189,7 +189,7 @@
 	r0, _, e1 := Syscall(SYS_SENDMSG, uintptr(s), uintptr(unsafe.Pointer(msg)), uintptr(flags))
 	n = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -200,7 +200,7 @@
 	r0, _, e1 := Syscall6(SYS_KEVENT, uintptr(kq), uintptr(change), uintptr(nchange), uintptr(event), uintptr(nevent), uintptr(unsafe.Pointer(timeout)))
 	n = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -216,7 +216,7 @@
 	}
 	_, _, e1 := Syscall6(SYS___SYSCTL, uintptr(_p0), uintptr(len(mib)), uintptr(unsafe.Pointer(old)), uintptr(unsafe.Pointer(oldlen)), uintptr(unsafe.Pointer(new)), uintptr(newlen))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -232,7 +232,7 @@
 	_, _, e1 := Syscall(SYS_UTIMES, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(timeval)), 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -242,7 +242,7 @@
 func futimes(fd int, timeval *[2]Timeval) (err error) {
 	_, _, e1 := Syscall(SYS_FUTIMES, uintptr(fd), uintptr(unsafe.Pointer(timeval)), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -253,7 +253,7 @@
 	r0, _, e1 := Syscall(SYS_FCNTL, uintptr(fd), uintptr(cmd), uintptr(arg))
 	val = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -265,7 +265,7 @@
 	r = int(r0)
 	w = int(r1)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -282,7 +282,7 @@
 	r0, _, e1 := Syscall6(SYS_EXTPREAD, uintptr(fd), uintptr(_p0), uintptr(len(p)), uintptr(flags), uintptr(offset), 0)
 	n = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -299,7 +299,7 @@
 	r0, _, e1 := Syscall6(SYS_EXTPWRITE, uintptr(fd), uintptr(_p0), uintptr(len(p)), uintptr(flags), uintptr(offset), 0)
 	n = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -315,7 +315,7 @@
 	_, _, e1 := Syscall(SYS_ACCESS, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -325,7 +325,7 @@
 func Adjtime(delta *Timeval, olddelta *Timeval) (err error) {
 	_, _, e1 := Syscall(SYS_ADJTIME, uintptr(unsafe.Pointer(delta)), uintptr(unsafe.Pointer(olddelta)), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -341,7 +341,7 @@
 	_, _, e1 := Syscall(SYS_CHDIR, uintptr(unsafe.Pointer(_p0)), 0, 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -357,7 +357,7 @@
 	_, _, e1 := Syscall(SYS_CHFLAGS, uintptr(unsafe.Pointer(_p0)), uintptr(flags), 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -373,7 +373,7 @@
 	_, _, e1 := Syscall(SYS_CHMOD, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -389,7 +389,7 @@
 	_, _, e1 := Syscall(SYS_CHOWN, uintptr(unsafe.Pointer(_p0)), uintptr(uid), uintptr(gid))
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -405,7 +405,7 @@
 	_, _, e1 := Syscall(SYS_CHROOT, uintptr(unsafe.Pointer(_p0)), 0, 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -415,7 +415,7 @@
 func Close(fd int) (err error) {
 	_, _, e1 := Syscall(SYS_CLOSE, uintptr(fd), 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -423,10 +423,10 @@
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
 func Dup(fd int) (nfd int, err error) {
-	r0, _, e1 := RawSyscall(SYS_DUP, uintptr(fd), 0, 0)
+	r0, _, e1 := Syscall(SYS_DUP, uintptr(fd), 0, 0)
 	nfd = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -434,9 +434,9 @@
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
 func Dup2(from int, to int) (err error) {
-	_, _, e1 := RawSyscall(SYS_DUP2, uintptr(from), uintptr(to), 0)
+	_, _, e1 := Syscall(SYS_DUP2, uintptr(from), uintptr(to), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -453,7 +453,7 @@
 func Fchdir(fd int) (err error) {
 	_, _, e1 := Syscall(SYS_FCHDIR, uintptr(fd), 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -463,7 +463,7 @@
 func Fchflags(fd int, flags int) (err error) {
 	_, _, e1 := Syscall(SYS_FCHFLAGS, uintptr(fd), uintptr(flags), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -473,7 +473,7 @@
 func Fchmod(fd int, mode uint32) (err error) {
 	_, _, e1 := Syscall(SYS_FCHMOD, uintptr(fd), uintptr(mode), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -483,7 +483,7 @@
 func Fchown(fd int, uid int, gid int) (err error) {
 	_, _, e1 := Syscall(SYS_FCHOWN, uintptr(fd), uintptr(uid), uintptr(gid))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -493,7 +493,7 @@
 func Flock(fd int, how int) (err error) {
 	_, _, e1 := Syscall(SYS_FLOCK, uintptr(fd), uintptr(how), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -504,7 +504,7 @@
 	r0, _, e1 := Syscall(SYS_FPATHCONF, uintptr(fd), uintptr(name), 0)
 	val = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -514,7 +514,7 @@
 func Fstat(fd int, stat *Stat_t) (err error) {
 	_, _, e1 := Syscall(SYS_FSTAT, uintptr(fd), uintptr(unsafe.Pointer(stat)), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -524,7 +524,7 @@
 func Fstatfs(fd int, stat *Statfs_t) (err error) {
 	_, _, e1 := Syscall(SYS_FSTATFS, uintptr(fd), uintptr(unsafe.Pointer(stat)), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -534,7 +534,7 @@
 func Fsync(fd int) (err error) {
 	_, _, e1 := Syscall(SYS_FSYNC, uintptr(fd), 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -544,7 +544,7 @@
 func Ftruncate(fd int, length int64) (err error) {
 	_, _, e1 := Syscall(SYS_FTRUNCATE, uintptr(fd), 0, uintptr(length))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -561,7 +561,7 @@
 	r0, _, e1 := Syscall6(SYS_GETDIRENTRIES, uintptr(fd), uintptr(_p0), uintptr(len(buf)), uintptr(unsafe.Pointer(basep)), 0, 0)
 	n = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -604,7 +604,7 @@
 	r0, _, e1 := RawSyscall(SYS_GETPGID, uintptr(pid), 0, 0)
 	pgid = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -639,7 +639,7 @@
 	r0, _, e1 := Syscall(SYS_GETPRIORITY, uintptr(which), uintptr(who), 0)
 	prio = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -649,7 +649,7 @@
 func Getrlimit(which int, lim *Rlimit) (err error) {
 	_, _, e1 := RawSyscall(SYS_GETRLIMIT, uintptr(which), uintptr(unsafe.Pointer(lim)), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -659,7 +659,7 @@
 func Getrusage(who int, rusage *Rusage) (err error) {
 	_, _, e1 := RawSyscall(SYS_GETRUSAGE, uintptr(who), uintptr(unsafe.Pointer(rusage)), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -670,7 +670,7 @@
 	r0, _, e1 := RawSyscall(SYS_GETSID, uintptr(pid), 0, 0)
 	sid = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -680,7 +680,7 @@
 func Gettimeofday(tv *Timeval) (err error) {
 	_, _, e1 := RawSyscall(SYS_GETTIMEOFDAY, uintptr(unsafe.Pointer(tv)), 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -706,7 +706,7 @@
 func Kill(pid int, signum Signal) (err error) {
 	_, _, e1 := Syscall(SYS_KILL, uintptr(pid), uintptr(signum), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -717,7 +717,7 @@
 	r0, _, e1 := Syscall(SYS_KQUEUE, 0, 0, 0)
 	fd = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -733,7 +733,7 @@
 	_, _, e1 := Syscall(SYS_LCHOWN, uintptr(unsafe.Pointer(_p0)), uintptr(uid), uintptr(gid))
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -755,7 +755,7 @@
 	use(unsafe.Pointer(_p0))
 	use(unsafe.Pointer(_p1))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -765,7 +765,7 @@
 func Listen(s int, backlog int) (err error) {
 	_, _, e1 := Syscall(SYS_LISTEN, uintptr(s), uintptr(backlog), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -781,7 +781,7 @@
 	_, _, e1 := Syscall(SYS_LSTAT, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -797,7 +797,7 @@
 	_, _, e1 := Syscall(SYS_MKDIR, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -813,7 +813,7 @@
 	_, _, e1 := Syscall(SYS_MKFIFO, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -829,7 +829,7 @@
 	_, _, e1 := Syscall(SYS_MKNOD, uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(dev))
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -839,7 +839,7 @@
 func Nanosleep(time *Timespec, leftover *Timespec) (err error) {
 	_, _, e1 := Syscall(SYS_NANOSLEEP, uintptr(unsafe.Pointer(time)), uintptr(unsafe.Pointer(leftover)), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -856,7 +856,7 @@
 	use(unsafe.Pointer(_p0))
 	fd = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -873,7 +873,7 @@
 	use(unsafe.Pointer(_p0))
 	val = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -890,7 +890,7 @@
 	r0, _, e1 := Syscall(SYS_READ, uintptr(fd), uintptr(_p0), uintptr(len(p)))
 	n = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -913,7 +913,7 @@
 	use(unsafe.Pointer(_p0))
 	n = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -935,7 +935,7 @@
 	use(unsafe.Pointer(_p0))
 	use(unsafe.Pointer(_p1))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -951,7 +951,7 @@
 	_, _, e1 := Syscall(SYS_REVOKE, uintptr(unsafe.Pointer(_p0)), 0, 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -967,7 +967,7 @@
 	_, _, e1 := Syscall(SYS_RMDIR, uintptr(unsafe.Pointer(_p0)), 0, 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -978,7 +978,7 @@
 	r0, _, e1 := Syscall6(SYS_LSEEK, uintptr(fd), 0, uintptr(offset), uintptr(whence), 0, 0)
 	newoffset = int64(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -988,7 +988,7 @@
 func Select(n int, r *FdSet, w *FdSet, e *FdSet, timeout *Timeval) (err error) {
 	_, _, e1 := Syscall6(SYS_SELECT, uintptr(n), uintptr(unsafe.Pointer(r)), uintptr(unsafe.Pointer(w)), uintptr(unsafe.Pointer(e)), uintptr(unsafe.Pointer(timeout)), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -998,7 +998,7 @@
 func Setegid(egid int) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETEGID, uintptr(egid), 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1008,7 +1008,7 @@
 func Seteuid(euid int) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETEUID, uintptr(euid), 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1018,7 +1018,7 @@
 func Setgid(gid int) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETGID, uintptr(gid), 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1034,7 +1034,7 @@
 	_, _, e1 := Syscall(SYS_SETLOGIN, uintptr(unsafe.Pointer(_p0)), 0, 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1044,7 +1044,7 @@
 func Setpgid(pid int, pgid int) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETPGID, uintptr(pid), uintptr(pgid), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1054,7 +1054,7 @@
 func Setpriority(which int, who int, prio int) (err error) {
 	_, _, e1 := Syscall(SYS_SETPRIORITY, uintptr(which), uintptr(who), uintptr(prio))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1064,7 +1064,7 @@
 func Setregid(rgid int, egid int) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETREGID, uintptr(rgid), uintptr(egid), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1074,7 +1074,7 @@
 func Setreuid(ruid int, euid int) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETREUID, uintptr(ruid), uintptr(euid), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1084,7 +1084,7 @@
 func Setrlimit(which int, lim *Rlimit) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETRLIMIT, uintptr(which), uintptr(unsafe.Pointer(lim)), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1095,7 +1095,7 @@
 	r0, _, e1 := RawSyscall(SYS_SETSID, 0, 0, 0)
 	pid = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1105,7 +1105,7 @@
 func Settimeofday(tp *Timeval) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETTIMEOFDAY, uintptr(unsafe.Pointer(tp)), 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1115,7 +1115,7 @@
 func Setuid(uid int) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETUID, uintptr(uid), 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1131,7 +1131,7 @@
 	_, _, e1 := Syscall(SYS_STAT, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1147,7 +1147,7 @@
 	_, _, e1 := Syscall(SYS_STATFS, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1169,7 +1169,7 @@
 	use(unsafe.Pointer(_p0))
 	use(unsafe.Pointer(_p1))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1179,7 +1179,7 @@
 func Sync() (err error) {
 	_, _, e1 := Syscall(SYS_SYNC, 0, 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1195,7 +1195,7 @@
 	_, _, e1 := Syscall(SYS_TRUNCATE, uintptr(unsafe.Pointer(_p0)), 0, uintptr(length))
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1219,7 +1219,7 @@
 	_, _, e1 := Syscall(SYS_UNDELETE, uintptr(unsafe.Pointer(_p0)), 0, 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1235,7 +1235,7 @@
 	_, _, e1 := Syscall(SYS_UNLINK, uintptr(unsafe.Pointer(_p0)), 0, 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1251,7 +1251,7 @@
 	_, _, e1 := Syscall(SYS_UNMOUNT, uintptr(unsafe.Pointer(_p0)), uintptr(flags), 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1268,7 +1268,7 @@
 	r0, _, e1 := Syscall(SYS_WRITE, uintptr(fd), uintptr(_p0), uintptr(len(p)))
 	n = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1279,7 +1279,7 @@
 	r0, _, e1 := Syscall9(SYS_MMAP, uintptr(addr), uintptr(length), uintptr(prot), uintptr(flag), uintptr(fd), 0, uintptr(pos), 0, 0)
 	ret = uintptr(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1289,7 +1289,7 @@
 func munmap(addr uintptr, length uintptr) (err error) {
 	_, _, e1 := Syscall(SYS_MUNMAP, uintptr(addr), uintptr(length), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1300,7 +1300,7 @@
 	r0, _, e1 := Syscall(SYS_READ, uintptr(fd), uintptr(unsafe.Pointer(buf)), uintptr(nbuf))
 	n = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1311,7 +1311,7 @@
 	r0, _, e1 := Syscall(SYS_WRITE, uintptr(fd), uintptr(unsafe.Pointer(buf)), uintptr(nbuf))
 	n = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
diff --git a/src/syscall/zsyscall_freebsd_386.go b/src/syscall/zsyscall_freebsd_386.go
index c8c636f..7cb21c9 100644
--- a/src/syscall/zsyscall_freebsd_386.go
+++ b/src/syscall/zsyscall_freebsd_386.go
@@ -11,7 +11,7 @@
 	r0, _, e1 := RawSyscall(SYS_GETGROUPS, uintptr(ngid), uintptr(unsafe.Pointer(gid)), 0)
 	n = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -21,7 +21,7 @@
 func setgroups(ngid int, gid *_Gid_t) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETGROUPS, uintptr(ngid), uintptr(unsafe.Pointer(gid)), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -32,7 +32,7 @@
 	r0, _, e1 := Syscall6(SYS_WAIT4, uintptr(pid), uintptr(unsafe.Pointer(wstatus)), uintptr(options), uintptr(unsafe.Pointer(rusage)), 0, 0)
 	wpid = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -43,7 +43,7 @@
 	r0, _, e1 := Syscall(SYS_ACCEPT, uintptr(s), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)))
 	fd = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -53,7 +53,7 @@
 func bind(s int, addr unsafe.Pointer, addrlen _Socklen) (err error) {
 	_, _, e1 := Syscall(SYS_BIND, uintptr(s), uintptr(addr), uintptr(addrlen))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -63,7 +63,7 @@
 func connect(s int, addr unsafe.Pointer, addrlen _Socklen) (err error) {
 	_, _, e1 := Syscall(SYS_CONNECT, uintptr(s), uintptr(addr), uintptr(addrlen))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -74,7 +74,7 @@
 	r0, _, e1 := RawSyscall(SYS_SOCKET, uintptr(domain), uintptr(typ), uintptr(proto))
 	fd = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -84,7 +84,7 @@
 func getsockopt(s int, level int, name int, val unsafe.Pointer, vallen *_Socklen) (err error) {
 	_, _, e1 := Syscall6(SYS_GETSOCKOPT, uintptr(s), uintptr(level), uintptr(name), uintptr(val), uintptr(unsafe.Pointer(vallen)), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -94,7 +94,7 @@
 func setsockopt(s int, level int, name int, val unsafe.Pointer, vallen uintptr) (err error) {
 	_, _, e1 := Syscall6(SYS_SETSOCKOPT, uintptr(s), uintptr(level), uintptr(name), uintptr(val), uintptr(vallen), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -104,7 +104,7 @@
 func getpeername(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (err error) {
 	_, _, e1 := RawSyscall(SYS_GETPEERNAME, uintptr(fd), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -114,7 +114,7 @@
 func getsockname(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (err error) {
 	_, _, e1 := RawSyscall(SYS_GETSOCKNAME, uintptr(fd), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -124,7 +124,7 @@
 func Shutdown(s int, how int) (err error) {
 	_, _, e1 := Syscall(SYS_SHUTDOWN, uintptr(s), uintptr(how), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -134,7 +134,7 @@
 func socketpair(domain int, typ int, proto int, fd *[2]int32) (err error) {
 	_, _, e1 := RawSyscall6(SYS_SOCKETPAIR, uintptr(domain), uintptr(typ), uintptr(proto), uintptr(unsafe.Pointer(fd)), 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -151,7 +151,7 @@
 	r0, _, e1 := Syscall6(SYS_RECVFROM, uintptr(fd), uintptr(_p0), uintptr(len(p)), uintptr(flags), uintptr(unsafe.Pointer(from)), uintptr(unsafe.Pointer(fromlen)))
 	n = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -167,7 +167,7 @@
 	}
 	_, _, e1 := Syscall6(SYS_SENDTO, uintptr(s), uintptr(_p0), uintptr(len(buf)), uintptr(flags), uintptr(to), uintptr(addrlen))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -178,7 +178,7 @@
 	r0, _, e1 := Syscall(SYS_RECVMSG, uintptr(s), uintptr(unsafe.Pointer(msg)), uintptr(flags))
 	n = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -189,7 +189,7 @@
 	r0, _, e1 := Syscall(SYS_SENDMSG, uintptr(s), uintptr(unsafe.Pointer(msg)), uintptr(flags))
 	n = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -200,7 +200,7 @@
 	r0, _, e1 := Syscall6(SYS_KEVENT, uintptr(kq), uintptr(change), uintptr(nchange), uintptr(event), uintptr(nevent), uintptr(unsafe.Pointer(timeout)))
 	n = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -216,7 +216,7 @@
 	}
 	_, _, e1 := Syscall6(SYS___SYSCTL, uintptr(_p0), uintptr(len(mib)), uintptr(unsafe.Pointer(old)), uintptr(unsafe.Pointer(oldlen)), uintptr(unsafe.Pointer(new)), uintptr(newlen))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -232,7 +232,7 @@
 	_, _, e1 := Syscall(SYS_UTIMES, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(timeval)), 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -242,7 +242,7 @@
 func futimes(fd int, timeval *[2]Timeval) (err error) {
 	_, _, e1 := Syscall(SYS_FUTIMES, uintptr(fd), uintptr(unsafe.Pointer(timeval)), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -253,7 +253,7 @@
 	r0, _, e1 := Syscall(SYS_FCNTL, uintptr(fd), uintptr(cmd), uintptr(arg))
 	val = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -265,7 +265,7 @@
 	r = int(r0)
 	w = int(r1)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -281,7 +281,7 @@
 	_, _, e1 := Syscall(SYS_ACCESS, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -291,7 +291,7 @@
 func Adjtime(delta *Timeval, olddelta *Timeval) (err error) {
 	_, _, e1 := Syscall(SYS_ADJTIME, uintptr(unsafe.Pointer(delta)), uintptr(unsafe.Pointer(olddelta)), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -307,7 +307,7 @@
 	_, _, e1 := Syscall(SYS_CHDIR, uintptr(unsafe.Pointer(_p0)), 0, 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -323,7 +323,7 @@
 	_, _, e1 := Syscall(SYS_CHFLAGS, uintptr(unsafe.Pointer(_p0)), uintptr(flags), 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -339,7 +339,7 @@
 	_, _, e1 := Syscall(SYS_CHMOD, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -355,7 +355,7 @@
 	_, _, e1 := Syscall(SYS_CHOWN, uintptr(unsafe.Pointer(_p0)), uintptr(uid), uintptr(gid))
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -371,7 +371,7 @@
 	_, _, e1 := Syscall(SYS_CHROOT, uintptr(unsafe.Pointer(_p0)), 0, 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -381,7 +381,7 @@
 func Close(fd int) (err error) {
 	_, _, e1 := Syscall(SYS_CLOSE, uintptr(fd), 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -389,10 +389,10 @@
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
 func Dup(fd int) (nfd int, err error) {
-	r0, _, e1 := RawSyscall(SYS_DUP, uintptr(fd), 0, 0)
+	r0, _, e1 := Syscall(SYS_DUP, uintptr(fd), 0, 0)
 	nfd = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -400,9 +400,9 @@
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
 func Dup2(from int, to int) (err error) {
-	_, _, e1 := RawSyscall(SYS_DUP2, uintptr(from), uintptr(to), 0)
+	_, _, e1 := Syscall(SYS_DUP2, uintptr(from), uintptr(to), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -419,7 +419,7 @@
 func Fchdir(fd int) (err error) {
 	_, _, e1 := Syscall(SYS_FCHDIR, uintptr(fd), 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -429,7 +429,7 @@
 func Fchflags(fd int, flags int) (err error) {
 	_, _, e1 := Syscall(SYS_FCHFLAGS, uintptr(fd), uintptr(flags), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -439,7 +439,7 @@
 func Fchmod(fd int, mode uint32) (err error) {
 	_, _, e1 := Syscall(SYS_FCHMOD, uintptr(fd), uintptr(mode), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -449,7 +449,7 @@
 func Fchown(fd int, uid int, gid int) (err error) {
 	_, _, e1 := Syscall(SYS_FCHOWN, uintptr(fd), uintptr(uid), uintptr(gid))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -459,7 +459,7 @@
 func Flock(fd int, how int) (err error) {
 	_, _, e1 := Syscall(SYS_FLOCK, uintptr(fd), uintptr(how), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -470,7 +470,7 @@
 	r0, _, e1 := Syscall(SYS_FPATHCONF, uintptr(fd), uintptr(name), 0)
 	val = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -480,7 +480,7 @@
 func Fstat(fd int, stat *Stat_t) (err error) {
 	_, _, e1 := Syscall(SYS_FSTAT, uintptr(fd), uintptr(unsafe.Pointer(stat)), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -490,7 +490,7 @@
 func Fstatfs(fd int, stat *Statfs_t) (err error) {
 	_, _, e1 := Syscall(SYS_FSTATFS, uintptr(fd), uintptr(unsafe.Pointer(stat)), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -500,7 +500,7 @@
 func Fsync(fd int) (err error) {
 	_, _, e1 := Syscall(SYS_FSYNC, uintptr(fd), 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -510,7 +510,7 @@
 func Ftruncate(fd int, length int64) (err error) {
 	_, _, e1 := Syscall(SYS_FTRUNCATE, uintptr(fd), uintptr(length), uintptr(length>>32))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -527,7 +527,7 @@
 	r0, _, e1 := Syscall6(SYS_GETDIRENTRIES, uintptr(fd), uintptr(_p0), uintptr(len(buf)), uintptr(unsafe.Pointer(basep)), 0, 0)
 	n = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -570,7 +570,7 @@
 	r0, _, e1 := RawSyscall(SYS_GETPGID, uintptr(pid), 0, 0)
 	pgid = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -605,7 +605,7 @@
 	r0, _, e1 := Syscall(SYS_GETPRIORITY, uintptr(which), uintptr(who), 0)
 	prio = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -615,7 +615,7 @@
 func Getrlimit(which int, lim *Rlimit) (err error) {
 	_, _, e1 := RawSyscall(SYS_GETRLIMIT, uintptr(which), uintptr(unsafe.Pointer(lim)), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -625,7 +625,7 @@
 func Getrusage(who int, rusage *Rusage) (err error) {
 	_, _, e1 := RawSyscall(SYS_GETRUSAGE, uintptr(who), uintptr(unsafe.Pointer(rusage)), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -636,7 +636,7 @@
 	r0, _, e1 := RawSyscall(SYS_GETSID, uintptr(pid), 0, 0)
 	sid = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -646,7 +646,7 @@
 func Gettimeofday(tv *Timeval) (err error) {
 	_, _, e1 := RawSyscall(SYS_GETTIMEOFDAY, uintptr(unsafe.Pointer(tv)), 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -672,7 +672,7 @@
 func Kill(pid int, signum Signal) (err error) {
 	_, _, e1 := Syscall(SYS_KILL, uintptr(pid), uintptr(signum), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -683,7 +683,7 @@
 	r0, _, e1 := Syscall(SYS_KQUEUE, 0, 0, 0)
 	fd = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -699,7 +699,7 @@
 	_, _, e1 := Syscall(SYS_LCHOWN, uintptr(unsafe.Pointer(_p0)), uintptr(uid), uintptr(gid))
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -721,7 +721,7 @@
 	use(unsafe.Pointer(_p0))
 	use(unsafe.Pointer(_p1))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -731,7 +731,7 @@
 func Listen(s int, backlog int) (err error) {
 	_, _, e1 := Syscall(SYS_LISTEN, uintptr(s), uintptr(backlog), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -747,7 +747,7 @@
 	_, _, e1 := Syscall(SYS_LSTAT, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -763,7 +763,7 @@
 	_, _, e1 := Syscall(SYS_MKDIR, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -779,7 +779,7 @@
 	_, _, e1 := Syscall(SYS_MKFIFO, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -795,7 +795,7 @@
 	_, _, e1 := Syscall(SYS_MKNOD, uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(dev))
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -805,7 +805,7 @@
 func Nanosleep(time *Timespec, leftover *Timespec) (err error) {
 	_, _, e1 := Syscall(SYS_NANOSLEEP, uintptr(unsafe.Pointer(time)), uintptr(unsafe.Pointer(leftover)), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -822,7 +822,7 @@
 	use(unsafe.Pointer(_p0))
 	fd = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -839,7 +839,7 @@
 	use(unsafe.Pointer(_p0))
 	val = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -856,7 +856,7 @@
 	r0, _, e1 := Syscall6(SYS_PREAD, uintptr(fd), uintptr(_p0), uintptr(len(p)), uintptr(offset), uintptr(offset>>32), 0)
 	n = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -873,7 +873,7 @@
 	r0, _, e1 := Syscall6(SYS_PWRITE, uintptr(fd), uintptr(_p0), uintptr(len(p)), uintptr(offset), uintptr(offset>>32), 0)
 	n = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -890,7 +890,7 @@
 	r0, _, e1 := Syscall(SYS_READ, uintptr(fd), uintptr(_p0), uintptr(len(p)))
 	n = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -913,7 +913,7 @@
 	use(unsafe.Pointer(_p0))
 	n = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -935,7 +935,7 @@
 	use(unsafe.Pointer(_p0))
 	use(unsafe.Pointer(_p1))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -951,7 +951,7 @@
 	_, _, e1 := Syscall(SYS_REVOKE, uintptr(unsafe.Pointer(_p0)), 0, 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -967,7 +967,7 @@
 	_, _, e1 := Syscall(SYS_RMDIR, uintptr(unsafe.Pointer(_p0)), 0, 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -978,7 +978,7 @@
 	r0, r1, e1 := Syscall6(SYS_LSEEK, uintptr(fd), uintptr(offset), uintptr(offset>>32), uintptr(whence), 0, 0)
 	newoffset = int64(int64(r1)<<32 | int64(r0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -988,7 +988,7 @@
 func Select(n int, r *FdSet, w *FdSet, e *FdSet, timeout *Timeval) (err error) {
 	_, _, e1 := Syscall6(SYS_SELECT, uintptr(n), uintptr(unsafe.Pointer(r)), uintptr(unsafe.Pointer(w)), uintptr(unsafe.Pointer(e)), uintptr(unsafe.Pointer(timeout)), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -998,7 +998,7 @@
 func Setegid(egid int) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETEGID, uintptr(egid), 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1008,7 +1008,7 @@
 func Seteuid(euid int) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETEUID, uintptr(euid), 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1018,7 +1018,7 @@
 func Setgid(gid int) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETGID, uintptr(gid), 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1034,7 +1034,7 @@
 	_, _, e1 := Syscall(SYS_SETLOGIN, uintptr(unsafe.Pointer(_p0)), 0, 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1044,7 +1044,7 @@
 func Setpgid(pid int, pgid int) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETPGID, uintptr(pid), uintptr(pgid), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1054,7 +1054,7 @@
 func Setpriority(which int, who int, prio int) (err error) {
 	_, _, e1 := Syscall(SYS_SETPRIORITY, uintptr(which), uintptr(who), uintptr(prio))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1064,7 +1064,7 @@
 func Setregid(rgid int, egid int) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETREGID, uintptr(rgid), uintptr(egid), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1074,7 +1074,7 @@
 func Setreuid(ruid int, euid int) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETREUID, uintptr(ruid), uintptr(euid), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1084,7 +1084,7 @@
 func Setrlimit(which int, lim *Rlimit) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETRLIMIT, uintptr(which), uintptr(unsafe.Pointer(lim)), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1095,7 +1095,7 @@
 	r0, _, e1 := RawSyscall(SYS_SETSID, 0, 0, 0)
 	pid = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1105,7 +1105,7 @@
 func Settimeofday(tp *Timeval) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETTIMEOFDAY, uintptr(unsafe.Pointer(tp)), 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1115,7 +1115,7 @@
 func Setuid(uid int) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETUID, uintptr(uid), 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1131,7 +1131,7 @@
 	_, _, e1 := Syscall(SYS_STAT, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1147,7 +1147,7 @@
 	_, _, e1 := Syscall(SYS_STATFS, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1169,7 +1169,7 @@
 	use(unsafe.Pointer(_p0))
 	use(unsafe.Pointer(_p1))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1179,7 +1179,7 @@
 func Sync() (err error) {
 	_, _, e1 := Syscall(SYS_SYNC, 0, 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1195,7 +1195,7 @@
 	_, _, e1 := Syscall(SYS_TRUNCATE, uintptr(unsafe.Pointer(_p0)), uintptr(length), uintptr(length>>32))
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1219,7 +1219,7 @@
 	_, _, e1 := Syscall(SYS_UNDELETE, uintptr(unsafe.Pointer(_p0)), 0, 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1235,7 +1235,7 @@
 	_, _, e1 := Syscall(SYS_UNLINK, uintptr(unsafe.Pointer(_p0)), 0, 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1251,7 +1251,7 @@
 	_, _, e1 := Syscall(SYS_UNMOUNT, uintptr(unsafe.Pointer(_p0)), uintptr(flags), 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1268,7 +1268,7 @@
 	r0, _, e1 := Syscall(SYS_WRITE, uintptr(fd), uintptr(_p0), uintptr(len(p)))
 	n = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1279,7 +1279,7 @@
 	r0, _, e1 := Syscall9(SYS_MMAP, uintptr(addr), uintptr(length), uintptr(prot), uintptr(flag), uintptr(fd), uintptr(pos), uintptr(pos>>32), 0, 0)
 	ret = uintptr(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1289,7 +1289,7 @@
 func munmap(addr uintptr, length uintptr) (err error) {
 	_, _, e1 := Syscall(SYS_MUNMAP, uintptr(addr), uintptr(length), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1300,7 +1300,7 @@
 	r0, _, e1 := Syscall(SYS_READ, uintptr(fd), uintptr(unsafe.Pointer(buf)), uintptr(nbuf))
 	n = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1311,7 +1311,7 @@
 	r0, _, e1 := Syscall(SYS_WRITE, uintptr(fd), uintptr(unsafe.Pointer(buf)), uintptr(nbuf))
 	n = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1322,7 +1322,7 @@
 	r0, _, e1 := Syscall6(SYS_ACCEPT4, uintptr(fd), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)), uintptr(flags), 0, 0)
 	nfd = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
diff --git a/src/syscall/zsyscall_freebsd_amd64.go b/src/syscall/zsyscall_freebsd_amd64.go
index 026b560..3cb87c1 100644
--- a/src/syscall/zsyscall_freebsd_amd64.go
+++ b/src/syscall/zsyscall_freebsd_amd64.go
@@ -11,7 +11,7 @@
 	r0, _, e1 := RawSyscall(SYS_GETGROUPS, uintptr(ngid), uintptr(unsafe.Pointer(gid)), 0)
 	n = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -21,7 +21,7 @@
 func setgroups(ngid int, gid *_Gid_t) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETGROUPS, uintptr(ngid), uintptr(unsafe.Pointer(gid)), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -32,7 +32,7 @@
 	r0, _, e1 := Syscall6(SYS_WAIT4, uintptr(pid), uintptr(unsafe.Pointer(wstatus)), uintptr(options), uintptr(unsafe.Pointer(rusage)), 0, 0)
 	wpid = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -43,7 +43,7 @@
 	r0, _, e1 := Syscall(SYS_ACCEPT, uintptr(s), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)))
 	fd = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -53,7 +53,7 @@
 func bind(s int, addr unsafe.Pointer, addrlen _Socklen) (err error) {
 	_, _, e1 := Syscall(SYS_BIND, uintptr(s), uintptr(addr), uintptr(addrlen))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -63,7 +63,7 @@
 func connect(s int, addr unsafe.Pointer, addrlen _Socklen) (err error) {
 	_, _, e1 := Syscall(SYS_CONNECT, uintptr(s), uintptr(addr), uintptr(addrlen))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -74,7 +74,7 @@
 	r0, _, e1 := RawSyscall(SYS_SOCKET, uintptr(domain), uintptr(typ), uintptr(proto))
 	fd = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -84,7 +84,7 @@
 func getsockopt(s int, level int, name int, val unsafe.Pointer, vallen *_Socklen) (err error) {
 	_, _, e1 := Syscall6(SYS_GETSOCKOPT, uintptr(s), uintptr(level), uintptr(name), uintptr(val), uintptr(unsafe.Pointer(vallen)), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -94,7 +94,7 @@
 func setsockopt(s int, level int, name int, val unsafe.Pointer, vallen uintptr) (err error) {
 	_, _, e1 := Syscall6(SYS_SETSOCKOPT, uintptr(s), uintptr(level), uintptr(name), uintptr(val), uintptr(vallen), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -104,7 +104,7 @@
 func getpeername(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (err error) {
 	_, _, e1 := RawSyscall(SYS_GETPEERNAME, uintptr(fd), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -114,7 +114,7 @@
 func getsockname(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (err error) {
 	_, _, e1 := RawSyscall(SYS_GETSOCKNAME, uintptr(fd), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -124,7 +124,7 @@
 func Shutdown(s int, how int) (err error) {
 	_, _, e1 := Syscall(SYS_SHUTDOWN, uintptr(s), uintptr(how), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -134,7 +134,7 @@
 func socketpair(domain int, typ int, proto int, fd *[2]int32) (err error) {
 	_, _, e1 := RawSyscall6(SYS_SOCKETPAIR, uintptr(domain), uintptr(typ), uintptr(proto), uintptr(unsafe.Pointer(fd)), 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -151,7 +151,7 @@
 	r0, _, e1 := Syscall6(SYS_RECVFROM, uintptr(fd), uintptr(_p0), uintptr(len(p)), uintptr(flags), uintptr(unsafe.Pointer(from)), uintptr(unsafe.Pointer(fromlen)))
 	n = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -167,7 +167,7 @@
 	}
 	_, _, e1 := Syscall6(SYS_SENDTO, uintptr(s), uintptr(_p0), uintptr(len(buf)), uintptr(flags), uintptr(to), uintptr(addrlen))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -178,7 +178,7 @@
 	r0, _, e1 := Syscall(SYS_RECVMSG, uintptr(s), uintptr(unsafe.Pointer(msg)), uintptr(flags))
 	n = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -189,7 +189,7 @@
 	r0, _, e1 := Syscall(SYS_SENDMSG, uintptr(s), uintptr(unsafe.Pointer(msg)), uintptr(flags))
 	n = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -200,7 +200,7 @@
 	r0, _, e1 := Syscall6(SYS_KEVENT, uintptr(kq), uintptr(change), uintptr(nchange), uintptr(event), uintptr(nevent), uintptr(unsafe.Pointer(timeout)))
 	n = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -216,7 +216,7 @@
 	}
 	_, _, e1 := Syscall6(SYS___SYSCTL, uintptr(_p0), uintptr(len(mib)), uintptr(unsafe.Pointer(old)), uintptr(unsafe.Pointer(oldlen)), uintptr(unsafe.Pointer(new)), uintptr(newlen))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -232,7 +232,7 @@
 	_, _, e1 := Syscall(SYS_UTIMES, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(timeval)), 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -242,7 +242,7 @@
 func futimes(fd int, timeval *[2]Timeval) (err error) {
 	_, _, e1 := Syscall(SYS_FUTIMES, uintptr(fd), uintptr(unsafe.Pointer(timeval)), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -253,7 +253,7 @@
 	r0, _, e1 := Syscall(SYS_FCNTL, uintptr(fd), uintptr(cmd), uintptr(arg))
 	val = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -265,7 +265,7 @@
 	r = int(r0)
 	w = int(r1)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -281,7 +281,7 @@
 	_, _, e1 := Syscall(SYS_ACCESS, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -291,7 +291,7 @@
 func Adjtime(delta *Timeval, olddelta *Timeval) (err error) {
 	_, _, e1 := Syscall(SYS_ADJTIME, uintptr(unsafe.Pointer(delta)), uintptr(unsafe.Pointer(olddelta)), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -307,7 +307,7 @@
 	_, _, e1 := Syscall(SYS_CHDIR, uintptr(unsafe.Pointer(_p0)), 0, 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -323,7 +323,7 @@
 	_, _, e1 := Syscall(SYS_CHFLAGS, uintptr(unsafe.Pointer(_p0)), uintptr(flags), 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -339,7 +339,7 @@
 	_, _, e1 := Syscall(SYS_CHMOD, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -355,7 +355,7 @@
 	_, _, e1 := Syscall(SYS_CHOWN, uintptr(unsafe.Pointer(_p0)), uintptr(uid), uintptr(gid))
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -371,7 +371,7 @@
 	_, _, e1 := Syscall(SYS_CHROOT, uintptr(unsafe.Pointer(_p0)), 0, 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -381,7 +381,7 @@
 func Close(fd int) (err error) {
 	_, _, e1 := Syscall(SYS_CLOSE, uintptr(fd), 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -389,10 +389,10 @@
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
 func Dup(fd int) (nfd int, err error) {
-	r0, _, e1 := RawSyscall(SYS_DUP, uintptr(fd), 0, 0)
+	r0, _, e1 := Syscall(SYS_DUP, uintptr(fd), 0, 0)
 	nfd = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -400,9 +400,9 @@
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
 func Dup2(from int, to int) (err error) {
-	_, _, e1 := RawSyscall(SYS_DUP2, uintptr(from), uintptr(to), 0)
+	_, _, e1 := Syscall(SYS_DUP2, uintptr(from), uintptr(to), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -419,7 +419,7 @@
 func Fchdir(fd int) (err error) {
 	_, _, e1 := Syscall(SYS_FCHDIR, uintptr(fd), 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -429,7 +429,7 @@
 func Fchflags(fd int, flags int) (err error) {
 	_, _, e1 := Syscall(SYS_FCHFLAGS, uintptr(fd), uintptr(flags), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -439,7 +439,7 @@
 func Fchmod(fd int, mode uint32) (err error) {
 	_, _, e1 := Syscall(SYS_FCHMOD, uintptr(fd), uintptr(mode), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -449,7 +449,7 @@
 func Fchown(fd int, uid int, gid int) (err error) {
 	_, _, e1 := Syscall(SYS_FCHOWN, uintptr(fd), uintptr(uid), uintptr(gid))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -459,7 +459,7 @@
 func Flock(fd int, how int) (err error) {
 	_, _, e1 := Syscall(SYS_FLOCK, uintptr(fd), uintptr(how), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -470,7 +470,7 @@
 	r0, _, e1 := Syscall(SYS_FPATHCONF, uintptr(fd), uintptr(name), 0)
 	val = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -480,7 +480,7 @@
 func Fstat(fd int, stat *Stat_t) (err error) {
 	_, _, e1 := Syscall(SYS_FSTAT, uintptr(fd), uintptr(unsafe.Pointer(stat)), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -490,7 +490,7 @@
 func Fstatfs(fd int, stat *Statfs_t) (err error) {
 	_, _, e1 := Syscall(SYS_FSTATFS, uintptr(fd), uintptr(unsafe.Pointer(stat)), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -500,7 +500,7 @@
 func Fsync(fd int) (err error) {
 	_, _, e1 := Syscall(SYS_FSYNC, uintptr(fd), 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -510,7 +510,7 @@
 func Ftruncate(fd int, length int64) (err error) {
 	_, _, e1 := Syscall(SYS_FTRUNCATE, uintptr(fd), uintptr(length), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -527,7 +527,7 @@
 	r0, _, e1 := Syscall6(SYS_GETDIRENTRIES, uintptr(fd), uintptr(_p0), uintptr(len(buf)), uintptr(unsafe.Pointer(basep)), 0, 0)
 	n = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -570,7 +570,7 @@
 	r0, _, e1 := RawSyscall(SYS_GETPGID, uintptr(pid), 0, 0)
 	pgid = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -605,7 +605,7 @@
 	r0, _, e1 := Syscall(SYS_GETPRIORITY, uintptr(which), uintptr(who), 0)
 	prio = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -615,7 +615,7 @@
 func Getrlimit(which int, lim *Rlimit) (err error) {
 	_, _, e1 := RawSyscall(SYS_GETRLIMIT, uintptr(which), uintptr(unsafe.Pointer(lim)), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -625,7 +625,7 @@
 func Getrusage(who int, rusage *Rusage) (err error) {
 	_, _, e1 := RawSyscall(SYS_GETRUSAGE, uintptr(who), uintptr(unsafe.Pointer(rusage)), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -636,7 +636,7 @@
 	r0, _, e1 := RawSyscall(SYS_GETSID, uintptr(pid), 0, 0)
 	sid = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -646,7 +646,7 @@
 func Gettimeofday(tv *Timeval) (err error) {
 	_, _, e1 := RawSyscall(SYS_GETTIMEOFDAY, uintptr(unsafe.Pointer(tv)), 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -672,7 +672,7 @@
 func Kill(pid int, signum Signal) (err error) {
 	_, _, e1 := Syscall(SYS_KILL, uintptr(pid), uintptr(signum), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -683,7 +683,7 @@
 	r0, _, e1 := Syscall(SYS_KQUEUE, 0, 0, 0)
 	fd = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -699,7 +699,7 @@
 	_, _, e1 := Syscall(SYS_LCHOWN, uintptr(unsafe.Pointer(_p0)), uintptr(uid), uintptr(gid))
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -721,7 +721,7 @@
 	use(unsafe.Pointer(_p0))
 	use(unsafe.Pointer(_p1))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -731,7 +731,7 @@
 func Listen(s int, backlog int) (err error) {
 	_, _, e1 := Syscall(SYS_LISTEN, uintptr(s), uintptr(backlog), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -747,7 +747,7 @@
 	_, _, e1 := Syscall(SYS_LSTAT, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -763,7 +763,7 @@
 	_, _, e1 := Syscall(SYS_MKDIR, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -779,7 +779,7 @@
 	_, _, e1 := Syscall(SYS_MKFIFO, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -795,7 +795,7 @@
 	_, _, e1 := Syscall(SYS_MKNOD, uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(dev))
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -805,7 +805,7 @@
 func Nanosleep(time *Timespec, leftover *Timespec) (err error) {
 	_, _, e1 := Syscall(SYS_NANOSLEEP, uintptr(unsafe.Pointer(time)), uintptr(unsafe.Pointer(leftover)), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -822,7 +822,7 @@
 	use(unsafe.Pointer(_p0))
 	fd = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -839,7 +839,7 @@
 	use(unsafe.Pointer(_p0))
 	val = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -856,7 +856,7 @@
 	r0, _, e1 := Syscall6(SYS_PREAD, uintptr(fd), uintptr(_p0), uintptr(len(p)), uintptr(offset), 0, 0)
 	n = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -873,7 +873,7 @@
 	r0, _, e1 := Syscall6(SYS_PWRITE, uintptr(fd), uintptr(_p0), uintptr(len(p)), uintptr(offset), 0, 0)
 	n = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -890,7 +890,7 @@
 	r0, _, e1 := Syscall(SYS_READ, uintptr(fd), uintptr(_p0), uintptr(len(p)))
 	n = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -913,7 +913,7 @@
 	use(unsafe.Pointer(_p0))
 	n = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -935,7 +935,7 @@
 	use(unsafe.Pointer(_p0))
 	use(unsafe.Pointer(_p1))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -951,7 +951,7 @@
 	_, _, e1 := Syscall(SYS_REVOKE, uintptr(unsafe.Pointer(_p0)), 0, 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -967,7 +967,7 @@
 	_, _, e1 := Syscall(SYS_RMDIR, uintptr(unsafe.Pointer(_p0)), 0, 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -978,7 +978,7 @@
 	r0, _, e1 := Syscall(SYS_LSEEK, uintptr(fd), uintptr(offset), uintptr(whence))
 	newoffset = int64(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -988,7 +988,7 @@
 func Select(n int, r *FdSet, w *FdSet, e *FdSet, timeout *Timeval) (err error) {
 	_, _, e1 := Syscall6(SYS_SELECT, uintptr(n), uintptr(unsafe.Pointer(r)), uintptr(unsafe.Pointer(w)), uintptr(unsafe.Pointer(e)), uintptr(unsafe.Pointer(timeout)), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -998,7 +998,7 @@
 func Setegid(egid int) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETEGID, uintptr(egid), 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1008,7 +1008,7 @@
 func Seteuid(euid int) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETEUID, uintptr(euid), 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1018,7 +1018,7 @@
 func Setgid(gid int) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETGID, uintptr(gid), 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1034,7 +1034,7 @@
 	_, _, e1 := Syscall(SYS_SETLOGIN, uintptr(unsafe.Pointer(_p0)), 0, 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1044,7 +1044,7 @@
 func Setpgid(pid int, pgid int) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETPGID, uintptr(pid), uintptr(pgid), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1054,7 +1054,7 @@
 func Setpriority(which int, who int, prio int) (err error) {
 	_, _, e1 := Syscall(SYS_SETPRIORITY, uintptr(which), uintptr(who), uintptr(prio))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1064,7 +1064,7 @@
 func Setregid(rgid int, egid int) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETREGID, uintptr(rgid), uintptr(egid), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1074,7 +1074,7 @@
 func Setreuid(ruid int, euid int) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETREUID, uintptr(ruid), uintptr(euid), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1084,7 +1084,7 @@
 func Setrlimit(which int, lim *Rlimit) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETRLIMIT, uintptr(which), uintptr(unsafe.Pointer(lim)), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1095,7 +1095,7 @@
 	r0, _, e1 := RawSyscall(SYS_SETSID, 0, 0, 0)
 	pid = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1105,7 +1105,7 @@
 func Settimeofday(tp *Timeval) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETTIMEOFDAY, uintptr(unsafe.Pointer(tp)), 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1115,7 +1115,7 @@
 func Setuid(uid int) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETUID, uintptr(uid), 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1131,7 +1131,7 @@
 	_, _, e1 := Syscall(SYS_STAT, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1147,7 +1147,7 @@
 	_, _, e1 := Syscall(SYS_STATFS, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1169,7 +1169,7 @@
 	use(unsafe.Pointer(_p0))
 	use(unsafe.Pointer(_p1))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1179,7 +1179,7 @@
 func Sync() (err error) {
 	_, _, e1 := Syscall(SYS_SYNC, 0, 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1195,7 +1195,7 @@
 	_, _, e1 := Syscall(SYS_TRUNCATE, uintptr(unsafe.Pointer(_p0)), uintptr(length), 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1219,7 +1219,7 @@
 	_, _, e1 := Syscall(SYS_UNDELETE, uintptr(unsafe.Pointer(_p0)), 0, 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1235,7 +1235,7 @@
 	_, _, e1 := Syscall(SYS_UNLINK, uintptr(unsafe.Pointer(_p0)), 0, 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1251,7 +1251,7 @@
 	_, _, e1 := Syscall(SYS_UNMOUNT, uintptr(unsafe.Pointer(_p0)), uintptr(flags), 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1268,7 +1268,7 @@
 	r0, _, e1 := Syscall(SYS_WRITE, uintptr(fd), uintptr(_p0), uintptr(len(p)))
 	n = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1279,7 +1279,7 @@
 	r0, _, e1 := Syscall6(SYS_MMAP, uintptr(addr), uintptr(length), uintptr(prot), uintptr(flag), uintptr(fd), uintptr(pos))
 	ret = uintptr(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1289,7 +1289,7 @@
 func munmap(addr uintptr, length uintptr) (err error) {
 	_, _, e1 := Syscall(SYS_MUNMAP, uintptr(addr), uintptr(length), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1300,7 +1300,7 @@
 	r0, _, e1 := Syscall(SYS_READ, uintptr(fd), uintptr(unsafe.Pointer(buf)), uintptr(nbuf))
 	n = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1311,7 +1311,7 @@
 	r0, _, e1 := Syscall(SYS_WRITE, uintptr(fd), uintptr(unsafe.Pointer(buf)), uintptr(nbuf))
 	n = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1322,7 +1322,7 @@
 	r0, _, e1 := Syscall6(SYS_ACCEPT4, uintptr(fd), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)), uintptr(flags), 0, 0)
 	nfd = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
diff --git a/src/syscall/zsyscall_freebsd_arm.go b/src/syscall/zsyscall_freebsd_arm.go
index 0c349cb..3404183 100644
--- a/src/syscall/zsyscall_freebsd_arm.go
+++ b/src/syscall/zsyscall_freebsd_arm.go
@@ -11,7 +11,7 @@
 	r0, _, e1 := RawSyscall(SYS_GETGROUPS, uintptr(ngid), uintptr(unsafe.Pointer(gid)), 0)
 	n = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -21,7 +21,7 @@
 func setgroups(ngid int, gid *_Gid_t) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETGROUPS, uintptr(ngid), uintptr(unsafe.Pointer(gid)), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -32,7 +32,7 @@
 	r0, _, e1 := Syscall6(SYS_WAIT4, uintptr(pid), uintptr(unsafe.Pointer(wstatus)), uintptr(options), uintptr(unsafe.Pointer(rusage)), 0, 0)
 	wpid = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -43,7 +43,7 @@
 	r0, _, e1 := Syscall(SYS_ACCEPT, uintptr(s), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)))
 	fd = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -53,7 +53,7 @@
 func bind(s int, addr unsafe.Pointer, addrlen _Socklen) (err error) {
 	_, _, e1 := Syscall(SYS_BIND, uintptr(s), uintptr(addr), uintptr(addrlen))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -63,7 +63,7 @@
 func connect(s int, addr unsafe.Pointer, addrlen _Socklen) (err error) {
 	_, _, e1 := Syscall(SYS_CONNECT, uintptr(s), uintptr(addr), uintptr(addrlen))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -74,7 +74,7 @@
 	r0, _, e1 := RawSyscall(SYS_SOCKET, uintptr(domain), uintptr(typ), uintptr(proto))
 	fd = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -84,7 +84,7 @@
 func getsockopt(s int, level int, name int, val unsafe.Pointer, vallen *_Socklen) (err error) {
 	_, _, e1 := Syscall6(SYS_GETSOCKOPT, uintptr(s), uintptr(level), uintptr(name), uintptr(val), uintptr(unsafe.Pointer(vallen)), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -94,7 +94,7 @@
 func setsockopt(s int, level int, name int, val unsafe.Pointer, vallen uintptr) (err error) {
 	_, _, e1 := Syscall6(SYS_SETSOCKOPT, uintptr(s), uintptr(level), uintptr(name), uintptr(val), uintptr(vallen), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -104,7 +104,7 @@
 func getpeername(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (err error) {
 	_, _, e1 := RawSyscall(SYS_GETPEERNAME, uintptr(fd), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -114,7 +114,7 @@
 func getsockname(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (err error) {
 	_, _, e1 := RawSyscall(SYS_GETSOCKNAME, uintptr(fd), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -124,7 +124,7 @@
 func Shutdown(s int, how int) (err error) {
 	_, _, e1 := Syscall(SYS_SHUTDOWN, uintptr(s), uintptr(how), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -134,7 +134,7 @@
 func socketpair(domain int, typ int, proto int, fd *[2]int32) (err error) {
 	_, _, e1 := RawSyscall6(SYS_SOCKETPAIR, uintptr(domain), uintptr(typ), uintptr(proto), uintptr(unsafe.Pointer(fd)), 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -151,7 +151,7 @@
 	r0, _, e1 := Syscall6(SYS_RECVFROM, uintptr(fd), uintptr(_p0), uintptr(len(p)), uintptr(flags), uintptr(unsafe.Pointer(from)), uintptr(unsafe.Pointer(fromlen)))
 	n = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -167,7 +167,7 @@
 	}
 	_, _, e1 := Syscall6(SYS_SENDTO, uintptr(s), uintptr(_p0), uintptr(len(buf)), uintptr(flags), uintptr(to), uintptr(addrlen))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -178,7 +178,7 @@
 	r0, _, e1 := Syscall(SYS_RECVMSG, uintptr(s), uintptr(unsafe.Pointer(msg)), uintptr(flags))
 	n = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -189,7 +189,7 @@
 	r0, _, e1 := Syscall(SYS_SENDMSG, uintptr(s), uintptr(unsafe.Pointer(msg)), uintptr(flags))
 	n = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -200,7 +200,7 @@
 	r0, _, e1 := Syscall6(SYS_KEVENT, uintptr(kq), uintptr(change), uintptr(nchange), uintptr(event), uintptr(nevent), uintptr(unsafe.Pointer(timeout)))
 	n = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -216,7 +216,7 @@
 	}
 	_, _, e1 := Syscall6(SYS___SYSCTL, uintptr(_p0), uintptr(len(mib)), uintptr(unsafe.Pointer(old)), uintptr(unsafe.Pointer(oldlen)), uintptr(unsafe.Pointer(new)), uintptr(newlen))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -232,7 +232,7 @@
 	_, _, e1 := Syscall(SYS_UTIMES, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(timeval)), 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -242,7 +242,7 @@
 func futimes(fd int, timeval *[2]Timeval) (err error) {
 	_, _, e1 := Syscall(SYS_FUTIMES, uintptr(fd), uintptr(unsafe.Pointer(timeval)), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -253,7 +253,7 @@
 	r0, _, e1 := Syscall(SYS_FCNTL, uintptr(fd), uintptr(cmd), uintptr(arg))
 	val = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -265,7 +265,7 @@
 	r = int(r0)
 	w = int(r1)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -281,7 +281,7 @@
 	_, _, e1 := Syscall(SYS_ACCESS, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -291,7 +291,7 @@
 func Adjtime(delta *Timeval, olddelta *Timeval) (err error) {
 	_, _, e1 := Syscall(SYS_ADJTIME, uintptr(unsafe.Pointer(delta)), uintptr(unsafe.Pointer(olddelta)), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -307,7 +307,7 @@
 	_, _, e1 := Syscall(SYS_CHDIR, uintptr(unsafe.Pointer(_p0)), 0, 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -323,7 +323,7 @@
 	_, _, e1 := Syscall(SYS_CHFLAGS, uintptr(unsafe.Pointer(_p0)), uintptr(flags), 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -339,7 +339,7 @@
 	_, _, e1 := Syscall(SYS_CHMOD, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -355,7 +355,7 @@
 	_, _, e1 := Syscall(SYS_CHOWN, uintptr(unsafe.Pointer(_p0)), uintptr(uid), uintptr(gid))
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -371,7 +371,7 @@
 	_, _, e1 := Syscall(SYS_CHROOT, uintptr(unsafe.Pointer(_p0)), 0, 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -381,7 +381,7 @@
 func Close(fd int) (err error) {
 	_, _, e1 := Syscall(SYS_CLOSE, uintptr(fd), 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -389,10 +389,10 @@
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
 func Dup(fd int) (nfd int, err error) {
-	r0, _, e1 := RawSyscall(SYS_DUP, uintptr(fd), 0, 0)
+	r0, _, e1 := Syscall(SYS_DUP, uintptr(fd), 0, 0)
 	nfd = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -400,9 +400,9 @@
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
 func Dup2(from int, to int) (err error) {
-	_, _, e1 := RawSyscall(SYS_DUP2, uintptr(from), uintptr(to), 0)
+	_, _, e1 := Syscall(SYS_DUP2, uintptr(from), uintptr(to), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -419,7 +419,7 @@
 func Fchdir(fd int) (err error) {
 	_, _, e1 := Syscall(SYS_FCHDIR, uintptr(fd), 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -429,7 +429,7 @@
 func Fchflags(fd int, flags int) (err error) {
 	_, _, e1 := Syscall(SYS_FCHFLAGS, uintptr(fd), uintptr(flags), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -439,7 +439,7 @@
 func Fchmod(fd int, mode uint32) (err error) {
 	_, _, e1 := Syscall(SYS_FCHMOD, uintptr(fd), uintptr(mode), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -449,7 +449,7 @@
 func Fchown(fd int, uid int, gid int) (err error) {
 	_, _, e1 := Syscall(SYS_FCHOWN, uintptr(fd), uintptr(uid), uintptr(gid))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -459,7 +459,7 @@
 func Flock(fd int, how int) (err error) {
 	_, _, e1 := Syscall(SYS_FLOCK, uintptr(fd), uintptr(how), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -470,7 +470,7 @@
 	r0, _, e1 := Syscall(SYS_FPATHCONF, uintptr(fd), uintptr(name), 0)
 	val = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -480,7 +480,7 @@
 func Fstat(fd int, stat *Stat_t) (err error) {
 	_, _, e1 := Syscall(SYS_FSTAT, uintptr(fd), uintptr(unsafe.Pointer(stat)), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -490,7 +490,7 @@
 func Fstatfs(fd int, stat *Statfs_t) (err error) {
 	_, _, e1 := Syscall(SYS_FSTATFS, uintptr(fd), uintptr(unsafe.Pointer(stat)), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -500,7 +500,7 @@
 func Fsync(fd int) (err error) {
 	_, _, e1 := Syscall(SYS_FSYNC, uintptr(fd), 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -510,7 +510,7 @@
 func Ftruncate(fd int, length int64) (err error) {
 	_, _, e1 := Syscall6(SYS_FTRUNCATE, uintptr(fd), 0, uintptr(length), uintptr(length>>32), 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -527,7 +527,7 @@
 	r0, _, e1 := Syscall6(SYS_GETDIRENTRIES, uintptr(fd), uintptr(_p0), uintptr(len(buf)), uintptr(unsafe.Pointer(basep)), 0, 0)
 	n = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -570,7 +570,7 @@
 	r0, _, e1 := RawSyscall(SYS_GETPGID, uintptr(pid), 0, 0)
 	pgid = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -605,7 +605,7 @@
 	r0, _, e1 := Syscall(SYS_GETPRIORITY, uintptr(which), uintptr(who), 0)
 	prio = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -615,7 +615,7 @@
 func Getrlimit(which int, lim *Rlimit) (err error) {
 	_, _, e1 := RawSyscall(SYS_GETRLIMIT, uintptr(which), uintptr(unsafe.Pointer(lim)), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -625,7 +625,7 @@
 func Getrusage(who int, rusage *Rusage) (err error) {
 	_, _, e1 := RawSyscall(SYS_GETRUSAGE, uintptr(who), uintptr(unsafe.Pointer(rusage)), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -636,7 +636,7 @@
 	r0, _, e1 := RawSyscall(SYS_GETSID, uintptr(pid), 0, 0)
 	sid = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -646,7 +646,7 @@
 func Gettimeofday(tv *Timeval) (err error) {
 	_, _, e1 := RawSyscall(SYS_GETTIMEOFDAY, uintptr(unsafe.Pointer(tv)), 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -672,7 +672,7 @@
 func Kill(pid int, signum Signal) (err error) {
 	_, _, e1 := Syscall(SYS_KILL, uintptr(pid), uintptr(signum), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -683,7 +683,7 @@
 	r0, _, e1 := Syscall(SYS_KQUEUE, 0, 0, 0)
 	fd = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -699,7 +699,7 @@
 	_, _, e1 := Syscall(SYS_LCHOWN, uintptr(unsafe.Pointer(_p0)), uintptr(uid), uintptr(gid))
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -721,7 +721,7 @@
 	use(unsafe.Pointer(_p0))
 	use(unsafe.Pointer(_p1))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -731,7 +731,7 @@
 func Listen(s int, backlog int) (err error) {
 	_, _, e1 := Syscall(SYS_LISTEN, uintptr(s), uintptr(backlog), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -747,7 +747,7 @@
 	_, _, e1 := Syscall(SYS_LSTAT, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -763,7 +763,7 @@
 	_, _, e1 := Syscall(SYS_MKDIR, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -779,7 +779,7 @@
 	_, _, e1 := Syscall(SYS_MKFIFO, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -795,7 +795,7 @@
 	_, _, e1 := Syscall(SYS_MKNOD, uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(dev))
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -805,7 +805,7 @@
 func Nanosleep(time *Timespec, leftover *Timespec) (err error) {
 	_, _, e1 := Syscall(SYS_NANOSLEEP, uintptr(unsafe.Pointer(time)), uintptr(unsafe.Pointer(leftover)), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -822,7 +822,7 @@
 	use(unsafe.Pointer(_p0))
 	fd = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -839,7 +839,7 @@
 	use(unsafe.Pointer(_p0))
 	val = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -856,7 +856,7 @@
 	r0, _, e1 := Syscall6(SYS_PREAD, uintptr(fd), uintptr(_p0), uintptr(len(p)), 0, uintptr(offset), uintptr(offset>>32))
 	n = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -873,7 +873,7 @@
 	r0, _, e1 := Syscall6(SYS_PWRITE, uintptr(fd), uintptr(_p0), uintptr(len(p)), 0, uintptr(offset), uintptr(offset>>32))
 	n = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -890,7 +890,7 @@
 	r0, _, e1 := Syscall(SYS_READ, uintptr(fd), uintptr(_p0), uintptr(len(p)))
 	n = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -913,7 +913,7 @@
 	use(unsafe.Pointer(_p0))
 	n = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -935,7 +935,7 @@
 	use(unsafe.Pointer(_p0))
 	use(unsafe.Pointer(_p1))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -951,7 +951,7 @@
 	_, _, e1 := Syscall(SYS_REVOKE, uintptr(unsafe.Pointer(_p0)), 0, 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -967,7 +967,7 @@
 	_, _, e1 := Syscall(SYS_RMDIR, uintptr(unsafe.Pointer(_p0)), 0, 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -978,7 +978,7 @@
 	r0, r1, e1 := Syscall6(SYS_LSEEK, uintptr(fd), 0, uintptr(offset), uintptr(offset>>32), uintptr(whence), 0)
 	newoffset = int64(int64(r1)<<32 | int64(r0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -988,7 +988,7 @@
 func Select(n int, r *FdSet, w *FdSet, e *FdSet, timeout *Timeval) (err error) {
 	_, _, e1 := Syscall6(SYS_SELECT, uintptr(n), uintptr(unsafe.Pointer(r)), uintptr(unsafe.Pointer(w)), uintptr(unsafe.Pointer(e)), uintptr(unsafe.Pointer(timeout)), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -998,7 +998,7 @@
 func Setegid(egid int) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETEGID, uintptr(egid), 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1008,7 +1008,7 @@
 func Seteuid(euid int) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETEUID, uintptr(euid), 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1018,7 +1018,7 @@
 func Setgid(gid int) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETGID, uintptr(gid), 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1034,7 +1034,7 @@
 	_, _, e1 := Syscall(SYS_SETLOGIN, uintptr(unsafe.Pointer(_p0)), 0, 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1044,7 +1044,7 @@
 func Setpgid(pid int, pgid int) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETPGID, uintptr(pid), uintptr(pgid), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1054,7 +1054,7 @@
 func Setpriority(which int, who int, prio int) (err error) {
 	_, _, e1 := Syscall(SYS_SETPRIORITY, uintptr(which), uintptr(who), uintptr(prio))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1064,7 +1064,7 @@
 func Setregid(rgid int, egid int) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETREGID, uintptr(rgid), uintptr(egid), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1074,7 +1074,7 @@
 func Setreuid(ruid int, euid int) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETREUID, uintptr(ruid), uintptr(euid), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1084,7 +1084,7 @@
 func Setrlimit(which int, lim *Rlimit) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETRLIMIT, uintptr(which), uintptr(unsafe.Pointer(lim)), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1095,7 +1095,7 @@
 	r0, _, e1 := RawSyscall(SYS_SETSID, 0, 0, 0)
 	pid = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1105,7 +1105,7 @@
 func Settimeofday(tp *Timeval) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETTIMEOFDAY, uintptr(unsafe.Pointer(tp)), 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1115,7 +1115,7 @@
 func Setuid(uid int) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETUID, uintptr(uid), 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1131,7 +1131,7 @@
 	_, _, e1 := Syscall(SYS_STAT, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1147,7 +1147,7 @@
 	_, _, e1 := Syscall(SYS_STATFS, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1169,7 +1169,7 @@
 	use(unsafe.Pointer(_p0))
 	use(unsafe.Pointer(_p1))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1179,7 +1179,7 @@
 func Sync() (err error) {
 	_, _, e1 := Syscall(SYS_SYNC, 0, 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1195,7 +1195,7 @@
 	_, _, e1 := Syscall6(SYS_TRUNCATE, uintptr(unsafe.Pointer(_p0)), 0, uintptr(length), uintptr(length>>32), 0, 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1219,7 +1219,7 @@
 	_, _, e1 := Syscall(SYS_UNDELETE, uintptr(unsafe.Pointer(_p0)), 0, 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1235,7 +1235,7 @@
 	_, _, e1 := Syscall(SYS_UNLINK, uintptr(unsafe.Pointer(_p0)), 0, 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1251,7 +1251,7 @@
 	_, _, e1 := Syscall(SYS_UNMOUNT, uintptr(unsafe.Pointer(_p0)), uintptr(flags), 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1268,7 +1268,7 @@
 	r0, _, e1 := Syscall(SYS_WRITE, uintptr(fd), uintptr(_p0), uintptr(len(p)))
 	n = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1279,7 +1279,7 @@
 	r0, _, e1 := Syscall9(SYS_MMAP, uintptr(addr), uintptr(length), uintptr(prot), uintptr(flag), uintptr(fd), 0, uintptr(pos), uintptr(pos>>32), 0)
 	ret = uintptr(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1289,7 +1289,7 @@
 func munmap(addr uintptr, length uintptr) (err error) {
 	_, _, e1 := Syscall(SYS_MUNMAP, uintptr(addr), uintptr(length), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1300,7 +1300,7 @@
 	r0, _, e1 := Syscall(SYS_READ, uintptr(fd), uintptr(unsafe.Pointer(buf)), uintptr(nbuf))
 	n = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1311,7 +1311,7 @@
 	r0, _, e1 := Syscall(SYS_WRITE, uintptr(fd), uintptr(unsafe.Pointer(buf)), uintptr(nbuf))
 	n = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1322,7 +1322,7 @@
 	r0, _, e1 := Syscall6(SYS_ACCEPT4, uintptr(fd), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)), uintptr(flags), 0, 0)
 	nfd = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
diff --git a/src/syscall/zsyscall_linux_386.go b/src/syscall/zsyscall_linux_386.go
index 8745902..e7cf745 100644
--- a/src/syscall/zsyscall_linux_386.go
+++ b/src/syscall/zsyscall_linux_386.go
@@ -22,7 +22,7 @@
 	use(unsafe.Pointer(_p0))
 	use(unsafe.Pointer(_p1))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -39,7 +39,7 @@
 	use(unsafe.Pointer(_p0))
 	fd = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -62,7 +62,7 @@
 	use(unsafe.Pointer(_p0))
 	n = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -84,7 +84,7 @@
 	use(unsafe.Pointer(_p0))
 	use(unsafe.Pointer(_p1))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -100,7 +100,7 @@
 	_, _, e1 := Syscall(SYS_UNLINKAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(flags))
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -116,7 +116,7 @@
 	_, _, e1 := Syscall(SYS_UTIMES, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(times)), 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -132,7 +132,7 @@
 	_, _, e1 := Syscall(SYS_UTIMENSAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(times)))
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -142,7 +142,7 @@
 func futimesat(dirfd int, path *byte, times *[2]Timeval) (err error) {
 	_, _, e1 := Syscall(SYS_FUTIMESAT, uintptr(dirfd), uintptr(unsafe.Pointer(path)), uintptr(unsafe.Pointer(times)))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -159,7 +159,7 @@
 	r0, _, e1 := Syscall(SYS_GETCWD, uintptr(_p0), uintptr(len(buf)), 0)
 	n = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -170,7 +170,7 @@
 	r0, _, e1 := Syscall6(SYS_WAIT4, uintptr(pid), uintptr(unsafe.Pointer(wstatus)), uintptr(options), uintptr(unsafe.Pointer(rusage)), 0, 0)
 	wpid = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -180,7 +180,7 @@
 func ptrace(request int, pid int, addr uintptr, data uintptr) (err error) {
 	_, _, e1 := Syscall6(SYS_PTRACE, uintptr(request), uintptr(pid), uintptr(addr), uintptr(data), 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -196,7 +196,7 @@
 	_, _, e1 := Syscall6(SYS_REBOOT, uintptr(magic1), uintptr(magic2), uintptr(cmd), uintptr(unsafe.Pointer(_p0)), 0, 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -224,7 +224,7 @@
 	use(unsafe.Pointer(_p1))
 	use(unsafe.Pointer(_p2))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -240,7 +240,7 @@
 	_, _, e1 := Syscall(SYS_ACCT, uintptr(unsafe.Pointer(_p0)), 0, 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -251,7 +251,7 @@
 	r0, _, e1 := Syscall(SYS_ADJTIMEX, uintptr(unsafe.Pointer(buf)), 0, 0)
 	state = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -267,7 +267,7 @@
 	_, _, e1 := Syscall(SYS_CHDIR, uintptr(unsafe.Pointer(_p0)), 0, 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -283,7 +283,7 @@
 	_, _, e1 := Syscall(SYS_CHROOT, uintptr(unsafe.Pointer(_p0)), 0, 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -293,7 +293,7 @@
 func Close(fd int) (err error) {
 	_, _, e1 := Syscall(SYS_CLOSE, uintptr(fd), 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -301,10 +301,10 @@
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
 func Dup(oldfd int) (fd int, err error) {
-	r0, _, e1 := RawSyscall(SYS_DUP, uintptr(oldfd), 0, 0)
+	r0, _, e1 := Syscall(SYS_DUP, uintptr(oldfd), 0, 0)
 	fd = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -312,9 +312,9 @@
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
 func Dup3(oldfd int, newfd int, flags int) (err error) {
-	_, _, e1 := RawSyscall(SYS_DUP3, uintptr(oldfd), uintptr(newfd), uintptr(flags))
+	_, _, e1 := Syscall(SYS_DUP3, uintptr(oldfd), uintptr(newfd), uintptr(flags))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -325,7 +325,7 @@
 	r0, _, e1 := RawSyscall(SYS_EPOLL_CREATE, uintptr(size), 0, 0)
 	fd = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -336,7 +336,7 @@
 	r0, _, e1 := RawSyscall(SYS_EPOLL_CREATE1, uintptr(flag), 0, 0)
 	fd = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -346,7 +346,7 @@
 func EpollCtl(epfd int, op int, fd int, event *EpollEvent) (err error) {
 	_, _, e1 := RawSyscall6(SYS_EPOLL_CTL, uintptr(epfd), uintptr(op), uintptr(fd), uintptr(unsafe.Pointer(event)), 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -363,7 +363,7 @@
 	r0, _, e1 := Syscall6(SYS_EPOLL_WAIT, uintptr(epfd), uintptr(_p0), uintptr(len(events)), uintptr(msec), 0, 0)
 	n = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -386,7 +386,7 @@
 	_, _, e1 := Syscall6(SYS_FACCESSAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(flags), 0, 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -396,7 +396,7 @@
 func Fallocate(fd int, mode uint32, off int64, len int64) (err error) {
 	_, _, e1 := Syscall6(SYS_FALLOCATE, uintptr(fd), uintptr(mode), uintptr(off), uintptr(off>>32), uintptr(len), uintptr(len>>32))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -406,7 +406,7 @@
 func Fchdir(fd int) (err error) {
 	_, _, e1 := Syscall(SYS_FCHDIR, uintptr(fd), 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -416,7 +416,7 @@
 func Fchmod(fd int, mode uint32) (err error) {
 	_, _, e1 := Syscall(SYS_FCHMOD, uintptr(fd), uintptr(mode), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -432,7 +432,7 @@
 	_, _, e1 := Syscall6(SYS_FCHMODAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(flags), 0, 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -448,7 +448,7 @@
 	_, _, e1 := Syscall6(SYS_FCHOWNAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(uid), uintptr(gid), uintptr(flags), 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -459,7 +459,7 @@
 	r0, _, e1 := Syscall(SYS_FCNTL, uintptr(fd), uintptr(cmd), uintptr(arg))
 	val = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -469,7 +469,7 @@
 func Fdatasync(fd int) (err error) {
 	_, _, e1 := Syscall(SYS_FDATASYNC, uintptr(fd), 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -479,7 +479,7 @@
 func Flock(fd int, how int) (err error) {
 	_, _, e1 := Syscall(SYS_FLOCK, uintptr(fd), uintptr(how), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -489,7 +489,7 @@
 func Fsync(fd int) (err error) {
 	_, _, e1 := Syscall(SYS_FSYNC, uintptr(fd), 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -506,7 +506,7 @@
 	r0, _, e1 := Syscall(SYS_GETDENTS64, uintptr(fd), uintptr(_p0), uintptr(len(buf)))
 	n = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -517,21 +517,13 @@
 	r0, _, e1 := RawSyscall(SYS_GETPGID, uintptr(pid), 0, 0)
 	pgid = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
-func Getpgrp() (pid int) {
-	r0, _, _ := RawSyscall(SYS_GETPGRP, 0, 0, 0)
-	pid = int(r0)
-	return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
 func Getpid() (pid int) {
 	r0, _, _ := RawSyscall(SYS_GETPID, 0, 0, 0)
 	pid = int(r0)
@@ -552,7 +544,7 @@
 	r0, _, e1 := Syscall(SYS_GETPRIORITY, uintptr(which), uintptr(who), 0)
 	prio = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -562,7 +554,7 @@
 func Getrusage(who int, rusage *Rusage) (err error) {
 	_, _, e1 := RawSyscall(SYS_GETRUSAGE, uintptr(who), uintptr(unsafe.Pointer(rusage)), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -599,7 +591,7 @@
 	use(unsafe.Pointer(_p1))
 	sz = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -616,7 +608,7 @@
 	use(unsafe.Pointer(_p0))
 	watchdesc = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -627,7 +619,7 @@
 	r0, _, e1 := RawSyscall(SYS_INOTIFY_INIT, 0, 0, 0)
 	fd = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -638,7 +630,7 @@
 	r0, _, e1 := RawSyscall(SYS_INOTIFY_INIT1, uintptr(flags), 0, 0)
 	fd = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -649,7 +641,7 @@
 	r0, _, e1 := RawSyscall(SYS_INOTIFY_RM_WATCH, uintptr(fd), uintptr(watchdesc), 0)
 	success = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -659,7 +651,7 @@
 func Kill(pid int, sig Signal) (err error) {
 	_, _, e1 := RawSyscall(SYS_KILL, uintptr(pid), uintptr(sig), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -676,7 +668,7 @@
 	r0, _, e1 := Syscall(SYS_SYSLOG, uintptr(typ), uintptr(_p0), uintptr(len(buf)))
 	n = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -699,7 +691,7 @@
 	use(unsafe.Pointer(_p0))
 	sz = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -715,7 +707,7 @@
 	_, _, e1 := Syscall(SYS_MKDIRAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode))
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -731,7 +723,7 @@
 	_, _, e1 := Syscall6(SYS_MKNODAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(dev), 0, 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -741,7 +733,7 @@
 func Nanosleep(time *Timespec, leftover *Timespec) (err error) {
 	_, _, e1 := Syscall(SYS_NANOSLEEP, uintptr(unsafe.Pointer(time)), uintptr(unsafe.Pointer(leftover)), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -751,7 +743,7 @@
 func Pause() (err error) {
 	_, _, e1 := Syscall(SYS_PAUSE, 0, 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -773,7 +765,7 @@
 	use(unsafe.Pointer(_p0))
 	use(unsafe.Pointer(_p1))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -783,7 +775,7 @@
 func prlimit(pid int, resource int, old *Rlimit, newlimit *Rlimit) (err error) {
 	_, _, e1 := RawSyscall6(SYS_PRLIMIT64, uintptr(pid), uintptr(resource), uintptr(unsafe.Pointer(old)), uintptr(unsafe.Pointer(newlimit)), 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -800,7 +792,7 @@
 	r0, _, e1 := Syscall(SYS_READ, uintptr(fd), uintptr(_p0), uintptr(len(p)))
 	n = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -822,7 +814,7 @@
 	use(unsafe.Pointer(_p0))
 	use(unsafe.Pointer(_p1))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -844,7 +836,7 @@
 	use(unsafe.Pointer(_p0))
 	use(unsafe.Pointer(_p1))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -860,7 +852,7 @@
 	}
 	_, _, e1 := Syscall(SYS_SETDOMAINNAME, uintptr(_p0), uintptr(len(p)), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -876,7 +868,7 @@
 	}
 	_, _, e1 := Syscall(SYS_SETHOSTNAME, uintptr(_p0), uintptr(len(p)), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -886,7 +878,7 @@
 func Setpgid(pid int, pgid int) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETPGID, uintptr(pid), uintptr(pgid), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -897,7 +889,7 @@
 	r0, _, e1 := RawSyscall(SYS_SETSID, 0, 0, 0)
 	pid = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -907,7 +899,7 @@
 func Settimeofday(tv *Timeval) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETTIMEOFDAY, uintptr(unsafe.Pointer(tv)), 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -917,7 +909,7 @@
 func Setpriority(which int, who int, prio int) (err error) {
 	_, _, e1 := Syscall(SYS_SETPRIORITY, uintptr(which), uintptr(who), uintptr(prio))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -945,7 +937,7 @@
 	use(unsafe.Pointer(_p0))
 	use(unsafe.Pointer(_p1))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -962,7 +954,7 @@
 func Sysinfo(info *Sysinfo_t) (err error) {
 	_, _, e1 := RawSyscall(SYS_SYSINFO, uintptr(unsafe.Pointer(info)), 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -973,7 +965,7 @@
 	r0, r1, e1 := Syscall6(SYS_TEE, uintptr(rfd), uintptr(wfd), uintptr(len), uintptr(flags), 0, 0)
 	n = int64(int64(r1)<<32 | int64(r0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -983,7 +975,7 @@
 func Tgkill(tgid int, tid int, sig Signal) (err error) {
 	_, _, e1 := RawSyscall(SYS_TGKILL, uintptr(tgid), uintptr(tid), uintptr(sig))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -994,7 +986,7 @@
 	r0, _, e1 := RawSyscall(SYS_TIMES, uintptr(unsafe.Pointer(tms)), 0, 0)
 	ticks = uintptr(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1012,7 +1004,7 @@
 func Uname(buf *Utsname) (err error) {
 	_, _, e1 := RawSyscall(SYS_UNAME, uintptr(unsafe.Pointer(buf)), 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1028,7 +1020,7 @@
 	_, _, e1 := Syscall(SYS_UMOUNT2, uintptr(unsafe.Pointer(_p0)), uintptr(flags), 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1038,7 +1030,7 @@
 func Unshare(flags int) (err error) {
 	_, _, e1 := Syscall(SYS_UNSHARE, uintptr(flags), 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1048,7 +1040,7 @@
 func Ustat(dev int, ubuf *Ustat_t) (err error) {
 	_, _, e1 := Syscall(SYS_USTAT, uintptr(dev), uintptr(unsafe.Pointer(ubuf)), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1064,7 +1056,7 @@
 	_, _, e1 := Syscall(SYS_UTIME, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(buf)), 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1081,7 +1073,7 @@
 	r0, _, e1 := Syscall(SYS_WRITE, uintptr(fd), uintptr(_p0), uintptr(len(p)))
 	n = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1091,7 +1083,7 @@
 func exitThread(code int) (err error) {
 	_, _, e1 := Syscall(SYS_EXIT, uintptr(code), 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1102,7 +1094,7 @@
 	r0, _, e1 := Syscall(SYS_READ, uintptr(fd), uintptr(unsafe.Pointer(p)), uintptr(np))
 	n = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1113,7 +1105,7 @@
 	r0, _, e1 := Syscall(SYS_WRITE, uintptr(fd), uintptr(unsafe.Pointer(p)), uintptr(np))
 	n = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1123,7 +1115,7 @@
 func munmap(addr uintptr, length uintptr) (err error) {
 	_, _, e1 := Syscall(SYS_MUNMAP, uintptr(addr), uintptr(length), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1139,7 +1131,7 @@
 	}
 	_, _, e1 := Syscall(SYS_MADVISE, uintptr(_p0), uintptr(len(b)), uintptr(advice))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1155,7 +1147,7 @@
 	}
 	_, _, e1 := Syscall(SYS_MPROTECT, uintptr(_p0), uintptr(len(b)), uintptr(prot))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1171,7 +1163,7 @@
 	}
 	_, _, e1 := Syscall(SYS_MLOCK, uintptr(_p0), uintptr(len(b)), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1187,7 +1179,7 @@
 	}
 	_, _, e1 := Syscall(SYS_MUNLOCK, uintptr(_p0), uintptr(len(b)), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1197,7 +1189,7 @@
 func Mlockall(flags int) (err error) {
 	_, _, e1 := Syscall(SYS_MLOCKALL, uintptr(flags), 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1207,7 +1199,7 @@
 func Munlockall() (err error) {
 	_, _, e1 := Syscall(SYS_MUNLOCKALL, 0, 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1217,7 +1209,7 @@
 func pipe(p *[2]_C_int) (err error) {
 	_, _, e1 := RawSyscall(SYS_PIPE, uintptr(unsafe.Pointer(p)), 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1227,7 +1219,7 @@
 func pipe2(p *[2]_C_int, flags int) (err error) {
 	_, _, e1 := RawSyscall(SYS_PIPE2, uintptr(unsafe.Pointer(p)), uintptr(flags), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1235,9 +1227,9 @@
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
 func Dup2(oldfd int, newfd int) (err error) {
-	_, _, e1 := RawSyscall(SYS_DUP2, uintptr(oldfd), uintptr(newfd), 0)
+	_, _, e1 := Syscall(SYS_DUP2, uintptr(oldfd), uintptr(newfd), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1247,7 +1239,7 @@
 func Fchown(fd int, uid int, gid int) (err error) {
 	_, _, e1 := Syscall(SYS_FCHOWN32, uintptr(fd), uintptr(uid), uintptr(gid))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1257,7 +1249,7 @@
 func Fstat(fd int, stat *Stat_t) (err error) {
 	_, _, e1 := Syscall(SYS_FSTAT64, uintptr(fd), uintptr(unsafe.Pointer(stat)), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1267,7 +1259,7 @@
 func Ftruncate(fd int, length int64) (err error) {
 	_, _, e1 := Syscall(SYS_FTRUNCATE64, uintptr(fd), uintptr(length), uintptr(length>>32))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1309,7 +1301,7 @@
 func Ioperm(from int, num int, on int) (err error) {
 	_, _, e1 := Syscall(SYS_IOPERM, uintptr(from), uintptr(num), uintptr(on))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1319,7 +1311,7 @@
 func Iopl(level int) (err error) {
 	_, _, e1 := Syscall(SYS_IOPL, uintptr(level), 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1335,7 +1327,7 @@
 	_, _, e1 := Syscall(SYS_LCHOWN32, uintptr(unsafe.Pointer(_p0)), uintptr(uid), uintptr(gid))
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1351,7 +1343,7 @@
 	_, _, e1 := Syscall(SYS_LSTAT64, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1368,7 +1360,7 @@
 	r0, _, e1 := Syscall6(SYS_PREAD64, uintptr(fd), uintptr(_p0), uintptr(len(p)), uintptr(offset), uintptr(offset>>32), 0)
 	n = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1385,7 +1377,7 @@
 	r0, _, e1 := Syscall6(SYS_PWRITE64, uintptr(fd), uintptr(_p0), uintptr(len(p)), uintptr(offset), uintptr(offset>>32), 0)
 	n = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1396,7 +1388,7 @@
 	r0, _, e1 := Syscall6(SYS_SENDFILE64, uintptr(outfd), uintptr(infd), uintptr(unsafe.Pointer(offset)), uintptr(count), 0, 0)
 	written = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1406,7 +1398,7 @@
 func Setfsgid(gid int) (err error) {
 	_, _, e1 := Syscall(SYS_SETFSGID32, uintptr(gid), 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1416,7 +1408,7 @@
 func Setfsuid(uid int) (err error) {
 	_, _, e1 := Syscall(SYS_SETFSUID32, uintptr(uid), 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1426,7 +1418,7 @@
 func Setregid(rgid int, egid int) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETREGID32, uintptr(rgid), uintptr(egid), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1436,7 +1428,7 @@
 func Setresgid(rgid int, egid int, sgid int) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETRESGID32, uintptr(rgid), uintptr(egid), uintptr(sgid))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1446,7 +1438,7 @@
 func Setresuid(ruid int, euid int, suid int) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETRESUID32, uintptr(ruid), uintptr(euid), uintptr(suid))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1456,7 +1448,7 @@
 func Setreuid(ruid int, euid int) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETREUID32, uintptr(ruid), uintptr(euid), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1467,7 +1459,7 @@
 	r0, _, e1 := Syscall6(SYS_SPLICE, uintptr(rfd), uintptr(unsafe.Pointer(roff)), uintptr(wfd), uintptr(unsafe.Pointer(woff)), uintptr(len), uintptr(flags))
 	n = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1483,7 +1475,7 @@
 	_, _, e1 := Syscall(SYS_STAT64, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1493,7 +1485,7 @@
 func SyncFileRange(fd int, off int64, n int64, flags int) (err error) {
 	_, _, e1 := Syscall6(SYS_SYNC_FILE_RANGE, uintptr(fd), uintptr(off), uintptr(off>>32), uintptr(n), uintptr(n>>32), uintptr(flags))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1509,7 +1501,7 @@
 	_, _, e1 := Syscall(SYS_TRUNCATE64, uintptr(unsafe.Pointer(_p0)), uintptr(length), uintptr(length>>32))
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1520,7 +1512,7 @@
 	r0, _, e1 := RawSyscall(SYS_GETGROUPS32, uintptr(n), uintptr(unsafe.Pointer(list)), 0)
 	nn = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1530,7 +1522,7 @@
 func setgroups(n int, list *_Gid_t) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETGROUPS32, uintptr(n), uintptr(unsafe.Pointer(list)), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1541,7 +1533,7 @@
 	r0, _, e1 := Syscall6(SYS__NEWSELECT, uintptr(nfd), uintptr(unsafe.Pointer(r)), uintptr(unsafe.Pointer(w)), uintptr(unsafe.Pointer(e)), uintptr(unsafe.Pointer(timeout)), 0)
 	n = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1552,7 +1544,7 @@
 	r0, _, e1 := Syscall6(SYS_MMAP2, uintptr(addr), uintptr(length), uintptr(prot), uintptr(flags), uintptr(fd), uintptr(pageOffset))
 	xaddr = uintptr(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1562,7 +1554,7 @@
 func getrlimit(resource int, rlim *rlimit32) (err error) {
 	_, _, e1 := RawSyscall(SYS_GETRLIMIT, uintptr(resource), uintptr(unsafe.Pointer(rlim)), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1572,7 +1564,7 @@
 func setrlimit(resource int, rlim *rlimit32) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETRLIMIT, uintptr(resource), uintptr(unsafe.Pointer(rlim)), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1582,7 +1574,7 @@
 func Gettimeofday(tv *Timeval) (err error) {
 	_, _, e1 := RawSyscall(SYS_GETTIMEOFDAY, uintptr(unsafe.Pointer(tv)), 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1593,7 +1585,7 @@
 	r0, _, e1 := RawSyscall(SYS_TIME, uintptr(unsafe.Pointer(t)), 0, 0)
 	tt = Time_t(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
diff --git a/src/syscall/zsyscall_linux_amd64.go b/src/syscall/zsyscall_linux_amd64.go
index c163c96..b23573b 100644
--- a/src/syscall/zsyscall_linux_amd64.go
+++ b/src/syscall/zsyscall_linux_amd64.go
@@ -22,7 +22,7 @@
 	use(unsafe.Pointer(_p0))
 	use(unsafe.Pointer(_p1))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -39,7 +39,7 @@
 	use(unsafe.Pointer(_p0))
 	fd = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -62,7 +62,7 @@
 	use(unsafe.Pointer(_p0))
 	n = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -84,7 +84,7 @@
 	use(unsafe.Pointer(_p0))
 	use(unsafe.Pointer(_p1))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -100,7 +100,7 @@
 	_, _, e1 := Syscall(SYS_UNLINKAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(flags))
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -116,7 +116,7 @@
 	_, _, e1 := Syscall(SYS_UTIMES, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(times)), 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -132,7 +132,7 @@
 	_, _, e1 := Syscall(SYS_UTIMENSAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(times)))
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -142,7 +142,7 @@
 func futimesat(dirfd int, path *byte, times *[2]Timeval) (err error) {
 	_, _, e1 := Syscall(SYS_FUTIMESAT, uintptr(dirfd), uintptr(unsafe.Pointer(path)), uintptr(unsafe.Pointer(times)))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -159,7 +159,7 @@
 	r0, _, e1 := Syscall(SYS_GETCWD, uintptr(_p0), uintptr(len(buf)), 0)
 	n = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -170,7 +170,7 @@
 	r0, _, e1 := Syscall6(SYS_WAIT4, uintptr(pid), uintptr(unsafe.Pointer(wstatus)), uintptr(options), uintptr(unsafe.Pointer(rusage)), 0, 0)
 	wpid = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -180,7 +180,7 @@
 func ptrace(request int, pid int, addr uintptr, data uintptr) (err error) {
 	_, _, e1 := Syscall6(SYS_PTRACE, uintptr(request), uintptr(pid), uintptr(addr), uintptr(data), 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -196,7 +196,7 @@
 	_, _, e1 := Syscall6(SYS_REBOOT, uintptr(magic1), uintptr(magic2), uintptr(cmd), uintptr(unsafe.Pointer(_p0)), 0, 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -224,7 +224,7 @@
 	use(unsafe.Pointer(_p1))
 	use(unsafe.Pointer(_p2))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -240,7 +240,7 @@
 	_, _, e1 := Syscall(SYS_ACCT, uintptr(unsafe.Pointer(_p0)), 0, 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -251,7 +251,7 @@
 	r0, _, e1 := Syscall(SYS_ADJTIMEX, uintptr(unsafe.Pointer(buf)), 0, 0)
 	state = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -267,7 +267,7 @@
 	_, _, e1 := Syscall(SYS_CHDIR, uintptr(unsafe.Pointer(_p0)), 0, 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -283,7 +283,7 @@
 	_, _, e1 := Syscall(SYS_CHROOT, uintptr(unsafe.Pointer(_p0)), 0, 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -293,7 +293,7 @@
 func Close(fd int) (err error) {
 	_, _, e1 := Syscall(SYS_CLOSE, uintptr(fd), 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -301,10 +301,10 @@
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
 func Dup(oldfd int) (fd int, err error) {
-	r0, _, e1 := RawSyscall(SYS_DUP, uintptr(oldfd), 0, 0)
+	r0, _, e1 := Syscall(SYS_DUP, uintptr(oldfd), 0, 0)
 	fd = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -312,9 +312,9 @@
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
 func Dup3(oldfd int, newfd int, flags int) (err error) {
-	_, _, e1 := RawSyscall(SYS_DUP3, uintptr(oldfd), uintptr(newfd), uintptr(flags))
+	_, _, e1 := Syscall(SYS_DUP3, uintptr(oldfd), uintptr(newfd), uintptr(flags))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -325,7 +325,7 @@
 	r0, _, e1 := RawSyscall(SYS_EPOLL_CREATE, uintptr(size), 0, 0)
 	fd = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -336,7 +336,7 @@
 	r0, _, e1 := RawSyscall(SYS_EPOLL_CREATE1, uintptr(flag), 0, 0)
 	fd = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -346,7 +346,7 @@
 func EpollCtl(epfd int, op int, fd int, event *EpollEvent) (err error) {
 	_, _, e1 := RawSyscall6(SYS_EPOLL_CTL, uintptr(epfd), uintptr(op), uintptr(fd), uintptr(unsafe.Pointer(event)), 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -363,7 +363,7 @@
 	r0, _, e1 := Syscall6(SYS_EPOLL_WAIT, uintptr(epfd), uintptr(_p0), uintptr(len(events)), uintptr(msec), 0, 0)
 	n = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -386,7 +386,7 @@
 	_, _, e1 := Syscall6(SYS_FACCESSAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(flags), 0, 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -396,7 +396,7 @@
 func Fallocate(fd int, mode uint32, off int64, len int64) (err error) {
 	_, _, e1 := Syscall6(SYS_FALLOCATE, uintptr(fd), uintptr(mode), uintptr(off), uintptr(len), 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -406,7 +406,7 @@
 func Fchdir(fd int) (err error) {
 	_, _, e1 := Syscall(SYS_FCHDIR, uintptr(fd), 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -416,7 +416,7 @@
 func Fchmod(fd int, mode uint32) (err error) {
 	_, _, e1 := Syscall(SYS_FCHMOD, uintptr(fd), uintptr(mode), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -432,7 +432,7 @@
 	_, _, e1 := Syscall6(SYS_FCHMODAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(flags), 0, 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -448,7 +448,7 @@
 	_, _, e1 := Syscall6(SYS_FCHOWNAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(uid), uintptr(gid), uintptr(flags), 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -459,7 +459,7 @@
 	r0, _, e1 := Syscall(SYS_FCNTL, uintptr(fd), uintptr(cmd), uintptr(arg))
 	val = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -469,7 +469,7 @@
 func Fdatasync(fd int) (err error) {
 	_, _, e1 := Syscall(SYS_FDATASYNC, uintptr(fd), 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -479,7 +479,7 @@
 func Flock(fd int, how int) (err error) {
 	_, _, e1 := Syscall(SYS_FLOCK, uintptr(fd), uintptr(how), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -489,7 +489,7 @@
 func Fsync(fd int) (err error) {
 	_, _, e1 := Syscall(SYS_FSYNC, uintptr(fd), 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -506,7 +506,7 @@
 	r0, _, e1 := Syscall(SYS_GETDENTS64, uintptr(fd), uintptr(_p0), uintptr(len(buf)))
 	n = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -517,21 +517,13 @@
 	r0, _, e1 := RawSyscall(SYS_GETPGID, uintptr(pid), 0, 0)
 	pgid = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
-func Getpgrp() (pid int) {
-	r0, _, _ := RawSyscall(SYS_GETPGRP, 0, 0, 0)
-	pid = int(r0)
-	return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
 func Getpid() (pid int) {
 	r0, _, _ := RawSyscall(SYS_GETPID, 0, 0, 0)
 	pid = int(r0)
@@ -552,7 +544,7 @@
 	r0, _, e1 := Syscall(SYS_GETPRIORITY, uintptr(which), uintptr(who), 0)
 	prio = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -562,7 +554,7 @@
 func Getrusage(who int, rusage *Rusage) (err error) {
 	_, _, e1 := RawSyscall(SYS_GETRUSAGE, uintptr(who), uintptr(unsafe.Pointer(rusage)), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -599,7 +591,7 @@
 	use(unsafe.Pointer(_p1))
 	sz = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -616,7 +608,7 @@
 	use(unsafe.Pointer(_p0))
 	watchdesc = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -627,7 +619,7 @@
 	r0, _, e1 := RawSyscall(SYS_INOTIFY_INIT, 0, 0, 0)
 	fd = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -638,7 +630,7 @@
 	r0, _, e1 := RawSyscall(SYS_INOTIFY_INIT1, uintptr(flags), 0, 0)
 	fd = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -649,7 +641,7 @@
 	r0, _, e1 := RawSyscall(SYS_INOTIFY_RM_WATCH, uintptr(fd), uintptr(watchdesc), 0)
 	success = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -659,7 +651,7 @@
 func Kill(pid int, sig Signal) (err error) {
 	_, _, e1 := RawSyscall(SYS_KILL, uintptr(pid), uintptr(sig), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -676,7 +668,7 @@
 	r0, _, e1 := Syscall(SYS_SYSLOG, uintptr(typ), uintptr(_p0), uintptr(len(buf)))
 	n = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -699,7 +691,7 @@
 	use(unsafe.Pointer(_p0))
 	sz = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -715,7 +707,7 @@
 	_, _, e1 := Syscall(SYS_MKDIRAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode))
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -731,7 +723,7 @@
 	_, _, e1 := Syscall6(SYS_MKNODAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(dev), 0, 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -741,7 +733,7 @@
 func Nanosleep(time *Timespec, leftover *Timespec) (err error) {
 	_, _, e1 := Syscall(SYS_NANOSLEEP, uintptr(unsafe.Pointer(time)), uintptr(unsafe.Pointer(leftover)), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -751,7 +743,7 @@
 func Pause() (err error) {
 	_, _, e1 := Syscall(SYS_PAUSE, 0, 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -773,7 +765,7 @@
 	use(unsafe.Pointer(_p0))
 	use(unsafe.Pointer(_p1))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -783,7 +775,7 @@
 func prlimit(pid int, resource int, old *Rlimit, newlimit *Rlimit) (err error) {
 	_, _, e1 := RawSyscall6(SYS_PRLIMIT64, uintptr(pid), uintptr(resource), uintptr(unsafe.Pointer(old)), uintptr(unsafe.Pointer(newlimit)), 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -800,7 +792,7 @@
 	r0, _, e1 := Syscall(SYS_READ, uintptr(fd), uintptr(_p0), uintptr(len(p)))
 	n = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -822,7 +814,7 @@
 	use(unsafe.Pointer(_p0))
 	use(unsafe.Pointer(_p1))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -844,7 +836,7 @@
 	use(unsafe.Pointer(_p0))
 	use(unsafe.Pointer(_p1))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -860,7 +852,7 @@
 	}
 	_, _, e1 := Syscall(SYS_SETDOMAINNAME, uintptr(_p0), uintptr(len(p)), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -876,7 +868,7 @@
 	}
 	_, _, e1 := Syscall(SYS_SETHOSTNAME, uintptr(_p0), uintptr(len(p)), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -886,7 +878,7 @@
 func Setpgid(pid int, pgid int) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETPGID, uintptr(pid), uintptr(pgid), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -897,7 +889,7 @@
 	r0, _, e1 := RawSyscall(SYS_SETSID, 0, 0, 0)
 	pid = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -907,7 +899,7 @@
 func Settimeofday(tv *Timeval) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETTIMEOFDAY, uintptr(unsafe.Pointer(tv)), 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -917,7 +909,7 @@
 func Setpriority(which int, who int, prio int) (err error) {
 	_, _, e1 := Syscall(SYS_SETPRIORITY, uintptr(which), uintptr(who), uintptr(prio))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -945,7 +937,7 @@
 	use(unsafe.Pointer(_p0))
 	use(unsafe.Pointer(_p1))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -962,7 +954,7 @@
 func Sysinfo(info *Sysinfo_t) (err error) {
 	_, _, e1 := RawSyscall(SYS_SYSINFO, uintptr(unsafe.Pointer(info)), 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -973,7 +965,7 @@
 	r0, _, e1 := Syscall6(SYS_TEE, uintptr(rfd), uintptr(wfd), uintptr(len), uintptr(flags), 0, 0)
 	n = int64(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -983,7 +975,7 @@
 func Tgkill(tgid int, tid int, sig Signal) (err error) {
 	_, _, e1 := RawSyscall(SYS_TGKILL, uintptr(tgid), uintptr(tid), uintptr(sig))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -994,7 +986,7 @@
 	r0, _, e1 := RawSyscall(SYS_TIMES, uintptr(unsafe.Pointer(tms)), 0, 0)
 	ticks = uintptr(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1012,7 +1004,7 @@
 func Uname(buf *Utsname) (err error) {
 	_, _, e1 := RawSyscall(SYS_UNAME, uintptr(unsafe.Pointer(buf)), 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1028,7 +1020,7 @@
 	_, _, e1 := Syscall(SYS_UMOUNT2, uintptr(unsafe.Pointer(_p0)), uintptr(flags), 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1038,7 +1030,7 @@
 func Unshare(flags int) (err error) {
 	_, _, e1 := Syscall(SYS_UNSHARE, uintptr(flags), 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1048,7 +1040,7 @@
 func Ustat(dev int, ubuf *Ustat_t) (err error) {
 	_, _, e1 := Syscall(SYS_USTAT, uintptr(dev), uintptr(unsafe.Pointer(ubuf)), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1064,7 +1056,7 @@
 	_, _, e1 := Syscall(SYS_UTIME, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(buf)), 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1081,7 +1073,7 @@
 	r0, _, e1 := Syscall(SYS_WRITE, uintptr(fd), uintptr(_p0), uintptr(len(p)))
 	n = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1091,7 +1083,7 @@
 func exitThread(code int) (err error) {
 	_, _, e1 := Syscall(SYS_EXIT, uintptr(code), 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1102,7 +1094,7 @@
 	r0, _, e1 := Syscall(SYS_READ, uintptr(fd), uintptr(unsafe.Pointer(p)), uintptr(np))
 	n = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1113,7 +1105,7 @@
 	r0, _, e1 := Syscall(SYS_WRITE, uintptr(fd), uintptr(unsafe.Pointer(p)), uintptr(np))
 	n = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1123,7 +1115,7 @@
 func munmap(addr uintptr, length uintptr) (err error) {
 	_, _, e1 := Syscall(SYS_MUNMAP, uintptr(addr), uintptr(length), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1139,7 +1131,7 @@
 	}
 	_, _, e1 := Syscall(SYS_MADVISE, uintptr(_p0), uintptr(len(b)), uintptr(advice))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1155,7 +1147,7 @@
 	}
 	_, _, e1 := Syscall(SYS_MPROTECT, uintptr(_p0), uintptr(len(b)), uintptr(prot))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1171,7 +1163,7 @@
 	}
 	_, _, e1 := Syscall(SYS_MLOCK, uintptr(_p0), uintptr(len(b)), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1187,7 +1179,7 @@
 	}
 	_, _, e1 := Syscall(SYS_MUNLOCK, uintptr(_p0), uintptr(len(b)), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1197,7 +1189,7 @@
 func Mlockall(flags int) (err error) {
 	_, _, e1 := Syscall(SYS_MLOCKALL, uintptr(flags), 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1207,7 +1199,7 @@
 func Munlockall() (err error) {
 	_, _, e1 := Syscall(SYS_MUNLOCKALL, 0, 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1215,9 +1207,9 @@
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
 func Dup2(oldfd int, newfd int) (err error) {
-	_, _, e1 := RawSyscall(SYS_DUP2, uintptr(oldfd), uintptr(newfd), 0)
+	_, _, e1 := Syscall(SYS_DUP2, uintptr(oldfd), uintptr(newfd), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1227,7 +1219,7 @@
 func Fchown(fd int, uid int, gid int) (err error) {
 	_, _, e1 := Syscall(SYS_FCHOWN, uintptr(fd), uintptr(uid), uintptr(gid))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1237,7 +1229,7 @@
 func Fstat(fd int, stat *Stat_t) (err error) {
 	_, _, e1 := Syscall(SYS_FSTAT, uintptr(fd), uintptr(unsafe.Pointer(stat)), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1247,7 +1239,7 @@
 func Fstatfs(fd int, buf *Statfs_t) (err error) {
 	_, _, e1 := Syscall(SYS_FSTATFS, uintptr(fd), uintptr(unsafe.Pointer(buf)), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1257,7 +1249,7 @@
 func Ftruncate(fd int, length int64) (err error) {
 	_, _, e1 := Syscall(SYS_FTRUNCATE, uintptr(fd), uintptr(length), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1291,7 +1283,7 @@
 func Getrlimit(resource int, rlim *Rlimit) (err error) {
 	_, _, e1 := RawSyscall(SYS_GETRLIMIT, uintptr(resource), uintptr(unsafe.Pointer(rlim)), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1309,7 +1301,7 @@
 func Ioperm(from int, num int, on int) (err error) {
 	_, _, e1 := Syscall(SYS_IOPERM, uintptr(from), uintptr(num), uintptr(on))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1319,7 +1311,7 @@
 func Iopl(level int) (err error) {
 	_, _, e1 := Syscall(SYS_IOPL, uintptr(level), 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1335,7 +1327,7 @@
 	_, _, e1 := Syscall(SYS_LCHOWN, uintptr(unsafe.Pointer(_p0)), uintptr(uid), uintptr(gid))
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1345,7 +1337,7 @@
 func Listen(s int, n int) (err error) {
 	_, _, e1 := Syscall(SYS_LISTEN, uintptr(s), uintptr(n), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1361,7 +1353,7 @@
 	_, _, e1 := Syscall(SYS_LSTAT, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1378,7 +1370,7 @@
 	r0, _, e1 := Syscall6(SYS_PREAD64, uintptr(fd), uintptr(_p0), uintptr(len(p)), uintptr(offset), 0, 0)
 	n = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1395,7 +1387,7 @@
 	r0, _, e1 := Syscall6(SYS_PWRITE64, uintptr(fd), uintptr(_p0), uintptr(len(p)), uintptr(offset), 0, 0)
 	n = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1406,7 +1398,7 @@
 	r0, _, e1 := Syscall(SYS_LSEEK, uintptr(fd), uintptr(offset), uintptr(whence))
 	off = int64(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1417,7 +1409,7 @@
 	r0, _, e1 := Syscall6(SYS_SELECT, uintptr(nfd), uintptr(unsafe.Pointer(r)), uintptr(unsafe.Pointer(w)), uintptr(unsafe.Pointer(e)), uintptr(unsafe.Pointer(timeout)), 0)
 	n = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1428,7 +1420,7 @@
 	r0, _, e1 := Syscall6(SYS_SENDFILE, uintptr(outfd), uintptr(infd), uintptr(unsafe.Pointer(offset)), uintptr(count), 0, 0)
 	written = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1438,7 +1430,7 @@
 func Setfsgid(gid int) (err error) {
 	_, _, e1 := Syscall(SYS_SETFSGID, uintptr(gid), 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1448,7 +1440,7 @@
 func Setfsuid(uid int) (err error) {
 	_, _, e1 := Syscall(SYS_SETFSUID, uintptr(uid), 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1458,7 +1450,7 @@
 func Setregid(rgid int, egid int) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETREGID, uintptr(rgid), uintptr(egid), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1468,7 +1460,7 @@
 func Setresgid(rgid int, egid int, sgid int) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETRESGID, uintptr(rgid), uintptr(egid), uintptr(sgid))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1478,7 +1470,7 @@
 func Setresuid(ruid int, euid int, suid int) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETRESUID, uintptr(ruid), uintptr(euid), uintptr(suid))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1488,7 +1480,7 @@
 func Setrlimit(resource int, rlim *Rlimit) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETRLIMIT, uintptr(resource), uintptr(unsafe.Pointer(rlim)), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1498,7 +1490,7 @@
 func Setreuid(ruid int, euid int) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETREUID, uintptr(ruid), uintptr(euid), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1508,7 +1500,7 @@
 func Shutdown(fd int, how int) (err error) {
 	_, _, e1 := Syscall(SYS_SHUTDOWN, uintptr(fd), uintptr(how), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1519,7 +1511,7 @@
 	r0, _, e1 := Syscall6(SYS_SPLICE, uintptr(rfd), uintptr(unsafe.Pointer(roff)), uintptr(wfd), uintptr(unsafe.Pointer(woff)), uintptr(len), uintptr(flags))
 	n = int64(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1535,7 +1527,7 @@
 	_, _, e1 := Syscall(SYS_STAT, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1551,7 +1543,7 @@
 	_, _, e1 := Syscall(SYS_STATFS, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(buf)), 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1561,7 +1553,7 @@
 func SyncFileRange(fd int, off int64, n int64, flags int) (err error) {
 	_, _, e1 := Syscall6(SYS_SYNC_FILE_RANGE, uintptr(fd), uintptr(off), uintptr(n), uintptr(flags), 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1577,7 +1569,7 @@
 	_, _, e1 := Syscall(SYS_TRUNCATE, uintptr(unsafe.Pointer(_p0)), uintptr(length), 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1588,7 +1580,7 @@
 	r0, _, e1 := Syscall(SYS_ACCEPT, uintptr(s), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)))
 	fd = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1599,7 +1591,7 @@
 	r0, _, e1 := Syscall6(SYS_ACCEPT4, uintptr(s), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)), uintptr(flags), 0, 0)
 	fd = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1609,7 +1601,7 @@
 func bind(s int, addr unsafe.Pointer, addrlen _Socklen) (err error) {
 	_, _, e1 := Syscall(SYS_BIND, uintptr(s), uintptr(addr), uintptr(addrlen))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1619,7 +1611,7 @@
 func connect(s int, addr unsafe.Pointer, addrlen _Socklen) (err error) {
 	_, _, e1 := Syscall(SYS_CONNECT, uintptr(s), uintptr(addr), uintptr(addrlen))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1630,7 +1622,7 @@
 	r0, _, e1 := RawSyscall(SYS_GETGROUPS, uintptr(n), uintptr(unsafe.Pointer(list)), 0)
 	nn = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1640,7 +1632,7 @@
 func setgroups(n int, list *_Gid_t) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETGROUPS, uintptr(n), uintptr(unsafe.Pointer(list)), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1650,7 +1642,7 @@
 func getsockopt(s int, level int, name int, val unsafe.Pointer, vallen *_Socklen) (err error) {
 	_, _, e1 := Syscall6(SYS_GETSOCKOPT, uintptr(s), uintptr(level), uintptr(name), uintptr(val), uintptr(unsafe.Pointer(vallen)), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1660,7 +1652,7 @@
 func setsockopt(s int, level int, name int, val unsafe.Pointer, vallen uintptr) (err error) {
 	_, _, e1 := Syscall6(SYS_SETSOCKOPT, uintptr(s), uintptr(level), uintptr(name), uintptr(val), uintptr(vallen), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1671,7 +1663,7 @@
 	r0, _, e1 := RawSyscall(SYS_SOCKET, uintptr(domain), uintptr(typ), uintptr(proto))
 	fd = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1681,7 +1673,7 @@
 func socketpair(domain int, typ int, proto int, fd *[2]int32) (err error) {
 	_, _, e1 := RawSyscall6(SYS_SOCKETPAIR, uintptr(domain), uintptr(typ), uintptr(proto), uintptr(unsafe.Pointer(fd)), 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1691,7 +1683,7 @@
 func getpeername(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (err error) {
 	_, _, e1 := RawSyscall(SYS_GETPEERNAME, uintptr(fd), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1701,7 +1693,7 @@
 func getsockname(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (err error) {
 	_, _, e1 := RawSyscall(SYS_GETSOCKNAME, uintptr(fd), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1718,7 +1710,7 @@
 	r0, _, e1 := Syscall6(SYS_RECVFROM, uintptr(fd), uintptr(_p0), uintptr(len(p)), uintptr(flags), uintptr(unsafe.Pointer(from)), uintptr(unsafe.Pointer(fromlen)))
 	n = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1734,7 +1726,7 @@
 	}
 	_, _, e1 := Syscall6(SYS_SENDTO, uintptr(s), uintptr(_p0), uintptr(len(buf)), uintptr(flags), uintptr(to), uintptr(addrlen))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1745,7 +1737,7 @@
 	r0, _, e1 := Syscall(SYS_RECVMSG, uintptr(s), uintptr(unsafe.Pointer(msg)), uintptr(flags))
 	n = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1756,7 +1748,7 @@
 	r0, _, e1 := Syscall(SYS_SENDMSG, uintptr(s), uintptr(unsafe.Pointer(msg)), uintptr(flags))
 	n = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1767,7 +1759,7 @@
 	r0, _, e1 := Syscall6(SYS_MMAP, uintptr(addr), uintptr(length), uintptr(prot), uintptr(flags), uintptr(fd), uintptr(offset))
 	xaddr = uintptr(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1777,7 +1769,7 @@
 func pipe(p *[2]_C_int) (err error) {
 	_, _, e1 := RawSyscall(SYS_PIPE, uintptr(unsafe.Pointer(p)), 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1787,7 +1779,7 @@
 func pipe2(p *[2]_C_int, flags int) (err error) {
 	_, _, e1 := RawSyscall(SYS_PIPE2, uintptr(unsafe.Pointer(p)), uintptr(flags), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
diff --git a/src/syscall/zsyscall_linux_arm.go b/src/syscall/zsyscall_linux_arm.go
index 976a293..054cf40 100644
--- a/src/syscall/zsyscall_linux_arm.go
+++ b/src/syscall/zsyscall_linux_arm.go
@@ -22,7 +22,7 @@
 	use(unsafe.Pointer(_p0))
 	use(unsafe.Pointer(_p1))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -39,7 +39,7 @@
 	use(unsafe.Pointer(_p0))
 	fd = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -62,7 +62,7 @@
 	use(unsafe.Pointer(_p0))
 	n = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -84,7 +84,7 @@
 	use(unsafe.Pointer(_p0))
 	use(unsafe.Pointer(_p1))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -100,7 +100,7 @@
 	_, _, e1 := Syscall(SYS_UNLINKAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(flags))
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -116,7 +116,7 @@
 	_, _, e1 := Syscall(SYS_UTIMES, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(times)), 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -132,7 +132,7 @@
 	_, _, e1 := Syscall(SYS_UTIMENSAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(times)))
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -142,7 +142,7 @@
 func futimesat(dirfd int, path *byte, times *[2]Timeval) (err error) {
 	_, _, e1 := Syscall(SYS_FUTIMESAT, uintptr(dirfd), uintptr(unsafe.Pointer(path)), uintptr(unsafe.Pointer(times)))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -159,7 +159,7 @@
 	r0, _, e1 := Syscall(SYS_GETCWD, uintptr(_p0), uintptr(len(buf)), 0)
 	n = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -170,7 +170,7 @@
 	r0, _, e1 := Syscall6(SYS_WAIT4, uintptr(pid), uintptr(unsafe.Pointer(wstatus)), uintptr(options), uintptr(unsafe.Pointer(rusage)), 0, 0)
 	wpid = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -180,7 +180,7 @@
 func ptrace(request int, pid int, addr uintptr, data uintptr) (err error) {
 	_, _, e1 := Syscall6(SYS_PTRACE, uintptr(request), uintptr(pid), uintptr(addr), uintptr(data), 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -196,7 +196,7 @@
 	_, _, e1 := Syscall6(SYS_REBOOT, uintptr(magic1), uintptr(magic2), uintptr(cmd), uintptr(unsafe.Pointer(_p0)), 0, 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -224,7 +224,7 @@
 	use(unsafe.Pointer(_p1))
 	use(unsafe.Pointer(_p2))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -240,7 +240,7 @@
 	_, _, e1 := Syscall(SYS_ACCT, uintptr(unsafe.Pointer(_p0)), 0, 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -251,7 +251,7 @@
 	r0, _, e1 := Syscall(SYS_ADJTIMEX, uintptr(unsafe.Pointer(buf)), 0, 0)
 	state = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -267,7 +267,7 @@
 	_, _, e1 := Syscall(SYS_CHDIR, uintptr(unsafe.Pointer(_p0)), 0, 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -283,7 +283,7 @@
 	_, _, e1 := Syscall(SYS_CHROOT, uintptr(unsafe.Pointer(_p0)), 0, 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -293,7 +293,7 @@
 func Close(fd int) (err error) {
 	_, _, e1 := Syscall(SYS_CLOSE, uintptr(fd), 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -301,10 +301,10 @@
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
 func Dup(oldfd int) (fd int, err error) {
-	r0, _, e1 := RawSyscall(SYS_DUP, uintptr(oldfd), 0, 0)
+	r0, _, e1 := Syscall(SYS_DUP, uintptr(oldfd), 0, 0)
 	fd = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -312,9 +312,9 @@
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
 func Dup3(oldfd int, newfd int, flags int) (err error) {
-	_, _, e1 := RawSyscall(SYS_DUP3, uintptr(oldfd), uintptr(newfd), uintptr(flags))
+	_, _, e1 := Syscall(SYS_DUP3, uintptr(oldfd), uintptr(newfd), uintptr(flags))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -325,7 +325,7 @@
 	r0, _, e1 := RawSyscall(SYS_EPOLL_CREATE, uintptr(size), 0, 0)
 	fd = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -336,7 +336,7 @@
 	r0, _, e1 := RawSyscall(SYS_EPOLL_CREATE1, uintptr(flag), 0, 0)
 	fd = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -346,7 +346,7 @@
 func EpollCtl(epfd int, op int, fd int, event *EpollEvent) (err error) {
 	_, _, e1 := RawSyscall6(SYS_EPOLL_CTL, uintptr(epfd), uintptr(op), uintptr(fd), uintptr(unsafe.Pointer(event)), 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -363,7 +363,7 @@
 	r0, _, e1 := Syscall6(SYS_EPOLL_WAIT, uintptr(epfd), uintptr(_p0), uintptr(len(events)), uintptr(msec), 0, 0)
 	n = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -386,7 +386,7 @@
 	_, _, e1 := Syscall6(SYS_FACCESSAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(flags), 0, 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -396,7 +396,7 @@
 func Fallocate(fd int, mode uint32, off int64, len int64) (err error) {
 	_, _, e1 := Syscall6(SYS_FALLOCATE, uintptr(fd), uintptr(mode), uintptr(off), uintptr(off>>32), uintptr(len), uintptr(len>>32))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -406,7 +406,7 @@
 func Fchdir(fd int) (err error) {
 	_, _, e1 := Syscall(SYS_FCHDIR, uintptr(fd), 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -416,7 +416,7 @@
 func Fchmod(fd int, mode uint32) (err error) {
 	_, _, e1 := Syscall(SYS_FCHMOD, uintptr(fd), uintptr(mode), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -432,7 +432,7 @@
 	_, _, e1 := Syscall6(SYS_FCHMODAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(flags), 0, 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -448,7 +448,7 @@
 	_, _, e1 := Syscall6(SYS_FCHOWNAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(uid), uintptr(gid), uintptr(flags), 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -459,7 +459,7 @@
 	r0, _, e1 := Syscall(SYS_FCNTL, uintptr(fd), uintptr(cmd), uintptr(arg))
 	val = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -469,7 +469,7 @@
 func Fdatasync(fd int) (err error) {
 	_, _, e1 := Syscall(SYS_FDATASYNC, uintptr(fd), 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -479,7 +479,7 @@
 func Flock(fd int, how int) (err error) {
 	_, _, e1 := Syscall(SYS_FLOCK, uintptr(fd), uintptr(how), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -489,7 +489,7 @@
 func Fsync(fd int) (err error) {
 	_, _, e1 := Syscall(SYS_FSYNC, uintptr(fd), 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -506,7 +506,7 @@
 	r0, _, e1 := Syscall(SYS_GETDENTS64, uintptr(fd), uintptr(_p0), uintptr(len(buf)))
 	n = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -517,21 +517,13 @@
 	r0, _, e1 := RawSyscall(SYS_GETPGID, uintptr(pid), 0, 0)
 	pgid = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
-func Getpgrp() (pid int) {
-	r0, _, _ := RawSyscall(SYS_GETPGRP, 0, 0, 0)
-	pid = int(r0)
-	return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
 func Getpid() (pid int) {
 	r0, _, _ := RawSyscall(SYS_GETPID, 0, 0, 0)
 	pid = int(r0)
@@ -552,7 +544,7 @@
 	r0, _, e1 := Syscall(SYS_GETPRIORITY, uintptr(which), uintptr(who), 0)
 	prio = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -562,7 +554,7 @@
 func Getrusage(who int, rusage *Rusage) (err error) {
 	_, _, e1 := RawSyscall(SYS_GETRUSAGE, uintptr(who), uintptr(unsafe.Pointer(rusage)), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -599,7 +591,7 @@
 	use(unsafe.Pointer(_p1))
 	sz = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -616,7 +608,7 @@
 	use(unsafe.Pointer(_p0))
 	watchdesc = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -627,7 +619,7 @@
 	r0, _, e1 := RawSyscall(SYS_INOTIFY_INIT, 0, 0, 0)
 	fd = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -638,7 +630,7 @@
 	r0, _, e1 := RawSyscall(SYS_INOTIFY_INIT1, uintptr(flags), 0, 0)
 	fd = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -649,7 +641,7 @@
 	r0, _, e1 := RawSyscall(SYS_INOTIFY_RM_WATCH, uintptr(fd), uintptr(watchdesc), 0)
 	success = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -659,7 +651,7 @@
 func Kill(pid int, sig Signal) (err error) {
 	_, _, e1 := RawSyscall(SYS_KILL, uintptr(pid), uintptr(sig), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -676,7 +668,7 @@
 	r0, _, e1 := Syscall(SYS_SYSLOG, uintptr(typ), uintptr(_p0), uintptr(len(buf)))
 	n = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -699,7 +691,7 @@
 	use(unsafe.Pointer(_p0))
 	sz = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -715,7 +707,7 @@
 	_, _, e1 := Syscall(SYS_MKDIRAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode))
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -731,7 +723,7 @@
 	_, _, e1 := Syscall6(SYS_MKNODAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(dev), 0, 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -741,7 +733,7 @@
 func Nanosleep(time *Timespec, leftover *Timespec) (err error) {
 	_, _, e1 := Syscall(SYS_NANOSLEEP, uintptr(unsafe.Pointer(time)), uintptr(unsafe.Pointer(leftover)), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -751,7 +743,7 @@
 func Pause() (err error) {
 	_, _, e1 := Syscall(SYS_PAUSE, 0, 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -773,7 +765,7 @@
 	use(unsafe.Pointer(_p0))
 	use(unsafe.Pointer(_p1))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -783,7 +775,7 @@
 func prlimit(pid int, resource int, old *Rlimit, newlimit *Rlimit) (err error) {
 	_, _, e1 := RawSyscall6(SYS_PRLIMIT64, uintptr(pid), uintptr(resource), uintptr(unsafe.Pointer(old)), uintptr(unsafe.Pointer(newlimit)), 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -800,7 +792,7 @@
 	r0, _, e1 := Syscall(SYS_READ, uintptr(fd), uintptr(_p0), uintptr(len(p)))
 	n = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -822,7 +814,7 @@
 	use(unsafe.Pointer(_p0))
 	use(unsafe.Pointer(_p1))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -844,7 +836,7 @@
 	use(unsafe.Pointer(_p0))
 	use(unsafe.Pointer(_p1))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -860,7 +852,7 @@
 	}
 	_, _, e1 := Syscall(SYS_SETDOMAINNAME, uintptr(_p0), uintptr(len(p)), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -876,7 +868,7 @@
 	}
 	_, _, e1 := Syscall(SYS_SETHOSTNAME, uintptr(_p0), uintptr(len(p)), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -886,7 +878,7 @@
 func Setpgid(pid int, pgid int) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETPGID, uintptr(pid), uintptr(pgid), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -897,7 +889,7 @@
 	r0, _, e1 := RawSyscall(SYS_SETSID, 0, 0, 0)
 	pid = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -907,7 +899,7 @@
 func Settimeofday(tv *Timeval) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETTIMEOFDAY, uintptr(unsafe.Pointer(tv)), 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -917,7 +909,7 @@
 func Setpriority(which int, who int, prio int) (err error) {
 	_, _, e1 := Syscall(SYS_SETPRIORITY, uintptr(which), uintptr(who), uintptr(prio))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -945,7 +937,7 @@
 	use(unsafe.Pointer(_p0))
 	use(unsafe.Pointer(_p1))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -962,7 +954,7 @@
 func Sysinfo(info *Sysinfo_t) (err error) {
 	_, _, e1 := RawSyscall(SYS_SYSINFO, uintptr(unsafe.Pointer(info)), 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -973,7 +965,7 @@
 	r0, r1, e1 := Syscall6(SYS_TEE, uintptr(rfd), uintptr(wfd), uintptr(len), uintptr(flags), 0, 0)
 	n = int64(int64(r1)<<32 | int64(r0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -983,7 +975,7 @@
 func Tgkill(tgid int, tid int, sig Signal) (err error) {
 	_, _, e1 := RawSyscall(SYS_TGKILL, uintptr(tgid), uintptr(tid), uintptr(sig))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -994,7 +986,7 @@
 	r0, _, e1 := RawSyscall(SYS_TIMES, uintptr(unsafe.Pointer(tms)), 0, 0)
 	ticks = uintptr(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1012,7 +1004,7 @@
 func Uname(buf *Utsname) (err error) {
 	_, _, e1 := RawSyscall(SYS_UNAME, uintptr(unsafe.Pointer(buf)), 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1028,7 +1020,7 @@
 	_, _, e1 := Syscall(SYS_UMOUNT2, uintptr(unsafe.Pointer(_p0)), uintptr(flags), 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1038,7 +1030,7 @@
 func Unshare(flags int) (err error) {
 	_, _, e1 := Syscall(SYS_UNSHARE, uintptr(flags), 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1048,7 +1040,7 @@
 func Ustat(dev int, ubuf *Ustat_t) (err error) {
 	_, _, e1 := Syscall(SYS_USTAT, uintptr(dev), uintptr(unsafe.Pointer(ubuf)), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1064,7 +1056,7 @@
 	_, _, e1 := Syscall(SYS_UTIME, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(buf)), 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1081,7 +1073,7 @@
 	r0, _, e1 := Syscall(SYS_WRITE, uintptr(fd), uintptr(_p0), uintptr(len(p)))
 	n = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1091,7 +1083,7 @@
 func exitThread(code int) (err error) {
 	_, _, e1 := Syscall(SYS_EXIT, uintptr(code), 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1102,7 +1094,7 @@
 	r0, _, e1 := Syscall(SYS_READ, uintptr(fd), uintptr(unsafe.Pointer(p)), uintptr(np))
 	n = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1113,7 +1105,7 @@
 	r0, _, e1 := Syscall(SYS_WRITE, uintptr(fd), uintptr(unsafe.Pointer(p)), uintptr(np))
 	n = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1123,7 +1115,7 @@
 func munmap(addr uintptr, length uintptr) (err error) {
 	_, _, e1 := Syscall(SYS_MUNMAP, uintptr(addr), uintptr(length), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1139,7 +1131,7 @@
 	}
 	_, _, e1 := Syscall(SYS_MADVISE, uintptr(_p0), uintptr(len(b)), uintptr(advice))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1155,7 +1147,7 @@
 	}
 	_, _, e1 := Syscall(SYS_MPROTECT, uintptr(_p0), uintptr(len(b)), uintptr(prot))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1171,7 +1163,7 @@
 	}
 	_, _, e1 := Syscall(SYS_MLOCK, uintptr(_p0), uintptr(len(b)), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1187,7 +1179,7 @@
 	}
 	_, _, e1 := Syscall(SYS_MUNLOCK, uintptr(_p0), uintptr(len(b)), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1197,7 +1189,7 @@
 func Mlockall(flags int) (err error) {
 	_, _, e1 := Syscall(SYS_MLOCKALL, uintptr(flags), 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1207,7 +1199,7 @@
 func Munlockall() (err error) {
 	_, _, e1 := Syscall(SYS_MUNLOCKALL, 0, 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1217,7 +1209,7 @@
 func pipe2(p *[2]_C_int, flags int) (err error) {
 	_, _, e1 := RawSyscall(SYS_PIPE2, uintptr(unsafe.Pointer(p)), uintptr(flags), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1228,7 +1220,7 @@
 	r0, _, e1 := Syscall(SYS_ACCEPT, uintptr(s), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)))
 	fd = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1239,7 +1231,7 @@
 	r0, _, e1 := Syscall6(SYS_ACCEPT4, uintptr(s), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)), uintptr(flags), 0, 0)
 	fd = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1249,7 +1241,7 @@
 func bind(s int, addr unsafe.Pointer, addrlen _Socklen) (err error) {
 	_, _, e1 := Syscall(SYS_BIND, uintptr(s), uintptr(addr), uintptr(addrlen))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1259,7 +1251,7 @@
 func connect(s int, addr unsafe.Pointer, addrlen _Socklen) (err error) {
 	_, _, e1 := Syscall(SYS_CONNECT, uintptr(s), uintptr(addr), uintptr(addrlen))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1270,7 +1262,7 @@
 	r0, _, e1 := RawSyscall(SYS_GETGROUPS32, uintptr(n), uintptr(unsafe.Pointer(list)), 0)
 	nn = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1280,7 +1272,7 @@
 func setgroups(n int, list *_Gid_t) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETGROUPS32, uintptr(n), uintptr(unsafe.Pointer(list)), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1290,7 +1282,7 @@
 func getsockopt(s int, level int, name int, val unsafe.Pointer, vallen *_Socklen) (err error) {
 	_, _, e1 := Syscall6(SYS_GETSOCKOPT, uintptr(s), uintptr(level), uintptr(name), uintptr(val), uintptr(unsafe.Pointer(vallen)), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1300,7 +1292,7 @@
 func setsockopt(s int, level int, name int, val unsafe.Pointer, vallen uintptr) (err error) {
 	_, _, e1 := Syscall6(SYS_SETSOCKOPT, uintptr(s), uintptr(level), uintptr(name), uintptr(val), uintptr(vallen), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1311,7 +1303,7 @@
 	r0, _, e1 := RawSyscall(SYS_SOCKET, uintptr(domain), uintptr(typ), uintptr(proto))
 	fd = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1321,7 +1313,7 @@
 func getpeername(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (err error) {
 	_, _, e1 := RawSyscall(SYS_GETPEERNAME, uintptr(fd), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1331,7 +1323,7 @@
 func getsockname(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (err error) {
 	_, _, e1 := RawSyscall(SYS_GETSOCKNAME, uintptr(fd), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1348,7 +1340,7 @@
 	r0, _, e1 := Syscall6(SYS_RECVFROM, uintptr(fd), uintptr(_p0), uintptr(len(p)), uintptr(flags), uintptr(unsafe.Pointer(from)), uintptr(unsafe.Pointer(fromlen)))
 	n = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1364,7 +1356,7 @@
 	}
 	_, _, e1 := Syscall6(SYS_SENDTO, uintptr(s), uintptr(_p0), uintptr(len(buf)), uintptr(flags), uintptr(to), uintptr(addrlen))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1374,7 +1366,7 @@
 func socketpair(domain int, typ int, flags int, fd *[2]int32) (err error) {
 	_, _, e1 := RawSyscall6(SYS_SOCKETPAIR, uintptr(domain), uintptr(typ), uintptr(flags), uintptr(unsafe.Pointer(fd)), 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1385,7 +1377,7 @@
 	r0, _, e1 := Syscall(SYS_RECVMSG, uintptr(s), uintptr(unsafe.Pointer(msg)), uintptr(flags))
 	n = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1396,7 +1388,7 @@
 	r0, _, e1 := Syscall(SYS_SENDMSG, uintptr(s), uintptr(unsafe.Pointer(msg)), uintptr(flags))
 	n = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1404,9 +1396,9 @@
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
 func Dup2(oldfd int, newfd int) (err error) {
-	_, _, e1 := RawSyscall(SYS_DUP2, uintptr(oldfd), uintptr(newfd), 0)
+	_, _, e1 := Syscall(SYS_DUP2, uintptr(oldfd), uintptr(newfd), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1416,7 +1408,7 @@
 func Fchown(fd int, uid int, gid int) (err error) {
 	_, _, e1 := Syscall(SYS_FCHOWN32, uintptr(fd), uintptr(uid), uintptr(gid))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1426,7 +1418,7 @@
 func Fstat(fd int, stat *Stat_t) (err error) {
 	_, _, e1 := Syscall(SYS_FSTAT64, uintptr(fd), uintptr(unsafe.Pointer(stat)), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1474,7 +1466,7 @@
 	_, _, e1 := Syscall(SYS_LCHOWN32, uintptr(unsafe.Pointer(_p0)), uintptr(uid), uintptr(gid))
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1484,7 +1476,7 @@
 func Listen(s int, n int) (err error) {
 	_, _, e1 := Syscall(SYS_LISTEN, uintptr(s), uintptr(n), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1500,7 +1492,7 @@
 	_, _, e1 := Syscall(SYS_LSTAT64, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1511,7 +1503,7 @@
 	r0, _, e1 := Syscall6(SYS_SENDFILE64, uintptr(outfd), uintptr(infd), uintptr(unsafe.Pointer(offset)), uintptr(count), 0, 0)
 	written = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1522,7 +1514,7 @@
 	r0, _, e1 := Syscall6(SYS__NEWSELECT, uintptr(nfd), uintptr(unsafe.Pointer(r)), uintptr(unsafe.Pointer(w)), uintptr(unsafe.Pointer(e)), uintptr(unsafe.Pointer(timeout)), 0)
 	n = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1532,7 +1524,7 @@
 func Setfsgid(gid int) (err error) {
 	_, _, e1 := Syscall(SYS_SETFSGID32, uintptr(gid), 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1542,7 +1534,7 @@
 func Setfsuid(uid int) (err error) {
 	_, _, e1 := Syscall(SYS_SETFSUID32, uintptr(uid), 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1552,7 +1544,7 @@
 func Setregid(rgid int, egid int) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETREGID32, uintptr(rgid), uintptr(egid), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1562,7 +1554,7 @@
 func Setresgid(rgid int, egid int, sgid int) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETRESGID32, uintptr(rgid), uintptr(egid), uintptr(sgid))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1572,7 +1564,7 @@
 func Setresuid(ruid int, euid int, suid int) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETRESUID32, uintptr(ruid), uintptr(euid), uintptr(suid))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1582,7 +1574,7 @@
 func Setreuid(ruid int, euid int) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETREUID32, uintptr(ruid), uintptr(euid), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1592,7 +1584,7 @@
 func Shutdown(fd int, how int) (err error) {
 	_, _, e1 := Syscall(SYS_SHUTDOWN, uintptr(fd), uintptr(how), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1603,7 +1595,7 @@
 	r0, _, e1 := Syscall6(SYS_SPLICE, uintptr(rfd), uintptr(unsafe.Pointer(roff)), uintptr(wfd), uintptr(unsafe.Pointer(woff)), uintptr(len), uintptr(flags))
 	n = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1619,7 +1611,7 @@
 	_, _, e1 := Syscall(SYS_STAT64, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1629,7 +1621,7 @@
 func Gettimeofday(tv *Timeval) (err error) {
 	_, _, e1 := RawSyscall(SYS_GETTIMEOFDAY, uintptr(unsafe.Pointer(tv)), 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1640,7 +1632,7 @@
 	r0, _, e1 := RawSyscall(SYS_TIME, uintptr(unsafe.Pointer(t)), 0, 0)
 	tt = Time_t(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1657,7 +1649,7 @@
 	r0, _, e1 := Syscall6(SYS_PREAD64, uintptr(fd), uintptr(_p0), uintptr(len(p)), 0, uintptr(offset), uintptr(offset>>32))
 	n = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1674,7 +1666,7 @@
 	r0, _, e1 := Syscall6(SYS_PWRITE64, uintptr(fd), uintptr(_p0), uintptr(len(p)), 0, uintptr(offset), uintptr(offset>>32))
 	n = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1690,7 +1682,7 @@
 	_, _, e1 := Syscall6(SYS_TRUNCATE64, uintptr(unsafe.Pointer(_p0)), 0, uintptr(length), uintptr(length>>32), 0, 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1700,7 +1692,7 @@
 func Ftruncate(fd int, length int64) (err error) {
 	_, _, e1 := Syscall6(SYS_FTRUNCATE64, uintptr(fd), 0, uintptr(length), uintptr(length>>32), 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1711,7 +1703,7 @@
 	r0, _, e1 := Syscall6(SYS_MMAP2, uintptr(addr), uintptr(length), uintptr(prot), uintptr(flags), uintptr(fd), uintptr(pageOffset))
 	xaddr = uintptr(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1721,7 +1713,7 @@
 func getrlimit(resource int, rlim *rlimit32) (err error) {
 	_, _, e1 := RawSyscall(SYS_GETRLIMIT, uintptr(resource), uintptr(unsafe.Pointer(rlim)), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1731,7 +1723,7 @@
 func setrlimit(resource int, rlim *rlimit32) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETRLIMIT, uintptr(resource), uintptr(unsafe.Pointer(rlim)), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
diff --git a/src/syscall/zsyscall_linux_arm64.go b/src/syscall/zsyscall_linux_arm64.go
new file mode 100644
index 0000000..26a14b7
--- /dev/null
+++ b/src/syscall/zsyscall_linux_arm64.go
@@ -0,0 +1,1750 @@
+// mksyscall.pl syscall_linux.go syscall_linux_arm64.go
+// MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
+
+package syscall
+
+import "unsafe"
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func linkat(olddirfd int, oldpath string, newdirfd int, newpath string, flags int) (err error) {
+	var _p0 *byte
+	_p0, err = BytePtrFromString(oldpath)
+	if err != nil {
+		return
+	}
+	var _p1 *byte
+	_p1, err = BytePtrFromString(newpath)
+	if err != nil {
+		return
+	}
+	_, _, e1 := Syscall6(SYS_LINKAT, uintptr(olddirfd), uintptr(unsafe.Pointer(_p0)), uintptr(newdirfd), uintptr(unsafe.Pointer(_p1)), uintptr(flags), 0)
+	use(unsafe.Pointer(_p0))
+	use(unsafe.Pointer(_p1))
+	if e1 != 0 {
+		err = errnoErr(e1)
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func openat(dirfd int, path string, flags int, mode uint32) (fd int, err error) {
+	var _p0 *byte
+	_p0, err = BytePtrFromString(path)
+	if err != nil {
+		return
+	}
+	r0, _, e1 := Syscall6(SYS_OPENAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(flags), uintptr(mode), 0, 0)
+	use(unsafe.Pointer(_p0))
+	fd = int(r0)
+	if e1 != 0 {
+		err = errnoErr(e1)
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func readlinkat(dirfd int, path string, buf []byte) (n int, err error) {
+	var _p0 *byte
+	_p0, err = BytePtrFromString(path)
+	if err != nil {
+		return
+	}
+	var _p1 unsafe.Pointer
+	if len(buf) > 0 {
+		_p1 = unsafe.Pointer(&buf[0])
+	} else {
+		_p1 = unsafe.Pointer(&_zero)
+	}
+	r0, _, e1 := Syscall6(SYS_READLINKAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(_p1), uintptr(len(buf)), 0, 0)
+	use(unsafe.Pointer(_p0))
+	n = int(r0)
+	if e1 != 0 {
+		err = errnoErr(e1)
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func symlinkat(oldpath string, newdirfd int, newpath string) (err error) {
+	var _p0 *byte
+	_p0, err = BytePtrFromString(oldpath)
+	if err != nil {
+		return
+	}
+	var _p1 *byte
+	_p1, err = BytePtrFromString(newpath)
+	if err != nil {
+		return
+	}
+	_, _, e1 := Syscall(SYS_SYMLINKAT, uintptr(unsafe.Pointer(_p0)), uintptr(newdirfd), uintptr(unsafe.Pointer(_p1)))
+	use(unsafe.Pointer(_p0))
+	use(unsafe.Pointer(_p1))
+	if e1 != 0 {
+		err = errnoErr(e1)
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func unlinkat(dirfd int, path string, flags int) (err error) {
+	var _p0 *byte
+	_p0, err = BytePtrFromString(path)
+	if err != nil {
+		return
+	}
+	_, _, e1 := Syscall(SYS_UNLINKAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(flags))
+	use(unsafe.Pointer(_p0))
+	if e1 != 0 {
+		err = errnoErr(e1)
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func utimes(path string, times *[2]Timeval) (err error) {
+	var _p0 *byte
+	_p0, err = BytePtrFromString(path)
+	if err != nil {
+		return
+	}
+	_, _, e1 := Syscall(SYS_UTIMES, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(times)), 0)
+	use(unsafe.Pointer(_p0))
+	if e1 != 0 {
+		err = errnoErr(e1)
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func utimensat(dirfd int, path string, times *[2]Timespec) (err error) {
+	var _p0 *byte
+	_p0, err = BytePtrFromString(path)
+	if err != nil {
+		return
+	}
+	_, _, e1 := Syscall(SYS_UTIMENSAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(times)))
+	use(unsafe.Pointer(_p0))
+	if e1 != 0 {
+		err = errnoErr(e1)
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func futimesat(dirfd int, path *byte, times *[2]Timeval) (err error) {
+	_, _, e1 := Syscall(SYS_FUTIMESAT, uintptr(dirfd), uintptr(unsafe.Pointer(path)), uintptr(unsafe.Pointer(times)))
+	if e1 != 0 {
+		err = errnoErr(e1)
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Getcwd(buf []byte) (n int, err error) {
+	var _p0 unsafe.Pointer
+	if len(buf) > 0 {
+		_p0 = unsafe.Pointer(&buf[0])
+	} else {
+		_p0 = unsafe.Pointer(&_zero)
+	}
+	r0, _, e1 := Syscall(SYS_GETCWD, uintptr(_p0), uintptr(len(buf)), 0)
+	n = int(r0)
+	if e1 != 0 {
+		err = errnoErr(e1)
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func wait4(pid int, wstatus *_C_int, options int, rusage *Rusage) (wpid int, err error) {
+	r0, _, e1 := Syscall6(SYS_WAIT4, uintptr(pid), uintptr(unsafe.Pointer(wstatus)), uintptr(options), uintptr(unsafe.Pointer(rusage)), 0, 0)
+	wpid = int(r0)
+	if e1 != 0 {
+		err = errnoErr(e1)
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func ptrace(request int, pid int, addr uintptr, data uintptr) (err error) {
+	_, _, e1 := Syscall6(SYS_PTRACE, uintptr(request), uintptr(pid), uintptr(addr), uintptr(data), 0, 0)
+	if e1 != 0 {
+		err = errnoErr(e1)
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func reboot(magic1 uint, magic2 uint, cmd int, arg string) (err error) {
+	var _p0 *byte
+	_p0, err = BytePtrFromString(arg)
+	if err != nil {
+		return
+	}
+	_, _, e1 := Syscall6(SYS_REBOOT, uintptr(magic1), uintptr(magic2), uintptr(cmd), uintptr(unsafe.Pointer(_p0)), 0, 0)
+	use(unsafe.Pointer(_p0))
+	if e1 != 0 {
+		err = errnoErr(e1)
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func mount(source string, target string, fstype string, flags uintptr, data *byte) (err error) {
+	var _p0 *byte
+	_p0, err = BytePtrFromString(source)
+	if err != nil {
+		return
+	}
+	var _p1 *byte
+	_p1, err = BytePtrFromString(target)
+	if err != nil {
+		return
+	}
+	var _p2 *byte
+	_p2, err = BytePtrFromString(fstype)
+	if err != nil {
+		return
+	}
+	_, _, e1 := Syscall6(SYS_MOUNT, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), uintptr(unsafe.Pointer(_p2)), uintptr(flags), uintptr(unsafe.Pointer(data)), 0)
+	use(unsafe.Pointer(_p0))
+	use(unsafe.Pointer(_p1))
+	use(unsafe.Pointer(_p2))
+	if e1 != 0 {
+		err = errnoErr(e1)
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Acct(path string) (err error) {
+	var _p0 *byte
+	_p0, err = BytePtrFromString(path)
+	if err != nil {
+		return
+	}
+	_, _, e1 := Syscall(SYS_ACCT, uintptr(unsafe.Pointer(_p0)), 0, 0)
+	use(unsafe.Pointer(_p0))
+	if e1 != 0 {
+		err = errnoErr(e1)
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Adjtimex(buf *Timex) (state int, err error) {
+	r0, _, e1 := Syscall(SYS_ADJTIMEX, uintptr(unsafe.Pointer(buf)), 0, 0)
+	state = int(r0)
+	if e1 != 0 {
+		err = errnoErr(e1)
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Chdir(path string) (err error) {
+	var _p0 *byte
+	_p0, err = BytePtrFromString(path)
+	if err != nil {
+		return
+	}
+	_, _, e1 := Syscall(SYS_CHDIR, uintptr(unsafe.Pointer(_p0)), 0, 0)
+	use(unsafe.Pointer(_p0))
+	if e1 != 0 {
+		err = errnoErr(e1)
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Chroot(path string) (err error) {
+	var _p0 *byte
+	_p0, err = BytePtrFromString(path)
+	if err != nil {
+		return
+	}
+	_, _, e1 := Syscall(SYS_CHROOT, uintptr(unsafe.Pointer(_p0)), 0, 0)
+	use(unsafe.Pointer(_p0))
+	if e1 != 0 {
+		err = errnoErr(e1)
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Close(fd int) (err error) {
+	_, _, e1 := Syscall(SYS_CLOSE, uintptr(fd), 0, 0)
+	if e1 != 0 {
+		err = errnoErr(e1)
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Dup(oldfd int) (fd int, err error) {
+	r0, _, e1 := Syscall(SYS_DUP, uintptr(oldfd), 0, 0)
+	fd = int(r0)
+	if e1 != 0 {
+		err = errnoErr(e1)
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Dup3(oldfd int, newfd int, flags int) (err error) {
+	_, _, e1 := Syscall(SYS_DUP3, uintptr(oldfd), uintptr(newfd), uintptr(flags))
+	if e1 != 0 {
+		err = errnoErr(e1)
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func EpollCreate(size int) (fd int, err error) {
+	r0, _, e1 := RawSyscall(SYS_EPOLL_CREATE, uintptr(size), 0, 0)
+	fd = int(r0)
+	if e1 != 0 {
+		err = errnoErr(e1)
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func EpollCreate1(flag int) (fd int, err error) {
+	r0, _, e1 := RawSyscall(SYS_EPOLL_CREATE1, uintptr(flag), 0, 0)
+	fd = int(r0)
+	if e1 != 0 {
+		err = errnoErr(e1)
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func EpollCtl(epfd int, op int, fd int, event *EpollEvent) (err error) {
+	_, _, e1 := RawSyscall6(SYS_EPOLL_CTL, uintptr(epfd), uintptr(op), uintptr(fd), uintptr(unsafe.Pointer(event)), 0, 0)
+	if e1 != 0 {
+		err = errnoErr(e1)
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func EpollWait(epfd int, events []EpollEvent, msec int) (n int, err error) {
+	var _p0 unsafe.Pointer
+	if len(events) > 0 {
+		_p0 = unsafe.Pointer(&events[0])
+	} else {
+		_p0 = unsafe.Pointer(&_zero)
+	}
+	r0, _, e1 := Syscall6(SYS_EPOLL_WAIT, uintptr(epfd), uintptr(_p0), uintptr(len(events)), uintptr(msec), 0, 0)
+	n = int(r0)
+	if e1 != 0 {
+		err = errnoErr(e1)
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Exit(code int) {
+	Syscall(SYS_EXIT_GROUP, uintptr(code), 0, 0)
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Faccessat(dirfd int, path string, mode uint32, flags int) (err error) {
+	var _p0 *byte
+	_p0, err = BytePtrFromString(path)
+	if err != nil {
+		return
+	}
+	_, _, e1 := Syscall6(SYS_FACCESSAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(flags), 0, 0)
+	use(unsafe.Pointer(_p0))
+	if e1 != 0 {
+		err = errnoErr(e1)
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Fallocate(fd int, mode uint32, off int64, len int64) (err error) {
+	_, _, e1 := Syscall6(SYS_FALLOCATE, uintptr(fd), uintptr(mode), uintptr(off), uintptr(len), 0, 0)
+	if e1 != 0 {
+		err = errnoErr(e1)
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Fchdir(fd int) (err error) {
+	_, _, e1 := Syscall(SYS_FCHDIR, uintptr(fd), 0, 0)
+	if e1 != 0 {
+		err = errnoErr(e1)
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Fchmod(fd int, mode uint32) (err error) {
+	_, _, e1 := Syscall(SYS_FCHMOD, uintptr(fd), uintptr(mode), 0)
+	if e1 != 0 {
+		err = errnoErr(e1)
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Fchmodat(dirfd int, path string, mode uint32, flags int) (err error) {
+	var _p0 *byte
+	_p0, err = BytePtrFromString(path)
+	if err != nil {
+		return
+	}
+	_, _, e1 := Syscall6(SYS_FCHMODAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(flags), 0, 0)
+	use(unsafe.Pointer(_p0))
+	if e1 != 0 {
+		err = errnoErr(e1)
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Fchownat(dirfd int, path string, uid int, gid int, flags int) (err error) {
+	var _p0 *byte
+	_p0, err = BytePtrFromString(path)
+	if err != nil {
+		return
+	}
+	_, _, e1 := Syscall6(SYS_FCHOWNAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(uid), uintptr(gid), uintptr(flags), 0)
+	use(unsafe.Pointer(_p0))
+	if e1 != 0 {
+		err = errnoErr(e1)
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func fcntl(fd int, cmd int, arg int) (val int, err error) {
+	r0, _, e1 := Syscall(SYS_FCNTL, uintptr(fd), uintptr(cmd), uintptr(arg))
+	val = int(r0)
+	if e1 != 0 {
+		err = errnoErr(e1)
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Fdatasync(fd int) (err error) {
+	_, _, e1 := Syscall(SYS_FDATASYNC, uintptr(fd), 0, 0)
+	if e1 != 0 {
+		err = errnoErr(e1)
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Flock(fd int, how int) (err error) {
+	_, _, e1 := Syscall(SYS_FLOCK, uintptr(fd), uintptr(how), 0)
+	if e1 != 0 {
+		err = errnoErr(e1)
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Fsync(fd int) (err error) {
+	_, _, e1 := Syscall(SYS_FSYNC, uintptr(fd), 0, 0)
+	if e1 != 0 {
+		err = errnoErr(e1)
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Getdents(fd int, buf []byte) (n int, err error) {
+	var _p0 unsafe.Pointer
+	if len(buf) > 0 {
+		_p0 = unsafe.Pointer(&buf[0])
+	} else {
+		_p0 = unsafe.Pointer(&_zero)
+	}
+	r0, _, e1 := Syscall(SYS_GETDENTS64, uintptr(fd), uintptr(_p0), uintptr(len(buf)))
+	n = int(r0)
+	if e1 != 0 {
+		err = errnoErr(e1)
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Getpgid(pid int) (pgid int, err error) {
+	r0, _, e1 := RawSyscall(SYS_GETPGID, uintptr(pid), 0, 0)
+	pgid = int(r0)
+	if e1 != 0 {
+		err = errnoErr(e1)
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Getpid() (pid int) {
+	r0, _, _ := RawSyscall(SYS_GETPID, 0, 0, 0)
+	pid = int(r0)
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Getppid() (ppid int) {
+	r0, _, _ := RawSyscall(SYS_GETPPID, 0, 0, 0)
+	ppid = int(r0)
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Getpriority(which int, who int) (prio int, err error) {
+	r0, _, e1 := Syscall(SYS_GETPRIORITY, uintptr(which), uintptr(who), 0)
+	prio = int(r0)
+	if e1 != 0 {
+		err = errnoErr(e1)
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Getrusage(who int, rusage *Rusage) (err error) {
+	_, _, e1 := RawSyscall(SYS_GETRUSAGE, uintptr(who), uintptr(unsafe.Pointer(rusage)), 0)
+	if e1 != 0 {
+		err = errnoErr(e1)
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Gettid() (tid int) {
+	r0, _, _ := RawSyscall(SYS_GETTID, 0, 0, 0)
+	tid = int(r0)
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Getxattr(path string, attr string, dest []byte) (sz int, err error) {
+	var _p0 *byte
+	_p0, err = BytePtrFromString(path)
+	if err != nil {
+		return
+	}
+	var _p1 *byte
+	_p1, err = BytePtrFromString(attr)
+	if err != nil {
+		return
+	}
+	var _p2 unsafe.Pointer
+	if len(dest) > 0 {
+		_p2 = unsafe.Pointer(&dest[0])
+	} else {
+		_p2 = unsafe.Pointer(&_zero)
+	}
+	r0, _, e1 := Syscall6(SYS_GETXATTR, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), uintptr(_p2), uintptr(len(dest)), 0, 0)
+	use(unsafe.Pointer(_p0))
+	use(unsafe.Pointer(_p1))
+	sz = int(r0)
+	if e1 != 0 {
+		err = errnoErr(e1)
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func InotifyAddWatch(fd int, pathname string, mask uint32) (watchdesc int, err error) {
+	var _p0 *byte
+	_p0, err = BytePtrFromString(pathname)
+	if err != nil {
+		return
+	}
+	r0, _, e1 := Syscall(SYS_INOTIFY_ADD_WATCH, uintptr(fd), uintptr(unsafe.Pointer(_p0)), uintptr(mask))
+	use(unsafe.Pointer(_p0))
+	watchdesc = int(r0)
+	if e1 != 0 {
+		err = errnoErr(e1)
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func InotifyInit() (fd int, err error) {
+	r0, _, e1 := RawSyscall(SYS_INOTIFY_INIT, 0, 0, 0)
+	fd = int(r0)
+	if e1 != 0 {
+		err = errnoErr(e1)
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func InotifyInit1(flags int) (fd int, err error) {
+	r0, _, e1 := RawSyscall(SYS_INOTIFY_INIT1, uintptr(flags), 0, 0)
+	fd = int(r0)
+	if e1 != 0 {
+		err = errnoErr(e1)
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func InotifyRmWatch(fd int, watchdesc uint32) (success int, err error) {
+	r0, _, e1 := RawSyscall(SYS_INOTIFY_RM_WATCH, uintptr(fd), uintptr(watchdesc), 0)
+	success = int(r0)
+	if e1 != 0 {
+		err = errnoErr(e1)
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Kill(pid int, sig Signal) (err error) {
+	_, _, e1 := RawSyscall(SYS_KILL, uintptr(pid), uintptr(sig), 0)
+	if e1 != 0 {
+		err = errnoErr(e1)
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Klogctl(typ int, buf []byte) (n int, err error) {
+	var _p0 unsafe.Pointer
+	if len(buf) > 0 {
+		_p0 = unsafe.Pointer(&buf[0])
+	} else {
+		_p0 = unsafe.Pointer(&_zero)
+	}
+	r0, _, e1 := Syscall(SYS_SYSLOG, uintptr(typ), uintptr(_p0), uintptr(len(buf)))
+	n = int(r0)
+	if e1 != 0 {
+		err = errnoErr(e1)
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Listxattr(path string, dest []byte) (sz int, err error) {
+	var _p0 *byte
+	_p0, err = BytePtrFromString(path)
+	if err != nil {
+		return
+	}
+	var _p1 unsafe.Pointer
+	if len(dest) > 0 {
+		_p1 = unsafe.Pointer(&dest[0])
+	} else {
+		_p1 = unsafe.Pointer(&_zero)
+	}
+	r0, _, e1 := Syscall(SYS_LISTXATTR, uintptr(unsafe.Pointer(_p0)), uintptr(_p1), uintptr(len(dest)))
+	use(unsafe.Pointer(_p0))
+	sz = int(r0)
+	if e1 != 0 {
+		err = errnoErr(e1)
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Mkdirat(dirfd int, path string, mode uint32) (err error) {
+	var _p0 *byte
+	_p0, err = BytePtrFromString(path)
+	if err != nil {
+		return
+	}
+	_, _, e1 := Syscall(SYS_MKDIRAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode))
+	use(unsafe.Pointer(_p0))
+	if e1 != 0 {
+		err = errnoErr(e1)
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Mknodat(dirfd int, path string, mode uint32, dev int) (err error) {
+	var _p0 *byte
+	_p0, err = BytePtrFromString(path)
+	if err != nil {
+		return
+	}
+	_, _, e1 := Syscall6(SYS_MKNODAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(dev), 0, 0)
+	use(unsafe.Pointer(_p0))
+	if e1 != 0 {
+		err = errnoErr(e1)
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Nanosleep(time *Timespec, leftover *Timespec) (err error) {
+	_, _, e1 := Syscall(SYS_NANOSLEEP, uintptr(unsafe.Pointer(time)), uintptr(unsafe.Pointer(leftover)), 0)
+	if e1 != 0 {
+		err = errnoErr(e1)
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Pause() (err error) {
+	_, _, e1 := Syscall(SYS_PAUSE, 0, 0, 0)
+	if e1 != 0 {
+		err = errnoErr(e1)
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func PivotRoot(newroot string, putold string) (err error) {
+	var _p0 *byte
+	_p0, err = BytePtrFromString(newroot)
+	if err != nil {
+		return
+	}
+	var _p1 *byte
+	_p1, err = BytePtrFromString(putold)
+	if err != nil {
+		return
+	}
+	_, _, e1 := Syscall(SYS_PIVOT_ROOT, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), 0)
+	use(unsafe.Pointer(_p0))
+	use(unsafe.Pointer(_p1))
+	if e1 != 0 {
+		err = errnoErr(e1)
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func prlimit(pid int, resource int, old *Rlimit, newlimit *Rlimit) (err error) {
+	_, _, e1 := RawSyscall6(SYS_PRLIMIT64, uintptr(pid), uintptr(resource), uintptr(unsafe.Pointer(old)), uintptr(unsafe.Pointer(newlimit)), 0, 0)
+	if e1 != 0 {
+		err = errnoErr(e1)
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func read(fd int, p []byte) (n int, err error) {
+	var _p0 unsafe.Pointer
+	if len(p) > 0 {
+		_p0 = unsafe.Pointer(&p[0])
+	} else {
+		_p0 = unsafe.Pointer(&_zero)
+	}
+	r0, _, e1 := Syscall(SYS_READ, uintptr(fd), uintptr(_p0), uintptr(len(p)))
+	n = int(r0)
+	if e1 != 0 {
+		err = errnoErr(e1)
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Removexattr(path string, attr string) (err error) {
+	var _p0 *byte
+	_p0, err = BytePtrFromString(path)
+	if err != nil {
+		return
+	}
+	var _p1 *byte
+	_p1, err = BytePtrFromString(attr)
+	if err != nil {
+		return
+	}
+	_, _, e1 := Syscall(SYS_REMOVEXATTR, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), 0)
+	use(unsafe.Pointer(_p0))
+	use(unsafe.Pointer(_p1))
+	if e1 != 0 {
+		err = errnoErr(e1)
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Renameat(olddirfd int, oldpath string, newdirfd int, newpath string) (err error) {
+	var _p0 *byte
+	_p0, err = BytePtrFromString(oldpath)
+	if err != nil {
+		return
+	}
+	var _p1 *byte
+	_p1, err = BytePtrFromString(newpath)
+	if err != nil {
+		return
+	}
+	_, _, e1 := Syscall6(SYS_RENAMEAT, uintptr(olddirfd), uintptr(unsafe.Pointer(_p0)), uintptr(newdirfd), uintptr(unsafe.Pointer(_p1)), 0, 0)
+	use(unsafe.Pointer(_p0))
+	use(unsafe.Pointer(_p1))
+	if e1 != 0 {
+		err = errnoErr(e1)
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Setdomainname(p []byte) (err error) {
+	var _p0 unsafe.Pointer
+	if len(p) > 0 {
+		_p0 = unsafe.Pointer(&p[0])
+	} else {
+		_p0 = unsafe.Pointer(&_zero)
+	}
+	_, _, e1 := Syscall(SYS_SETDOMAINNAME, uintptr(_p0), uintptr(len(p)), 0)
+	if e1 != 0 {
+		err = errnoErr(e1)
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Sethostname(p []byte) (err error) {
+	var _p0 unsafe.Pointer
+	if len(p) > 0 {
+		_p0 = unsafe.Pointer(&p[0])
+	} else {
+		_p0 = unsafe.Pointer(&_zero)
+	}
+	_, _, e1 := Syscall(SYS_SETHOSTNAME, uintptr(_p0), uintptr(len(p)), 0)
+	if e1 != 0 {
+		err = errnoErr(e1)
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Setpgid(pid int, pgid int) (err error) {
+	_, _, e1 := RawSyscall(SYS_SETPGID, uintptr(pid), uintptr(pgid), 0)
+	if e1 != 0 {
+		err = errnoErr(e1)
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Setsid() (pid int, err error) {
+	r0, _, e1 := RawSyscall(SYS_SETSID, 0, 0, 0)
+	pid = int(r0)
+	if e1 != 0 {
+		err = errnoErr(e1)
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Settimeofday(tv *Timeval) (err error) {
+	_, _, e1 := RawSyscall(SYS_SETTIMEOFDAY, uintptr(unsafe.Pointer(tv)), 0, 0)
+	if e1 != 0 {
+		err = errnoErr(e1)
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Setpriority(which int, who int, prio int) (err error) {
+	_, _, e1 := Syscall(SYS_SETPRIORITY, uintptr(which), uintptr(who), uintptr(prio))
+	if e1 != 0 {
+		err = errnoErr(e1)
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Setxattr(path string, attr string, data []byte, flags int) (err error) {
+	var _p0 *byte
+	_p0, err = BytePtrFromString(path)
+	if err != nil {
+		return
+	}
+	var _p1 *byte
+	_p1, err = BytePtrFromString(attr)
+	if err != nil {
+		return
+	}
+	var _p2 unsafe.Pointer
+	if len(data) > 0 {
+		_p2 = unsafe.Pointer(&data[0])
+	} else {
+		_p2 = unsafe.Pointer(&_zero)
+	}
+	_, _, e1 := Syscall6(SYS_SETXATTR, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), uintptr(_p2), uintptr(len(data)), uintptr(flags), 0)
+	use(unsafe.Pointer(_p0))
+	use(unsafe.Pointer(_p1))
+	if e1 != 0 {
+		err = errnoErr(e1)
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Sync() {
+	Syscall(SYS_SYNC, 0, 0, 0)
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Sysinfo(info *Sysinfo_t) (err error) {
+	_, _, e1 := RawSyscall(SYS_SYSINFO, uintptr(unsafe.Pointer(info)), 0, 0)
+	if e1 != 0 {
+		err = errnoErr(e1)
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Tee(rfd int, wfd int, len int, flags int) (n int64, err error) {
+	r0, _, e1 := Syscall6(SYS_TEE, uintptr(rfd), uintptr(wfd), uintptr(len), uintptr(flags), 0, 0)
+	n = int64(r0)
+	if e1 != 0 {
+		err = errnoErr(e1)
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Tgkill(tgid int, tid int, sig Signal) (err error) {
+	_, _, e1 := RawSyscall(SYS_TGKILL, uintptr(tgid), uintptr(tid), uintptr(sig))
+	if e1 != 0 {
+		err = errnoErr(e1)
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Times(tms *Tms) (ticks uintptr, err error) {
+	r0, _, e1 := RawSyscall(SYS_TIMES, uintptr(unsafe.Pointer(tms)), 0, 0)
+	ticks = uintptr(r0)
+	if e1 != 0 {
+		err = errnoErr(e1)
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Umask(mask int) (oldmask int) {
+	r0, _, _ := RawSyscall(SYS_UMASK, uintptr(mask), 0, 0)
+	oldmask = int(r0)
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Uname(buf *Utsname) (err error) {
+	_, _, e1 := RawSyscall(SYS_UNAME, uintptr(unsafe.Pointer(buf)), 0, 0)
+	if e1 != 0 {
+		err = errnoErr(e1)
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Unmount(target string, flags int) (err error) {
+	var _p0 *byte
+	_p0, err = BytePtrFromString(target)
+	if err != nil {
+		return
+	}
+	_, _, e1 := Syscall(SYS_UMOUNT2, uintptr(unsafe.Pointer(_p0)), uintptr(flags), 0)
+	use(unsafe.Pointer(_p0))
+	if e1 != 0 {
+		err = errnoErr(e1)
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Unshare(flags int) (err error) {
+	_, _, e1 := Syscall(SYS_UNSHARE, uintptr(flags), 0, 0)
+	if e1 != 0 {
+		err = errnoErr(e1)
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Ustat(dev int, ubuf *Ustat_t) (err error) {
+	_, _, e1 := Syscall(SYS_USTAT, uintptr(dev), uintptr(unsafe.Pointer(ubuf)), 0)
+	if e1 != 0 {
+		err = errnoErr(e1)
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Utime(path string, buf *Utimbuf) (err error) {
+	var _p0 *byte
+	_p0, err = BytePtrFromString(path)
+	if err != nil {
+		return
+	}
+	_, _, e1 := Syscall(SYS_UTIME, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(buf)), 0)
+	use(unsafe.Pointer(_p0))
+	if e1 != 0 {
+		err = errnoErr(e1)
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func write(fd int, p []byte) (n int, err error) {
+	var _p0 unsafe.Pointer
+	if len(p) > 0 {
+		_p0 = unsafe.Pointer(&p[0])
+	} else {
+		_p0 = unsafe.Pointer(&_zero)
+	}
+	r0, _, e1 := Syscall(SYS_WRITE, uintptr(fd), uintptr(_p0), uintptr(len(p)))
+	n = int(r0)
+	if e1 != 0 {
+		err = errnoErr(e1)
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func exitThread(code int) (err error) {
+	_, _, e1 := Syscall(SYS_EXIT, uintptr(code), 0, 0)
+	if e1 != 0 {
+		err = errnoErr(e1)
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func readlen(fd int, p *byte, np int) (n int, err error) {
+	r0, _, e1 := Syscall(SYS_READ, uintptr(fd), uintptr(unsafe.Pointer(p)), uintptr(np))
+	n = int(r0)
+	if e1 != 0 {
+		err = errnoErr(e1)
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func writelen(fd int, p *byte, np int) (n int, err error) {
+	r0, _, e1 := Syscall(SYS_WRITE, uintptr(fd), uintptr(unsafe.Pointer(p)), uintptr(np))
+	n = int(r0)
+	if e1 != 0 {
+		err = errnoErr(e1)
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func munmap(addr uintptr, length uintptr) (err error) {
+	_, _, e1 := Syscall(SYS_MUNMAP, uintptr(addr), uintptr(length), 0)
+	if e1 != 0 {
+		err = errnoErr(e1)
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Madvise(b []byte, advice int) (err error) {
+	var _p0 unsafe.Pointer
+	if len(b) > 0 {
+		_p0 = unsafe.Pointer(&b[0])
+	} else {
+		_p0 = unsafe.Pointer(&_zero)
+	}
+	_, _, e1 := Syscall(SYS_MADVISE, uintptr(_p0), uintptr(len(b)), uintptr(advice))
+	if e1 != 0 {
+		err = errnoErr(e1)
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Mprotect(b []byte, prot int) (err error) {
+	var _p0 unsafe.Pointer
+	if len(b) > 0 {
+		_p0 = unsafe.Pointer(&b[0])
+	} else {
+		_p0 = unsafe.Pointer(&_zero)
+	}
+	_, _, e1 := Syscall(SYS_MPROTECT, uintptr(_p0), uintptr(len(b)), uintptr(prot))
+	if e1 != 0 {
+		err = errnoErr(e1)
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Mlock(b []byte) (err error) {
+	var _p0 unsafe.Pointer
+	if len(b) > 0 {
+		_p0 = unsafe.Pointer(&b[0])
+	} else {
+		_p0 = unsafe.Pointer(&_zero)
+	}
+	_, _, e1 := Syscall(SYS_MLOCK, uintptr(_p0), uintptr(len(b)), 0)
+	if e1 != 0 {
+		err = errnoErr(e1)
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Munlock(b []byte) (err error) {
+	var _p0 unsafe.Pointer
+	if len(b) > 0 {
+		_p0 = unsafe.Pointer(&b[0])
+	} else {
+		_p0 = unsafe.Pointer(&_zero)
+	}
+	_, _, e1 := Syscall(SYS_MUNLOCK, uintptr(_p0), uintptr(len(b)), 0)
+	if e1 != 0 {
+		err = errnoErr(e1)
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Mlockall(flags int) (err error) {
+	_, _, e1 := Syscall(SYS_MLOCKALL, uintptr(flags), 0, 0)
+	if e1 != 0 {
+		err = errnoErr(e1)
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Munlockall() (err error) {
+	_, _, e1 := Syscall(SYS_MUNLOCKALL, 0, 0, 0)
+	if e1 != 0 {
+		err = errnoErr(e1)
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Fchown(fd int, uid int, gid int) (err error) {
+	_, _, e1 := Syscall(SYS_FCHOWN, uintptr(fd), uintptr(uid), uintptr(gid))
+	if e1 != 0 {
+		err = errnoErr(e1)
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Fstat(fd int, stat *Stat_t) (err error) {
+	_, _, e1 := Syscall(SYS_FSTAT, uintptr(fd), uintptr(unsafe.Pointer(stat)), 0)
+	if e1 != 0 {
+		err = errnoErr(e1)
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Fstatat(fd int, path string, stat *Stat_t, flags int) (err error) {
+	var _p0 *byte
+	_p0, err = BytePtrFromString(path)
+	if err != nil {
+		return
+	}
+	_, _, e1 := Syscall6(SYS_FSTATAT, uintptr(fd), uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), uintptr(flags), 0, 0)
+	use(unsafe.Pointer(_p0))
+	if e1 != 0 {
+		err = errnoErr(e1)
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Fstatfs(fd int, buf *Statfs_t) (err error) {
+	_, _, e1 := Syscall(SYS_FSTATFS, uintptr(fd), uintptr(unsafe.Pointer(buf)), 0)
+	if e1 != 0 {
+		err = errnoErr(e1)
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Ftruncate(fd int, length int64) (err error) {
+	_, _, e1 := Syscall(SYS_FTRUNCATE, uintptr(fd), uintptr(length), 0)
+	if e1 != 0 {
+		err = errnoErr(e1)
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Getegid() (egid int) {
+	r0, _, _ := RawSyscall(SYS_GETEGID, 0, 0, 0)
+	egid = int(r0)
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Geteuid() (euid int) {
+	r0, _, _ := RawSyscall(SYS_GETEUID, 0, 0, 0)
+	euid = int(r0)
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Getgid() (gid int) {
+	r0, _, _ := RawSyscall(SYS_GETGID, 0, 0, 0)
+	gid = int(r0)
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Getrlimit(resource int, rlim *Rlimit) (err error) {
+	_, _, e1 := RawSyscall(SYS_GETRLIMIT, uintptr(resource), uintptr(unsafe.Pointer(rlim)), 0)
+	if e1 != 0 {
+		err = errnoErr(e1)
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Getuid() (uid int) {
+	r0, _, _ := RawSyscall(SYS_GETUID, 0, 0, 0)
+	uid = int(r0)
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Lchown(path string, uid int, gid int) (err error) {
+	var _p0 *byte
+	_p0, err = BytePtrFromString(path)
+	if err != nil {
+		return
+	}
+	_, _, e1 := Syscall(SYS_LCHOWN, uintptr(unsafe.Pointer(_p0)), uintptr(uid), uintptr(gid))
+	use(unsafe.Pointer(_p0))
+	if e1 != 0 {
+		err = errnoErr(e1)
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Listen(s int, n int) (err error) {
+	_, _, e1 := Syscall(SYS_LISTEN, uintptr(s), uintptr(n), 0)
+	if e1 != 0 {
+		err = errnoErr(e1)
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Pread(fd int, p []byte, offset int64) (n int, err error) {
+	var _p0 unsafe.Pointer
+	if len(p) > 0 {
+		_p0 = unsafe.Pointer(&p[0])
+	} else {
+		_p0 = unsafe.Pointer(&_zero)
+	}
+	r0, _, e1 := Syscall6(SYS_PREAD64, uintptr(fd), uintptr(_p0), uintptr(len(p)), uintptr(offset), 0, 0)
+	n = int(r0)
+	if e1 != 0 {
+		err = errnoErr(e1)
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Pwrite(fd int, p []byte, offset int64) (n int, err error) {
+	var _p0 unsafe.Pointer
+	if len(p) > 0 {
+		_p0 = unsafe.Pointer(&p[0])
+	} else {
+		_p0 = unsafe.Pointer(&_zero)
+	}
+	r0, _, e1 := Syscall6(SYS_PWRITE64, uintptr(fd), uintptr(_p0), uintptr(len(p)), uintptr(offset), 0, 0)
+	n = int(r0)
+	if e1 != 0 {
+		err = errnoErr(e1)
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Seek(fd int, offset int64, whence int) (off int64, err error) {
+	r0, _, e1 := Syscall(SYS_LSEEK, uintptr(fd), uintptr(offset), uintptr(whence))
+	off = int64(r0)
+	if e1 != 0 {
+		err = errnoErr(e1)
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Select(nfd int, r *FdSet, w *FdSet, e *FdSet, timeout *Timeval) (n int, err error) {
+	r0, _, e1 := Syscall6(SYS_PSELECT6, uintptr(nfd), uintptr(unsafe.Pointer(r)), uintptr(unsafe.Pointer(w)), uintptr(unsafe.Pointer(e)), uintptr(unsafe.Pointer(timeout)), 0)
+	n = int(r0)
+	if e1 != 0 {
+		err = errnoErr(e1)
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func sendfile(outfd int, infd int, offset *int64, count int) (written int, err error) {
+	r0, _, e1 := Syscall6(SYS_SENDFILE, uintptr(outfd), uintptr(infd), uintptr(unsafe.Pointer(offset)), uintptr(count), 0, 0)
+	written = int(r0)
+	if e1 != 0 {
+		err = errnoErr(e1)
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Setfsgid(gid int) (err error) {
+	_, _, e1 := Syscall(SYS_SETFSGID, uintptr(gid), 0, 0)
+	if e1 != 0 {
+		err = errnoErr(e1)
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Setfsuid(uid int) (err error) {
+	_, _, e1 := Syscall(SYS_SETFSUID, uintptr(uid), 0, 0)
+	if e1 != 0 {
+		err = errnoErr(e1)
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Setregid(rgid int, egid int) (err error) {
+	_, _, e1 := RawSyscall(SYS_SETREGID, uintptr(rgid), uintptr(egid), 0)
+	if e1 != 0 {
+		err = errnoErr(e1)
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Setresgid(rgid int, egid int, sgid int) (err error) {
+	_, _, e1 := RawSyscall(SYS_SETRESGID, uintptr(rgid), uintptr(egid), uintptr(sgid))
+	if e1 != 0 {
+		err = errnoErr(e1)
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Setresuid(ruid int, euid int, suid int) (err error) {
+	_, _, e1 := RawSyscall(SYS_SETRESUID, uintptr(ruid), uintptr(euid), uintptr(suid))
+	if e1 != 0 {
+		err = errnoErr(e1)
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Setrlimit(resource int, rlim *Rlimit) (err error) {
+	_, _, e1 := RawSyscall(SYS_SETRLIMIT, uintptr(resource), uintptr(unsafe.Pointer(rlim)), 0)
+	if e1 != 0 {
+		err = errnoErr(e1)
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Setreuid(ruid int, euid int) (err error) {
+	_, _, e1 := RawSyscall(SYS_SETREUID, uintptr(ruid), uintptr(euid), 0)
+	if e1 != 0 {
+		err = errnoErr(e1)
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Shutdown(fd int, how int) (err error) {
+	_, _, e1 := Syscall(SYS_SHUTDOWN, uintptr(fd), uintptr(how), 0)
+	if e1 != 0 {
+		err = errnoErr(e1)
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Splice(rfd int, roff *int64, wfd int, woff *int64, len int, flags int) (n int64, err error) {
+	r0, _, e1 := Syscall6(SYS_SPLICE, uintptr(rfd), uintptr(unsafe.Pointer(roff)), uintptr(wfd), uintptr(unsafe.Pointer(woff)), uintptr(len), uintptr(flags))
+	n = int64(r0)
+	if e1 != 0 {
+		err = errnoErr(e1)
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Statfs(path string, buf *Statfs_t) (err error) {
+	var _p0 *byte
+	_p0, err = BytePtrFromString(path)
+	if err != nil {
+		return
+	}
+	_, _, e1 := Syscall(SYS_STATFS, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(buf)), 0)
+	use(unsafe.Pointer(_p0))
+	if e1 != 0 {
+		err = errnoErr(e1)
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func SyncFileRange(fd int, off int64, n int64, flags int) (err error) {
+	_, _, e1 := Syscall6(SYS_SYNC_FILE_RANGE2, uintptr(fd), uintptr(off), uintptr(n), uintptr(flags), 0, 0)
+	if e1 != 0 {
+		err = errnoErr(e1)
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Truncate(path string, length int64) (err error) {
+	var _p0 *byte
+	_p0, err = BytePtrFromString(path)
+	if err != nil {
+		return
+	}
+	_, _, e1 := Syscall(SYS_TRUNCATE, uintptr(unsafe.Pointer(_p0)), uintptr(length), 0)
+	use(unsafe.Pointer(_p0))
+	if e1 != 0 {
+		err = errnoErr(e1)
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func accept(s int, rsa *RawSockaddrAny, addrlen *_Socklen) (fd int, err error) {
+	r0, _, e1 := Syscall(SYS_ACCEPT, uintptr(s), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)))
+	fd = int(r0)
+	if e1 != 0 {
+		err = errnoErr(e1)
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func accept4(s int, rsa *RawSockaddrAny, addrlen *_Socklen, flags int) (fd int, err error) {
+	r0, _, e1 := Syscall6(SYS_ACCEPT4, uintptr(s), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)), uintptr(flags), 0, 0)
+	fd = int(r0)
+	if e1 != 0 {
+		err = errnoErr(e1)
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func bind(s int, addr unsafe.Pointer, addrlen _Socklen) (err error) {
+	_, _, e1 := Syscall(SYS_BIND, uintptr(s), uintptr(addr), uintptr(addrlen))
+	if e1 != 0 {
+		err = errnoErr(e1)
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func connect(s int, addr unsafe.Pointer, addrlen _Socklen) (err error) {
+	_, _, e1 := Syscall(SYS_CONNECT, uintptr(s), uintptr(addr), uintptr(addrlen))
+	if e1 != 0 {
+		err = errnoErr(e1)
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func getgroups(n int, list *_Gid_t) (nn int, err error) {
+	r0, _, e1 := RawSyscall(SYS_GETGROUPS, uintptr(n), uintptr(unsafe.Pointer(list)), 0)
+	nn = int(r0)
+	if e1 != 0 {
+		err = errnoErr(e1)
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func setgroups(n int, list *_Gid_t) (err error) {
+	_, _, e1 := RawSyscall(SYS_SETGROUPS, uintptr(n), uintptr(unsafe.Pointer(list)), 0)
+	if e1 != 0 {
+		err = errnoErr(e1)
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func getsockopt(s int, level int, name int, val unsafe.Pointer, vallen *_Socklen) (err error) {
+	_, _, e1 := Syscall6(SYS_GETSOCKOPT, uintptr(s), uintptr(level), uintptr(name), uintptr(val), uintptr(unsafe.Pointer(vallen)), 0)
+	if e1 != 0 {
+		err = errnoErr(e1)
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func setsockopt(s int, level int, name int, val unsafe.Pointer, vallen uintptr) (err error) {
+	_, _, e1 := Syscall6(SYS_SETSOCKOPT, uintptr(s), uintptr(level), uintptr(name), uintptr(val), uintptr(vallen), 0)
+	if e1 != 0 {
+		err = errnoErr(e1)
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func socket(domain int, typ int, proto int) (fd int, err error) {
+	r0, _, e1 := RawSyscall(SYS_SOCKET, uintptr(domain), uintptr(typ), uintptr(proto))
+	fd = int(r0)
+	if e1 != 0 {
+		err = errnoErr(e1)
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func socketpair(domain int, typ int, proto int, fd *[2]int32) (err error) {
+	_, _, e1 := RawSyscall6(SYS_SOCKETPAIR, uintptr(domain), uintptr(typ), uintptr(proto), uintptr(unsafe.Pointer(fd)), 0, 0)
+	if e1 != 0 {
+		err = errnoErr(e1)
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func getpeername(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (err error) {
+	_, _, e1 := RawSyscall(SYS_GETPEERNAME, uintptr(fd), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)))
+	if e1 != 0 {
+		err = errnoErr(e1)
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func getsockname(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (err error) {
+	_, _, e1 := RawSyscall(SYS_GETSOCKNAME, uintptr(fd), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)))
+	if e1 != 0 {
+		err = errnoErr(e1)
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func recvfrom(fd int, p []byte, flags int, from *RawSockaddrAny, fromlen *_Socklen) (n int, err error) {
+	var _p0 unsafe.Pointer
+	if len(p) > 0 {
+		_p0 = unsafe.Pointer(&p[0])
+	} else {
+		_p0 = unsafe.Pointer(&_zero)
+	}
+	r0, _, e1 := Syscall6(SYS_RECVFROM, uintptr(fd), uintptr(_p0), uintptr(len(p)), uintptr(flags), uintptr(unsafe.Pointer(from)), uintptr(unsafe.Pointer(fromlen)))
+	n = int(r0)
+	if e1 != 0 {
+		err = errnoErr(e1)
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func sendto(s int, buf []byte, flags int, to unsafe.Pointer, addrlen _Socklen) (err error) {
+	var _p0 unsafe.Pointer
+	if len(buf) > 0 {
+		_p0 = unsafe.Pointer(&buf[0])
+	} else {
+		_p0 = unsafe.Pointer(&_zero)
+	}
+	_, _, e1 := Syscall6(SYS_SENDTO, uintptr(s), uintptr(_p0), uintptr(len(buf)), uintptr(flags), uintptr(to), uintptr(addrlen))
+	if e1 != 0 {
+		err = errnoErr(e1)
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func recvmsg(s int, msg *Msghdr, flags int) (n int, err error) {
+	r0, _, e1 := Syscall(SYS_RECVMSG, uintptr(s), uintptr(unsafe.Pointer(msg)), uintptr(flags))
+	n = int(r0)
+	if e1 != 0 {
+		err = errnoErr(e1)
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func sendmsg(s int, msg *Msghdr, flags int) (n int, err error) {
+	r0, _, e1 := Syscall(SYS_SENDMSG, uintptr(s), uintptr(unsafe.Pointer(msg)), uintptr(flags))
+	n = int(r0)
+	if e1 != 0 {
+		err = errnoErr(e1)
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func mmap(addr uintptr, length uintptr, prot int, flags int, fd int, offset int64) (xaddr uintptr, err error) {
+	r0, _, e1 := Syscall6(SYS_MMAP, uintptr(addr), uintptr(length), uintptr(prot), uintptr(flags), uintptr(fd), uintptr(offset))
+	xaddr = uintptr(r0)
+	if e1 != 0 {
+		err = errnoErr(e1)
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Gettimeofday(tv *Timeval) (err error) {
+	_, _, e1 := RawSyscall(SYS_GETTIMEOFDAY, uintptr(unsafe.Pointer(tv)), 0, 0)
+	if e1 != 0 {
+		err = errnoErr(e1)
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Time(t *Time_t) (tt Time_t, err error) {
+	r0, _, e1 := RawSyscall(SYS_TIME, uintptr(unsafe.Pointer(t)), 0, 0)
+	tt = Time_t(r0)
+	if e1 != 0 {
+		err = errnoErr(e1)
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func pipe2(p *[2]_C_int, flags int) (err error) {
+	_, _, e1 := RawSyscall(SYS_PIPE2, uintptr(unsafe.Pointer(p)), uintptr(flags), 0)
+	if e1 != 0 {
+		err = errnoErr(e1)
+	}
+	return
+}
diff --git a/src/syscall/zsyscall_linux_ppc64.go b/src/syscall/zsyscall_linux_ppc64.go
index f8c3518..3262180 100644
--- a/src/syscall/zsyscall_linux_ppc64.go
+++ b/src/syscall/zsyscall_linux_ppc64.go
@@ -22,7 +22,7 @@
 	use(unsafe.Pointer(_p0))
 	use(unsafe.Pointer(_p1))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -39,7 +39,7 @@
 	use(unsafe.Pointer(_p0))
 	fd = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -62,7 +62,7 @@
 	use(unsafe.Pointer(_p0))
 	n = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -84,7 +84,7 @@
 	use(unsafe.Pointer(_p0))
 	use(unsafe.Pointer(_p1))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -100,7 +100,7 @@
 	_, _, e1 := Syscall(SYS_UNLINKAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(flags))
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -116,7 +116,7 @@
 	_, _, e1 := Syscall(SYS_UTIMES, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(times)), 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -132,7 +132,7 @@
 	_, _, e1 := Syscall(SYS_UTIMENSAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(times)))
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -142,7 +142,7 @@
 func futimesat(dirfd int, path *byte, times *[2]Timeval) (err error) {
 	_, _, e1 := Syscall(SYS_FUTIMESAT, uintptr(dirfd), uintptr(unsafe.Pointer(path)), uintptr(unsafe.Pointer(times)))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -159,7 +159,7 @@
 	r0, _, e1 := Syscall(SYS_GETCWD, uintptr(_p0), uintptr(len(buf)), 0)
 	n = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -170,7 +170,7 @@
 	r0, _, e1 := Syscall6(SYS_WAIT4, uintptr(pid), uintptr(unsafe.Pointer(wstatus)), uintptr(options), uintptr(unsafe.Pointer(rusage)), 0, 0)
 	wpid = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -180,7 +180,7 @@
 func ptrace(request int, pid int, addr uintptr, data uintptr) (err error) {
 	_, _, e1 := Syscall6(SYS_PTRACE, uintptr(request), uintptr(pid), uintptr(addr), uintptr(data), 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -196,7 +196,7 @@
 	_, _, e1 := Syscall6(SYS_REBOOT, uintptr(magic1), uintptr(magic2), uintptr(cmd), uintptr(unsafe.Pointer(_p0)), 0, 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -224,7 +224,7 @@
 	use(unsafe.Pointer(_p1))
 	use(unsafe.Pointer(_p2))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -240,7 +240,7 @@
 	_, _, e1 := Syscall(SYS_ACCT, uintptr(unsafe.Pointer(_p0)), 0, 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -251,7 +251,7 @@
 	r0, _, e1 := Syscall(SYS_ADJTIMEX, uintptr(unsafe.Pointer(buf)), 0, 0)
 	state = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -267,7 +267,7 @@
 	_, _, e1 := Syscall(SYS_CHDIR, uintptr(unsafe.Pointer(_p0)), 0, 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -283,7 +283,7 @@
 	_, _, e1 := Syscall(SYS_CHROOT, uintptr(unsafe.Pointer(_p0)), 0, 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -293,7 +293,7 @@
 func Close(fd int) (err error) {
 	_, _, e1 := Syscall(SYS_CLOSE, uintptr(fd), 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -301,10 +301,10 @@
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
 func Dup(oldfd int) (fd int, err error) {
-	r0, _, e1 := RawSyscall(SYS_DUP, uintptr(oldfd), 0, 0)
+	r0, _, e1 := Syscall(SYS_DUP, uintptr(oldfd), 0, 0)
 	fd = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -312,9 +312,9 @@
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
 func Dup3(oldfd int, newfd int, flags int) (err error) {
-	_, _, e1 := RawSyscall(SYS_DUP3, uintptr(oldfd), uintptr(newfd), uintptr(flags))
+	_, _, e1 := Syscall(SYS_DUP3, uintptr(oldfd), uintptr(newfd), uintptr(flags))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -325,7 +325,7 @@
 	r0, _, e1 := RawSyscall(SYS_EPOLL_CREATE, uintptr(size), 0, 0)
 	fd = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -336,7 +336,7 @@
 	r0, _, e1 := RawSyscall(SYS_EPOLL_CREATE1, uintptr(flag), 0, 0)
 	fd = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -346,7 +346,7 @@
 func EpollCtl(epfd int, op int, fd int, event *EpollEvent) (err error) {
 	_, _, e1 := RawSyscall6(SYS_EPOLL_CTL, uintptr(epfd), uintptr(op), uintptr(fd), uintptr(unsafe.Pointer(event)), 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -363,7 +363,7 @@
 	r0, _, e1 := Syscall6(SYS_EPOLL_WAIT, uintptr(epfd), uintptr(_p0), uintptr(len(events)), uintptr(msec), 0, 0)
 	n = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -386,7 +386,7 @@
 	_, _, e1 := Syscall6(SYS_FACCESSAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(flags), 0, 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -396,7 +396,7 @@
 func Fallocate(fd int, mode uint32, off int64, len int64) (err error) {
 	_, _, e1 := Syscall6(SYS_FALLOCATE, uintptr(fd), uintptr(mode), uintptr(off), uintptr(len), 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -406,7 +406,7 @@
 func Fchdir(fd int) (err error) {
 	_, _, e1 := Syscall(SYS_FCHDIR, uintptr(fd), 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -416,7 +416,7 @@
 func Fchmod(fd int, mode uint32) (err error) {
 	_, _, e1 := Syscall(SYS_FCHMOD, uintptr(fd), uintptr(mode), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -432,7 +432,7 @@
 	_, _, e1 := Syscall6(SYS_FCHMODAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(flags), 0, 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -448,7 +448,7 @@
 	_, _, e1 := Syscall6(SYS_FCHOWNAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(uid), uintptr(gid), uintptr(flags), 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -459,7 +459,7 @@
 	r0, _, e1 := Syscall(SYS_FCNTL, uintptr(fd), uintptr(cmd), uintptr(arg))
 	val = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -469,7 +469,7 @@
 func Fdatasync(fd int) (err error) {
 	_, _, e1 := Syscall(SYS_FDATASYNC, uintptr(fd), 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -479,7 +479,7 @@
 func Flock(fd int, how int) (err error) {
 	_, _, e1 := Syscall(SYS_FLOCK, uintptr(fd), uintptr(how), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -489,7 +489,7 @@
 func Fsync(fd int) (err error) {
 	_, _, e1 := Syscall(SYS_FSYNC, uintptr(fd), 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -506,7 +506,7 @@
 	r0, _, e1 := Syscall(SYS_GETDENTS64, uintptr(fd), uintptr(_p0), uintptr(len(buf)))
 	n = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -517,21 +517,13 @@
 	r0, _, e1 := RawSyscall(SYS_GETPGID, uintptr(pid), 0, 0)
 	pgid = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
-func Getpgrp() (pid int) {
-	r0, _, _ := RawSyscall(SYS_GETPGRP, 0, 0, 0)
-	pid = int(r0)
-	return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
 func Getpid() (pid int) {
 	r0, _, _ := RawSyscall(SYS_GETPID, 0, 0, 0)
 	pid = int(r0)
@@ -552,7 +544,7 @@
 	r0, _, e1 := Syscall(SYS_GETPRIORITY, uintptr(which), uintptr(who), 0)
 	prio = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -562,7 +554,7 @@
 func Getrusage(who int, rusage *Rusage) (err error) {
 	_, _, e1 := RawSyscall(SYS_GETRUSAGE, uintptr(who), uintptr(unsafe.Pointer(rusage)), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -599,7 +591,7 @@
 	use(unsafe.Pointer(_p1))
 	sz = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -616,7 +608,7 @@
 	use(unsafe.Pointer(_p0))
 	watchdesc = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -627,7 +619,7 @@
 	r0, _, e1 := RawSyscall(SYS_INOTIFY_INIT, 0, 0, 0)
 	fd = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -638,7 +630,7 @@
 	r0, _, e1 := RawSyscall(SYS_INOTIFY_INIT1, uintptr(flags), 0, 0)
 	fd = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -649,7 +641,7 @@
 	r0, _, e1 := RawSyscall(SYS_INOTIFY_RM_WATCH, uintptr(fd), uintptr(watchdesc), 0)
 	success = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -659,7 +651,7 @@
 func Kill(pid int, sig Signal) (err error) {
 	_, _, e1 := RawSyscall(SYS_KILL, uintptr(pid), uintptr(sig), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -676,7 +668,7 @@
 	r0, _, e1 := Syscall(SYS_SYSLOG, uintptr(typ), uintptr(_p0), uintptr(len(buf)))
 	n = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -699,7 +691,7 @@
 	use(unsafe.Pointer(_p0))
 	sz = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -715,7 +707,7 @@
 	_, _, e1 := Syscall(SYS_MKDIRAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode))
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -731,7 +723,7 @@
 	_, _, e1 := Syscall6(SYS_MKNODAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(dev), 0, 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -741,7 +733,7 @@
 func Nanosleep(time *Timespec, leftover *Timespec) (err error) {
 	_, _, e1 := Syscall(SYS_NANOSLEEP, uintptr(unsafe.Pointer(time)), uintptr(unsafe.Pointer(leftover)), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -751,7 +743,7 @@
 func Pause() (err error) {
 	_, _, e1 := Syscall(SYS_PAUSE, 0, 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -773,7 +765,7 @@
 	use(unsafe.Pointer(_p0))
 	use(unsafe.Pointer(_p1))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -783,7 +775,7 @@
 func prlimit(pid int, resource int, old *Rlimit, newlimit *Rlimit) (err error) {
 	_, _, e1 := RawSyscall6(SYS_PRLIMIT64, uintptr(pid), uintptr(resource), uintptr(unsafe.Pointer(old)), uintptr(unsafe.Pointer(newlimit)), 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -800,7 +792,7 @@
 	r0, _, e1 := Syscall(SYS_READ, uintptr(fd), uintptr(_p0), uintptr(len(p)))
 	n = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -822,7 +814,7 @@
 	use(unsafe.Pointer(_p0))
 	use(unsafe.Pointer(_p1))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -844,7 +836,7 @@
 	use(unsafe.Pointer(_p0))
 	use(unsafe.Pointer(_p1))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -860,7 +852,7 @@
 	}
 	_, _, e1 := Syscall(SYS_SETDOMAINNAME, uintptr(_p0), uintptr(len(p)), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -876,7 +868,7 @@
 	}
 	_, _, e1 := Syscall(SYS_SETHOSTNAME, uintptr(_p0), uintptr(len(p)), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -886,7 +878,7 @@
 func Setpgid(pid int, pgid int) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETPGID, uintptr(pid), uintptr(pgid), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -897,7 +889,7 @@
 	r0, _, e1 := RawSyscall(SYS_SETSID, 0, 0, 0)
 	pid = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -907,7 +899,7 @@
 func Settimeofday(tv *Timeval) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETTIMEOFDAY, uintptr(unsafe.Pointer(tv)), 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -917,7 +909,7 @@
 func Setpriority(which int, who int, prio int) (err error) {
 	_, _, e1 := Syscall(SYS_SETPRIORITY, uintptr(which), uintptr(who), uintptr(prio))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -945,7 +937,7 @@
 	use(unsafe.Pointer(_p0))
 	use(unsafe.Pointer(_p1))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -962,7 +954,7 @@
 func Sysinfo(info *Sysinfo_t) (err error) {
 	_, _, e1 := RawSyscall(SYS_SYSINFO, uintptr(unsafe.Pointer(info)), 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -973,7 +965,7 @@
 	r0, _, e1 := Syscall6(SYS_TEE, uintptr(rfd), uintptr(wfd), uintptr(len), uintptr(flags), 0, 0)
 	n = int64(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -983,7 +975,7 @@
 func Tgkill(tgid int, tid int, sig Signal) (err error) {
 	_, _, e1 := RawSyscall(SYS_TGKILL, uintptr(tgid), uintptr(tid), uintptr(sig))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -994,7 +986,7 @@
 	r0, _, e1 := RawSyscall(SYS_TIMES, uintptr(unsafe.Pointer(tms)), 0, 0)
 	ticks = uintptr(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1012,7 +1004,7 @@
 func Uname(buf *Utsname) (err error) {
 	_, _, e1 := RawSyscall(SYS_UNAME, uintptr(unsafe.Pointer(buf)), 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1028,7 +1020,7 @@
 	_, _, e1 := Syscall(SYS_UMOUNT2, uintptr(unsafe.Pointer(_p0)), uintptr(flags), 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1038,7 +1030,7 @@
 func Unshare(flags int) (err error) {
 	_, _, e1 := Syscall(SYS_UNSHARE, uintptr(flags), 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1048,7 +1040,7 @@
 func Ustat(dev int, ubuf *Ustat_t) (err error) {
 	_, _, e1 := Syscall(SYS_USTAT, uintptr(dev), uintptr(unsafe.Pointer(ubuf)), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1064,7 +1056,7 @@
 	_, _, e1 := Syscall(SYS_UTIME, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(buf)), 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1081,7 +1073,7 @@
 	r0, _, e1 := Syscall(SYS_WRITE, uintptr(fd), uintptr(_p0), uintptr(len(p)))
 	n = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1091,7 +1083,7 @@
 func exitThread(code int) (err error) {
 	_, _, e1 := Syscall(SYS_EXIT, uintptr(code), 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1102,7 +1094,7 @@
 	r0, _, e1 := Syscall(SYS_READ, uintptr(fd), uintptr(unsafe.Pointer(p)), uintptr(np))
 	n = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1113,7 +1105,7 @@
 	r0, _, e1 := Syscall(SYS_WRITE, uintptr(fd), uintptr(unsafe.Pointer(p)), uintptr(np))
 	n = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1123,7 +1115,7 @@
 func munmap(addr uintptr, length uintptr) (err error) {
 	_, _, e1 := Syscall(SYS_MUNMAP, uintptr(addr), uintptr(length), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1139,7 +1131,7 @@
 	}
 	_, _, e1 := Syscall(SYS_MADVISE, uintptr(_p0), uintptr(len(b)), uintptr(advice))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1155,7 +1147,7 @@
 	}
 	_, _, e1 := Syscall(SYS_MPROTECT, uintptr(_p0), uintptr(len(b)), uintptr(prot))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1171,7 +1163,7 @@
 	}
 	_, _, e1 := Syscall(SYS_MLOCK, uintptr(_p0), uintptr(len(b)), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1187,7 +1179,7 @@
 	}
 	_, _, e1 := Syscall(SYS_MUNLOCK, uintptr(_p0), uintptr(len(b)), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1197,7 +1189,7 @@
 func Mlockall(flags int) (err error) {
 	_, _, e1 := Syscall(SYS_MLOCKALL, uintptr(flags), 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1207,7 +1199,7 @@
 func Munlockall() (err error) {
 	_, _, e1 := Syscall(SYS_MUNLOCKALL, 0, 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1215,9 +1207,9 @@
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
 func Dup2(oldfd int, newfd int) (err error) {
-	_, _, e1 := RawSyscall(SYS_DUP2, uintptr(oldfd), uintptr(newfd), 0)
+	_, _, e1 := Syscall(SYS_DUP2, uintptr(oldfd), uintptr(newfd), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1227,7 +1219,7 @@
 func Fchown(fd int, uid int, gid int) (err error) {
 	_, _, e1 := Syscall(SYS_FCHOWN, uintptr(fd), uintptr(uid), uintptr(gid))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1237,7 +1229,7 @@
 func Fstat(fd int, stat *Stat_t) (err error) {
 	_, _, e1 := Syscall(SYS_FSTAT, uintptr(fd), uintptr(unsafe.Pointer(stat)), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1247,7 +1239,7 @@
 func Fstatfs(fd int, buf *Statfs_t) (err error) {
 	_, _, e1 := Syscall(SYS_FSTATFS, uintptr(fd), uintptr(unsafe.Pointer(buf)), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1257,7 +1249,7 @@
 func Ftruncate(fd int, length int64) (err error) {
 	_, _, e1 := Syscall(SYS_FTRUNCATE, uintptr(fd), uintptr(length), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1291,7 +1283,7 @@
 func Getrlimit(resource int, rlim *Rlimit) (err error) {
 	_, _, e1 := RawSyscall(SYS_UGETRLIMIT, uintptr(resource), uintptr(unsafe.Pointer(rlim)), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1309,7 +1301,7 @@
 func Ioperm(from int, num int, on int) (err error) {
 	_, _, e1 := Syscall(SYS_IOPERM, uintptr(from), uintptr(num), uintptr(on))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1319,7 +1311,7 @@
 func Iopl(level int) (err error) {
 	_, _, e1 := Syscall(SYS_IOPL, uintptr(level), 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1335,7 +1327,7 @@
 	_, _, e1 := Syscall(SYS_LCHOWN, uintptr(unsafe.Pointer(_p0)), uintptr(uid), uintptr(gid))
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1345,7 +1337,7 @@
 func Listen(s int, n int) (err error) {
 	_, _, e1 := Syscall(SYS_LISTEN, uintptr(s), uintptr(n), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1361,7 +1353,7 @@
 	_, _, e1 := Syscall(SYS_LSTAT, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1378,7 +1370,7 @@
 	r0, _, e1 := Syscall6(SYS_PREAD64, uintptr(fd), uintptr(_p0), uintptr(len(p)), uintptr(offset), 0, 0)
 	n = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1395,7 +1387,7 @@
 	r0, _, e1 := Syscall6(SYS_PWRITE64, uintptr(fd), uintptr(_p0), uintptr(len(p)), uintptr(offset), 0, 0)
 	n = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1406,7 +1398,7 @@
 	r0, _, e1 := Syscall(SYS_LSEEK, uintptr(fd), uintptr(offset), uintptr(whence))
 	off = int64(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1417,7 +1409,7 @@
 	r0, _, e1 := Syscall6(SYS_SELECT, uintptr(nfd), uintptr(unsafe.Pointer(r)), uintptr(unsafe.Pointer(w)), uintptr(unsafe.Pointer(e)), uintptr(unsafe.Pointer(timeout)), 0)
 	n = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1428,7 +1420,7 @@
 	r0, _, e1 := Syscall6(SYS_SENDFILE, uintptr(outfd), uintptr(infd), uintptr(unsafe.Pointer(offset)), uintptr(count), 0, 0)
 	written = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1438,7 +1430,7 @@
 func Setfsgid(gid int) (err error) {
 	_, _, e1 := Syscall(SYS_SETFSGID, uintptr(gid), 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1448,7 +1440,7 @@
 func Setfsuid(uid int) (err error) {
 	_, _, e1 := Syscall(SYS_SETFSUID, uintptr(uid), 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1458,7 +1450,7 @@
 func Setregid(rgid int, egid int) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETREGID, uintptr(rgid), uintptr(egid), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1468,7 +1460,7 @@
 func Setresgid(rgid int, egid int, sgid int) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETRESGID, uintptr(rgid), uintptr(egid), uintptr(sgid))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1478,7 +1470,7 @@
 func Setresuid(ruid int, euid int, suid int) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETRESUID, uintptr(ruid), uintptr(euid), uintptr(suid))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1488,7 +1480,7 @@
 func Setrlimit(resource int, rlim *Rlimit) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETRLIMIT, uintptr(resource), uintptr(unsafe.Pointer(rlim)), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1498,7 +1490,7 @@
 func Setreuid(ruid int, euid int) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETREUID, uintptr(ruid), uintptr(euid), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1508,7 +1500,7 @@
 func Shutdown(fd int, how int) (err error) {
 	_, _, e1 := Syscall(SYS_SHUTDOWN, uintptr(fd), uintptr(how), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1519,7 +1511,7 @@
 	r0, _, e1 := Syscall6(SYS_SPLICE, uintptr(rfd), uintptr(unsafe.Pointer(roff)), uintptr(wfd), uintptr(unsafe.Pointer(woff)), uintptr(len), uintptr(flags))
 	n = int64(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1535,7 +1527,7 @@
 	_, _, e1 := Syscall(SYS_STAT, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1551,7 +1543,7 @@
 	_, _, e1 := Syscall(SYS_STATFS, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(buf)), 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1561,7 +1553,7 @@
 func SyncFileRange(fd int, off int64, n int64, flags int) (err error) {
 	_, _, e1 := Syscall6(SYS_SYNC_FILE_RANGE2, uintptr(fd), uintptr(off), uintptr(n), uintptr(flags), 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1577,7 +1569,7 @@
 	_, _, e1 := Syscall(SYS_TRUNCATE, uintptr(unsafe.Pointer(_p0)), uintptr(length), 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1588,7 +1580,7 @@
 	r0, _, e1 := Syscall(SYS_ACCEPT, uintptr(s), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)))
 	fd = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1599,7 +1591,7 @@
 	r0, _, e1 := Syscall6(SYS_ACCEPT4, uintptr(s), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)), uintptr(flags), 0, 0)
 	fd = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1609,7 +1601,7 @@
 func bind(s int, addr unsafe.Pointer, addrlen _Socklen) (err error) {
 	_, _, e1 := Syscall(SYS_BIND, uintptr(s), uintptr(addr), uintptr(addrlen))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1619,7 +1611,7 @@
 func connect(s int, addr unsafe.Pointer, addrlen _Socklen) (err error) {
 	_, _, e1 := Syscall(SYS_CONNECT, uintptr(s), uintptr(addr), uintptr(addrlen))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1630,7 +1622,7 @@
 	r0, _, e1 := RawSyscall(SYS_GETGROUPS, uintptr(n), uintptr(unsafe.Pointer(list)), 0)
 	nn = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1640,7 +1632,7 @@
 func setgroups(n int, list *_Gid_t) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETGROUPS, uintptr(n), uintptr(unsafe.Pointer(list)), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1650,7 +1642,7 @@
 func getsockopt(s int, level int, name int, val unsafe.Pointer, vallen *_Socklen) (err error) {
 	_, _, e1 := Syscall6(SYS_GETSOCKOPT, uintptr(s), uintptr(level), uintptr(name), uintptr(val), uintptr(unsafe.Pointer(vallen)), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1660,7 +1652,7 @@
 func setsockopt(s int, level int, name int, val unsafe.Pointer, vallen uintptr) (err error) {
 	_, _, e1 := Syscall6(SYS_SETSOCKOPT, uintptr(s), uintptr(level), uintptr(name), uintptr(val), uintptr(vallen), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1671,7 +1663,7 @@
 	r0, _, e1 := RawSyscall(SYS_SOCKET, uintptr(domain), uintptr(typ), uintptr(proto))
 	fd = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1681,7 +1673,7 @@
 func socketpair(domain int, typ int, proto int, fd *[2]int32) (err error) {
 	_, _, e1 := RawSyscall6(SYS_SOCKETPAIR, uintptr(domain), uintptr(typ), uintptr(proto), uintptr(unsafe.Pointer(fd)), 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1691,7 +1683,7 @@
 func getpeername(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (err error) {
 	_, _, e1 := RawSyscall(SYS_GETPEERNAME, uintptr(fd), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1701,7 +1693,7 @@
 func getsockname(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (err error) {
 	_, _, e1 := RawSyscall(SYS_GETSOCKNAME, uintptr(fd), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1718,7 +1710,7 @@
 	r0, _, e1 := Syscall6(SYS_RECVFROM, uintptr(fd), uintptr(_p0), uintptr(len(p)), uintptr(flags), uintptr(unsafe.Pointer(from)), uintptr(unsafe.Pointer(fromlen)))
 	n = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1734,7 +1726,7 @@
 	}
 	_, _, e1 := Syscall6(SYS_SENDTO, uintptr(s), uintptr(_p0), uintptr(len(buf)), uintptr(flags), uintptr(to), uintptr(addrlen))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1745,7 +1737,7 @@
 	r0, _, e1 := Syscall(SYS_RECVMSG, uintptr(s), uintptr(unsafe.Pointer(msg)), uintptr(flags))
 	n = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1756,7 +1748,7 @@
 	r0, _, e1 := Syscall(SYS_SENDMSG, uintptr(s), uintptr(unsafe.Pointer(msg)), uintptr(flags))
 	n = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1767,7 +1759,7 @@
 	r0, _, e1 := Syscall6(SYS_MMAP, uintptr(addr), uintptr(length), uintptr(prot), uintptr(flags), uintptr(fd), uintptr(offset))
 	xaddr = uintptr(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1777,7 +1769,7 @@
 func Gettimeofday(tv *Timeval) (err error) {
 	_, _, e1 := RawSyscall(SYS_GETTIMEOFDAY, uintptr(unsafe.Pointer(tv)), 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1788,7 +1780,7 @@
 	r0, _, e1 := RawSyscall(SYS_TIME, uintptr(unsafe.Pointer(t)), 0, 0)
 	tt = Time_t(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1798,7 +1790,7 @@
 func pipe2(p *[2]_C_int, flags int) (err error) {
 	_, _, e1 := RawSyscall(SYS_PIPE2, uintptr(unsafe.Pointer(p)), uintptr(flags), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
diff --git a/src/syscall/zsyscall_linux_ppc64le.go b/src/syscall/zsyscall_linux_ppc64le.go
index f8c3518..3262180 100644
--- a/src/syscall/zsyscall_linux_ppc64le.go
+++ b/src/syscall/zsyscall_linux_ppc64le.go
@@ -22,7 +22,7 @@
 	use(unsafe.Pointer(_p0))
 	use(unsafe.Pointer(_p1))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -39,7 +39,7 @@
 	use(unsafe.Pointer(_p0))
 	fd = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -62,7 +62,7 @@
 	use(unsafe.Pointer(_p0))
 	n = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -84,7 +84,7 @@
 	use(unsafe.Pointer(_p0))
 	use(unsafe.Pointer(_p1))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -100,7 +100,7 @@
 	_, _, e1 := Syscall(SYS_UNLINKAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(flags))
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -116,7 +116,7 @@
 	_, _, e1 := Syscall(SYS_UTIMES, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(times)), 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -132,7 +132,7 @@
 	_, _, e1 := Syscall(SYS_UTIMENSAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(times)))
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -142,7 +142,7 @@
 func futimesat(dirfd int, path *byte, times *[2]Timeval) (err error) {
 	_, _, e1 := Syscall(SYS_FUTIMESAT, uintptr(dirfd), uintptr(unsafe.Pointer(path)), uintptr(unsafe.Pointer(times)))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -159,7 +159,7 @@
 	r0, _, e1 := Syscall(SYS_GETCWD, uintptr(_p0), uintptr(len(buf)), 0)
 	n = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -170,7 +170,7 @@
 	r0, _, e1 := Syscall6(SYS_WAIT4, uintptr(pid), uintptr(unsafe.Pointer(wstatus)), uintptr(options), uintptr(unsafe.Pointer(rusage)), 0, 0)
 	wpid = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -180,7 +180,7 @@
 func ptrace(request int, pid int, addr uintptr, data uintptr) (err error) {
 	_, _, e1 := Syscall6(SYS_PTRACE, uintptr(request), uintptr(pid), uintptr(addr), uintptr(data), 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -196,7 +196,7 @@
 	_, _, e1 := Syscall6(SYS_REBOOT, uintptr(magic1), uintptr(magic2), uintptr(cmd), uintptr(unsafe.Pointer(_p0)), 0, 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -224,7 +224,7 @@
 	use(unsafe.Pointer(_p1))
 	use(unsafe.Pointer(_p2))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -240,7 +240,7 @@
 	_, _, e1 := Syscall(SYS_ACCT, uintptr(unsafe.Pointer(_p0)), 0, 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -251,7 +251,7 @@
 	r0, _, e1 := Syscall(SYS_ADJTIMEX, uintptr(unsafe.Pointer(buf)), 0, 0)
 	state = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -267,7 +267,7 @@
 	_, _, e1 := Syscall(SYS_CHDIR, uintptr(unsafe.Pointer(_p0)), 0, 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -283,7 +283,7 @@
 	_, _, e1 := Syscall(SYS_CHROOT, uintptr(unsafe.Pointer(_p0)), 0, 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -293,7 +293,7 @@
 func Close(fd int) (err error) {
 	_, _, e1 := Syscall(SYS_CLOSE, uintptr(fd), 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -301,10 +301,10 @@
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
 func Dup(oldfd int) (fd int, err error) {
-	r0, _, e1 := RawSyscall(SYS_DUP, uintptr(oldfd), 0, 0)
+	r0, _, e1 := Syscall(SYS_DUP, uintptr(oldfd), 0, 0)
 	fd = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -312,9 +312,9 @@
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
 func Dup3(oldfd int, newfd int, flags int) (err error) {
-	_, _, e1 := RawSyscall(SYS_DUP3, uintptr(oldfd), uintptr(newfd), uintptr(flags))
+	_, _, e1 := Syscall(SYS_DUP3, uintptr(oldfd), uintptr(newfd), uintptr(flags))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -325,7 +325,7 @@
 	r0, _, e1 := RawSyscall(SYS_EPOLL_CREATE, uintptr(size), 0, 0)
 	fd = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -336,7 +336,7 @@
 	r0, _, e1 := RawSyscall(SYS_EPOLL_CREATE1, uintptr(flag), 0, 0)
 	fd = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -346,7 +346,7 @@
 func EpollCtl(epfd int, op int, fd int, event *EpollEvent) (err error) {
 	_, _, e1 := RawSyscall6(SYS_EPOLL_CTL, uintptr(epfd), uintptr(op), uintptr(fd), uintptr(unsafe.Pointer(event)), 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -363,7 +363,7 @@
 	r0, _, e1 := Syscall6(SYS_EPOLL_WAIT, uintptr(epfd), uintptr(_p0), uintptr(len(events)), uintptr(msec), 0, 0)
 	n = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -386,7 +386,7 @@
 	_, _, e1 := Syscall6(SYS_FACCESSAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(flags), 0, 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -396,7 +396,7 @@
 func Fallocate(fd int, mode uint32, off int64, len int64) (err error) {
 	_, _, e1 := Syscall6(SYS_FALLOCATE, uintptr(fd), uintptr(mode), uintptr(off), uintptr(len), 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -406,7 +406,7 @@
 func Fchdir(fd int) (err error) {
 	_, _, e1 := Syscall(SYS_FCHDIR, uintptr(fd), 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -416,7 +416,7 @@
 func Fchmod(fd int, mode uint32) (err error) {
 	_, _, e1 := Syscall(SYS_FCHMOD, uintptr(fd), uintptr(mode), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -432,7 +432,7 @@
 	_, _, e1 := Syscall6(SYS_FCHMODAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(flags), 0, 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -448,7 +448,7 @@
 	_, _, e1 := Syscall6(SYS_FCHOWNAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(uid), uintptr(gid), uintptr(flags), 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -459,7 +459,7 @@
 	r0, _, e1 := Syscall(SYS_FCNTL, uintptr(fd), uintptr(cmd), uintptr(arg))
 	val = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -469,7 +469,7 @@
 func Fdatasync(fd int) (err error) {
 	_, _, e1 := Syscall(SYS_FDATASYNC, uintptr(fd), 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -479,7 +479,7 @@
 func Flock(fd int, how int) (err error) {
 	_, _, e1 := Syscall(SYS_FLOCK, uintptr(fd), uintptr(how), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -489,7 +489,7 @@
 func Fsync(fd int) (err error) {
 	_, _, e1 := Syscall(SYS_FSYNC, uintptr(fd), 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -506,7 +506,7 @@
 	r0, _, e1 := Syscall(SYS_GETDENTS64, uintptr(fd), uintptr(_p0), uintptr(len(buf)))
 	n = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -517,21 +517,13 @@
 	r0, _, e1 := RawSyscall(SYS_GETPGID, uintptr(pid), 0, 0)
 	pgid = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
-func Getpgrp() (pid int) {
-	r0, _, _ := RawSyscall(SYS_GETPGRP, 0, 0, 0)
-	pid = int(r0)
-	return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
 func Getpid() (pid int) {
 	r0, _, _ := RawSyscall(SYS_GETPID, 0, 0, 0)
 	pid = int(r0)
@@ -552,7 +544,7 @@
 	r0, _, e1 := Syscall(SYS_GETPRIORITY, uintptr(which), uintptr(who), 0)
 	prio = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -562,7 +554,7 @@
 func Getrusage(who int, rusage *Rusage) (err error) {
 	_, _, e1 := RawSyscall(SYS_GETRUSAGE, uintptr(who), uintptr(unsafe.Pointer(rusage)), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -599,7 +591,7 @@
 	use(unsafe.Pointer(_p1))
 	sz = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -616,7 +608,7 @@
 	use(unsafe.Pointer(_p0))
 	watchdesc = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -627,7 +619,7 @@
 	r0, _, e1 := RawSyscall(SYS_INOTIFY_INIT, 0, 0, 0)
 	fd = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -638,7 +630,7 @@
 	r0, _, e1 := RawSyscall(SYS_INOTIFY_INIT1, uintptr(flags), 0, 0)
 	fd = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -649,7 +641,7 @@
 	r0, _, e1 := RawSyscall(SYS_INOTIFY_RM_WATCH, uintptr(fd), uintptr(watchdesc), 0)
 	success = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -659,7 +651,7 @@
 func Kill(pid int, sig Signal) (err error) {
 	_, _, e1 := RawSyscall(SYS_KILL, uintptr(pid), uintptr(sig), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -676,7 +668,7 @@
 	r0, _, e1 := Syscall(SYS_SYSLOG, uintptr(typ), uintptr(_p0), uintptr(len(buf)))
 	n = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -699,7 +691,7 @@
 	use(unsafe.Pointer(_p0))
 	sz = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -715,7 +707,7 @@
 	_, _, e1 := Syscall(SYS_MKDIRAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode))
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -731,7 +723,7 @@
 	_, _, e1 := Syscall6(SYS_MKNODAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(dev), 0, 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -741,7 +733,7 @@
 func Nanosleep(time *Timespec, leftover *Timespec) (err error) {
 	_, _, e1 := Syscall(SYS_NANOSLEEP, uintptr(unsafe.Pointer(time)), uintptr(unsafe.Pointer(leftover)), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -751,7 +743,7 @@
 func Pause() (err error) {
 	_, _, e1 := Syscall(SYS_PAUSE, 0, 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -773,7 +765,7 @@
 	use(unsafe.Pointer(_p0))
 	use(unsafe.Pointer(_p1))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -783,7 +775,7 @@
 func prlimit(pid int, resource int, old *Rlimit, newlimit *Rlimit) (err error) {
 	_, _, e1 := RawSyscall6(SYS_PRLIMIT64, uintptr(pid), uintptr(resource), uintptr(unsafe.Pointer(old)), uintptr(unsafe.Pointer(newlimit)), 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -800,7 +792,7 @@
 	r0, _, e1 := Syscall(SYS_READ, uintptr(fd), uintptr(_p0), uintptr(len(p)))
 	n = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -822,7 +814,7 @@
 	use(unsafe.Pointer(_p0))
 	use(unsafe.Pointer(_p1))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -844,7 +836,7 @@
 	use(unsafe.Pointer(_p0))
 	use(unsafe.Pointer(_p1))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -860,7 +852,7 @@
 	}
 	_, _, e1 := Syscall(SYS_SETDOMAINNAME, uintptr(_p0), uintptr(len(p)), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -876,7 +868,7 @@
 	}
 	_, _, e1 := Syscall(SYS_SETHOSTNAME, uintptr(_p0), uintptr(len(p)), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -886,7 +878,7 @@
 func Setpgid(pid int, pgid int) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETPGID, uintptr(pid), uintptr(pgid), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -897,7 +889,7 @@
 	r0, _, e1 := RawSyscall(SYS_SETSID, 0, 0, 0)
 	pid = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -907,7 +899,7 @@
 func Settimeofday(tv *Timeval) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETTIMEOFDAY, uintptr(unsafe.Pointer(tv)), 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -917,7 +909,7 @@
 func Setpriority(which int, who int, prio int) (err error) {
 	_, _, e1 := Syscall(SYS_SETPRIORITY, uintptr(which), uintptr(who), uintptr(prio))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -945,7 +937,7 @@
 	use(unsafe.Pointer(_p0))
 	use(unsafe.Pointer(_p1))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -962,7 +954,7 @@
 func Sysinfo(info *Sysinfo_t) (err error) {
 	_, _, e1 := RawSyscall(SYS_SYSINFO, uintptr(unsafe.Pointer(info)), 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -973,7 +965,7 @@
 	r0, _, e1 := Syscall6(SYS_TEE, uintptr(rfd), uintptr(wfd), uintptr(len), uintptr(flags), 0, 0)
 	n = int64(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -983,7 +975,7 @@
 func Tgkill(tgid int, tid int, sig Signal) (err error) {
 	_, _, e1 := RawSyscall(SYS_TGKILL, uintptr(tgid), uintptr(tid), uintptr(sig))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -994,7 +986,7 @@
 	r0, _, e1 := RawSyscall(SYS_TIMES, uintptr(unsafe.Pointer(tms)), 0, 0)
 	ticks = uintptr(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1012,7 +1004,7 @@
 func Uname(buf *Utsname) (err error) {
 	_, _, e1 := RawSyscall(SYS_UNAME, uintptr(unsafe.Pointer(buf)), 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1028,7 +1020,7 @@
 	_, _, e1 := Syscall(SYS_UMOUNT2, uintptr(unsafe.Pointer(_p0)), uintptr(flags), 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1038,7 +1030,7 @@
 func Unshare(flags int) (err error) {
 	_, _, e1 := Syscall(SYS_UNSHARE, uintptr(flags), 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1048,7 +1040,7 @@
 func Ustat(dev int, ubuf *Ustat_t) (err error) {
 	_, _, e1 := Syscall(SYS_USTAT, uintptr(dev), uintptr(unsafe.Pointer(ubuf)), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1064,7 +1056,7 @@
 	_, _, e1 := Syscall(SYS_UTIME, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(buf)), 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1081,7 +1073,7 @@
 	r0, _, e1 := Syscall(SYS_WRITE, uintptr(fd), uintptr(_p0), uintptr(len(p)))
 	n = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1091,7 +1083,7 @@
 func exitThread(code int) (err error) {
 	_, _, e1 := Syscall(SYS_EXIT, uintptr(code), 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1102,7 +1094,7 @@
 	r0, _, e1 := Syscall(SYS_READ, uintptr(fd), uintptr(unsafe.Pointer(p)), uintptr(np))
 	n = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1113,7 +1105,7 @@
 	r0, _, e1 := Syscall(SYS_WRITE, uintptr(fd), uintptr(unsafe.Pointer(p)), uintptr(np))
 	n = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1123,7 +1115,7 @@
 func munmap(addr uintptr, length uintptr) (err error) {
 	_, _, e1 := Syscall(SYS_MUNMAP, uintptr(addr), uintptr(length), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1139,7 +1131,7 @@
 	}
 	_, _, e1 := Syscall(SYS_MADVISE, uintptr(_p0), uintptr(len(b)), uintptr(advice))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1155,7 +1147,7 @@
 	}
 	_, _, e1 := Syscall(SYS_MPROTECT, uintptr(_p0), uintptr(len(b)), uintptr(prot))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1171,7 +1163,7 @@
 	}
 	_, _, e1 := Syscall(SYS_MLOCK, uintptr(_p0), uintptr(len(b)), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1187,7 +1179,7 @@
 	}
 	_, _, e1 := Syscall(SYS_MUNLOCK, uintptr(_p0), uintptr(len(b)), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1197,7 +1189,7 @@
 func Mlockall(flags int) (err error) {
 	_, _, e1 := Syscall(SYS_MLOCKALL, uintptr(flags), 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1207,7 +1199,7 @@
 func Munlockall() (err error) {
 	_, _, e1 := Syscall(SYS_MUNLOCKALL, 0, 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1215,9 +1207,9 @@
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
 func Dup2(oldfd int, newfd int) (err error) {
-	_, _, e1 := RawSyscall(SYS_DUP2, uintptr(oldfd), uintptr(newfd), 0)
+	_, _, e1 := Syscall(SYS_DUP2, uintptr(oldfd), uintptr(newfd), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1227,7 +1219,7 @@
 func Fchown(fd int, uid int, gid int) (err error) {
 	_, _, e1 := Syscall(SYS_FCHOWN, uintptr(fd), uintptr(uid), uintptr(gid))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1237,7 +1229,7 @@
 func Fstat(fd int, stat *Stat_t) (err error) {
 	_, _, e1 := Syscall(SYS_FSTAT, uintptr(fd), uintptr(unsafe.Pointer(stat)), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1247,7 +1239,7 @@
 func Fstatfs(fd int, buf *Statfs_t) (err error) {
 	_, _, e1 := Syscall(SYS_FSTATFS, uintptr(fd), uintptr(unsafe.Pointer(buf)), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1257,7 +1249,7 @@
 func Ftruncate(fd int, length int64) (err error) {
 	_, _, e1 := Syscall(SYS_FTRUNCATE, uintptr(fd), uintptr(length), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1291,7 +1283,7 @@
 func Getrlimit(resource int, rlim *Rlimit) (err error) {
 	_, _, e1 := RawSyscall(SYS_UGETRLIMIT, uintptr(resource), uintptr(unsafe.Pointer(rlim)), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1309,7 +1301,7 @@
 func Ioperm(from int, num int, on int) (err error) {
 	_, _, e1 := Syscall(SYS_IOPERM, uintptr(from), uintptr(num), uintptr(on))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1319,7 +1311,7 @@
 func Iopl(level int) (err error) {
 	_, _, e1 := Syscall(SYS_IOPL, uintptr(level), 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1335,7 +1327,7 @@
 	_, _, e1 := Syscall(SYS_LCHOWN, uintptr(unsafe.Pointer(_p0)), uintptr(uid), uintptr(gid))
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1345,7 +1337,7 @@
 func Listen(s int, n int) (err error) {
 	_, _, e1 := Syscall(SYS_LISTEN, uintptr(s), uintptr(n), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1361,7 +1353,7 @@
 	_, _, e1 := Syscall(SYS_LSTAT, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1378,7 +1370,7 @@
 	r0, _, e1 := Syscall6(SYS_PREAD64, uintptr(fd), uintptr(_p0), uintptr(len(p)), uintptr(offset), 0, 0)
 	n = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1395,7 +1387,7 @@
 	r0, _, e1 := Syscall6(SYS_PWRITE64, uintptr(fd), uintptr(_p0), uintptr(len(p)), uintptr(offset), 0, 0)
 	n = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1406,7 +1398,7 @@
 	r0, _, e1 := Syscall(SYS_LSEEK, uintptr(fd), uintptr(offset), uintptr(whence))
 	off = int64(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1417,7 +1409,7 @@
 	r0, _, e1 := Syscall6(SYS_SELECT, uintptr(nfd), uintptr(unsafe.Pointer(r)), uintptr(unsafe.Pointer(w)), uintptr(unsafe.Pointer(e)), uintptr(unsafe.Pointer(timeout)), 0)
 	n = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1428,7 +1420,7 @@
 	r0, _, e1 := Syscall6(SYS_SENDFILE, uintptr(outfd), uintptr(infd), uintptr(unsafe.Pointer(offset)), uintptr(count), 0, 0)
 	written = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1438,7 +1430,7 @@
 func Setfsgid(gid int) (err error) {
 	_, _, e1 := Syscall(SYS_SETFSGID, uintptr(gid), 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1448,7 +1440,7 @@
 func Setfsuid(uid int) (err error) {
 	_, _, e1 := Syscall(SYS_SETFSUID, uintptr(uid), 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1458,7 +1450,7 @@
 func Setregid(rgid int, egid int) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETREGID, uintptr(rgid), uintptr(egid), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1468,7 +1460,7 @@
 func Setresgid(rgid int, egid int, sgid int) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETRESGID, uintptr(rgid), uintptr(egid), uintptr(sgid))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1478,7 +1470,7 @@
 func Setresuid(ruid int, euid int, suid int) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETRESUID, uintptr(ruid), uintptr(euid), uintptr(suid))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1488,7 +1480,7 @@
 func Setrlimit(resource int, rlim *Rlimit) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETRLIMIT, uintptr(resource), uintptr(unsafe.Pointer(rlim)), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1498,7 +1490,7 @@
 func Setreuid(ruid int, euid int) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETREUID, uintptr(ruid), uintptr(euid), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1508,7 +1500,7 @@
 func Shutdown(fd int, how int) (err error) {
 	_, _, e1 := Syscall(SYS_SHUTDOWN, uintptr(fd), uintptr(how), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1519,7 +1511,7 @@
 	r0, _, e1 := Syscall6(SYS_SPLICE, uintptr(rfd), uintptr(unsafe.Pointer(roff)), uintptr(wfd), uintptr(unsafe.Pointer(woff)), uintptr(len), uintptr(flags))
 	n = int64(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1535,7 +1527,7 @@
 	_, _, e1 := Syscall(SYS_STAT, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1551,7 +1543,7 @@
 	_, _, e1 := Syscall(SYS_STATFS, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(buf)), 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1561,7 +1553,7 @@
 func SyncFileRange(fd int, off int64, n int64, flags int) (err error) {
 	_, _, e1 := Syscall6(SYS_SYNC_FILE_RANGE2, uintptr(fd), uintptr(off), uintptr(n), uintptr(flags), 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1577,7 +1569,7 @@
 	_, _, e1 := Syscall(SYS_TRUNCATE, uintptr(unsafe.Pointer(_p0)), uintptr(length), 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1588,7 +1580,7 @@
 	r0, _, e1 := Syscall(SYS_ACCEPT, uintptr(s), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)))
 	fd = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1599,7 +1591,7 @@
 	r0, _, e1 := Syscall6(SYS_ACCEPT4, uintptr(s), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)), uintptr(flags), 0, 0)
 	fd = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1609,7 +1601,7 @@
 func bind(s int, addr unsafe.Pointer, addrlen _Socklen) (err error) {
 	_, _, e1 := Syscall(SYS_BIND, uintptr(s), uintptr(addr), uintptr(addrlen))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1619,7 +1611,7 @@
 func connect(s int, addr unsafe.Pointer, addrlen _Socklen) (err error) {
 	_, _, e1 := Syscall(SYS_CONNECT, uintptr(s), uintptr(addr), uintptr(addrlen))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1630,7 +1622,7 @@
 	r0, _, e1 := RawSyscall(SYS_GETGROUPS, uintptr(n), uintptr(unsafe.Pointer(list)), 0)
 	nn = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1640,7 +1632,7 @@
 func setgroups(n int, list *_Gid_t) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETGROUPS, uintptr(n), uintptr(unsafe.Pointer(list)), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1650,7 +1642,7 @@
 func getsockopt(s int, level int, name int, val unsafe.Pointer, vallen *_Socklen) (err error) {
 	_, _, e1 := Syscall6(SYS_GETSOCKOPT, uintptr(s), uintptr(level), uintptr(name), uintptr(val), uintptr(unsafe.Pointer(vallen)), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1660,7 +1652,7 @@
 func setsockopt(s int, level int, name int, val unsafe.Pointer, vallen uintptr) (err error) {
 	_, _, e1 := Syscall6(SYS_SETSOCKOPT, uintptr(s), uintptr(level), uintptr(name), uintptr(val), uintptr(vallen), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1671,7 +1663,7 @@
 	r0, _, e1 := RawSyscall(SYS_SOCKET, uintptr(domain), uintptr(typ), uintptr(proto))
 	fd = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1681,7 +1673,7 @@
 func socketpair(domain int, typ int, proto int, fd *[2]int32) (err error) {
 	_, _, e1 := RawSyscall6(SYS_SOCKETPAIR, uintptr(domain), uintptr(typ), uintptr(proto), uintptr(unsafe.Pointer(fd)), 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1691,7 +1683,7 @@
 func getpeername(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (err error) {
 	_, _, e1 := RawSyscall(SYS_GETPEERNAME, uintptr(fd), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1701,7 +1693,7 @@
 func getsockname(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (err error) {
 	_, _, e1 := RawSyscall(SYS_GETSOCKNAME, uintptr(fd), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1718,7 +1710,7 @@
 	r0, _, e1 := Syscall6(SYS_RECVFROM, uintptr(fd), uintptr(_p0), uintptr(len(p)), uintptr(flags), uintptr(unsafe.Pointer(from)), uintptr(unsafe.Pointer(fromlen)))
 	n = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1734,7 +1726,7 @@
 	}
 	_, _, e1 := Syscall6(SYS_SENDTO, uintptr(s), uintptr(_p0), uintptr(len(buf)), uintptr(flags), uintptr(to), uintptr(addrlen))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1745,7 +1737,7 @@
 	r0, _, e1 := Syscall(SYS_RECVMSG, uintptr(s), uintptr(unsafe.Pointer(msg)), uintptr(flags))
 	n = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1756,7 +1748,7 @@
 	r0, _, e1 := Syscall(SYS_SENDMSG, uintptr(s), uintptr(unsafe.Pointer(msg)), uintptr(flags))
 	n = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1767,7 +1759,7 @@
 	r0, _, e1 := Syscall6(SYS_MMAP, uintptr(addr), uintptr(length), uintptr(prot), uintptr(flags), uintptr(fd), uintptr(offset))
 	xaddr = uintptr(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1777,7 +1769,7 @@
 func Gettimeofday(tv *Timeval) (err error) {
 	_, _, e1 := RawSyscall(SYS_GETTIMEOFDAY, uintptr(unsafe.Pointer(tv)), 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1788,7 +1780,7 @@
 	r0, _, e1 := RawSyscall(SYS_TIME, uintptr(unsafe.Pointer(t)), 0, 0)
 	tt = Time_t(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1798,7 +1790,7 @@
 func pipe2(p *[2]_C_int, flags int) (err error) {
 	_, _, e1 := RawSyscall(SYS_PIPE2, uintptr(unsafe.Pointer(p)), uintptr(flags), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
diff --git a/src/syscall/zsyscall_nacl_386.go b/src/syscall/zsyscall_nacl_386.go
index 32eed33..d0ff66c 100644
--- a/src/syscall/zsyscall_nacl_386.go
+++ b/src/syscall/zsyscall_nacl_386.go
@@ -10,7 +10,7 @@
 func naclClose(fd int) (err error) {
 	_, _, e1 := Syscall(sys_close, uintptr(fd), 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -20,7 +20,7 @@
 func Exit(code int) (err error) {
 	_, _, e1 := Syscall(sys_exit, uintptr(code), 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -30,7 +30,7 @@
 func naclFstat(fd int, stat *Stat_t) (err error) {
 	_, _, e1 := Syscall(sys_fstat, uintptr(fd), uintptr(unsafe.Pointer(stat)), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -47,7 +47,7 @@
 	r0, _, e1 := Syscall(sys_read, uintptr(fd), uintptr(_p0), uintptr(len(b)))
 	n = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -57,7 +57,23 @@
 func naclSeek(fd int, off *int64, whence int) (err error) {
 	_, _, e1 := Syscall(sys_lseek, uintptr(fd), uintptr(unsafe.Pointer(off)), uintptr(whence))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func naclGetRandomBytes(b []byte) (err error) {
+	var _p0 unsafe.Pointer
+	if len(b) > 0 {
+		_p0 = unsafe.Pointer(&b[0])
+	} else {
+		_p0 = unsafe.Pointer(&_zero)
+	}
+	_, _, e1 := Syscall(sys_get_random_bytes, uintptr(_p0), uintptr(len(b)), 0)
+	if e1 != 0 {
+		err = errnoErr(e1)
 	}
 	return
 }
diff --git a/src/syscall/zsyscall_nacl_amd64p32.go b/src/syscall/zsyscall_nacl_amd64p32.go
index 8bc81fa..592c8d8 100644
--- a/src/syscall/zsyscall_nacl_amd64p32.go
+++ b/src/syscall/zsyscall_nacl_amd64p32.go
@@ -10,7 +10,7 @@
 func naclClose(fd int) (err error) {
 	_, _, e1 := Syscall(sys_close, uintptr(fd), 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -20,7 +20,7 @@
 func Exit(code int) (err error) {
 	_, _, e1 := Syscall(sys_exit, uintptr(code), 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -30,7 +30,7 @@
 func naclFstat(fd int, stat *Stat_t) (err error) {
 	_, _, e1 := Syscall(sys_fstat, uintptr(fd), uintptr(unsafe.Pointer(stat)), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -47,7 +47,7 @@
 	r0, _, e1 := Syscall(sys_read, uintptr(fd), uintptr(_p0), uintptr(len(b)))
 	n = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -57,7 +57,23 @@
 func naclSeek(fd int, off *int64, whence int) (err error) {
 	_, _, e1 := Syscall(sys_lseek, uintptr(fd), uintptr(unsafe.Pointer(off)), uintptr(whence))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func naclGetRandomBytes(b []byte) (err error) {
+	var _p0 unsafe.Pointer
+	if len(b) > 0 {
+		_p0 = unsafe.Pointer(&b[0])
+	} else {
+		_p0 = unsafe.Pointer(&_zero)
+	}
+	_, _, e1 := Syscall(sys_get_random_bytes, uintptr(_p0), uintptr(len(b)), 0)
+	if e1 != 0 {
+		err = errnoErr(e1)
 	}
 	return
 }
diff --git a/src/syscall/zsyscall_nacl_arm.go b/src/syscall/zsyscall_nacl_arm.go
index adbaed0..10657ad 100644
--- a/src/syscall/zsyscall_nacl_arm.go
+++ b/src/syscall/zsyscall_nacl_arm.go
@@ -10,7 +10,7 @@
 func naclClose(fd int) (err error) {
 	_, _, e1 := Syscall(sys_close, uintptr(fd), 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -20,7 +20,7 @@
 func Exit(code int) (err error) {
 	_, _, e1 := Syscall(sys_exit, uintptr(code), 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -30,7 +30,7 @@
 func naclFstat(fd int, stat *Stat_t) (err error) {
 	_, _, e1 := Syscall(sys_fstat, uintptr(fd), uintptr(unsafe.Pointer(stat)), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -47,7 +47,7 @@
 	r0, _, e1 := Syscall(sys_read, uintptr(fd), uintptr(_p0), uintptr(len(b)))
 	n = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -57,7 +57,23 @@
 func naclSeek(fd int, off *int64, whence int) (err error) {
 	_, _, e1 := Syscall(sys_lseek, uintptr(fd), uintptr(unsafe.Pointer(off)), uintptr(whence))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func naclGetRandomBytes(b []byte) (err error) {
+	var _p0 unsafe.Pointer
+	if len(b) > 0 {
+		_p0 = unsafe.Pointer(&b[0])
+	} else {
+		_p0 = unsafe.Pointer(&_zero)
+	}
+	_, _, e1 := Syscall(sys_get_random_bytes, uintptr(_p0), uintptr(len(b)), 0)
+	if e1 != 0 {
+		err = errnoErr(e1)
 	}
 	return
 }
diff --git a/src/syscall/zsyscall_netbsd_386.go b/src/syscall/zsyscall_netbsd_386.go
index e9bd3d0..5131c25 100644
--- a/src/syscall/zsyscall_netbsd_386.go
+++ b/src/syscall/zsyscall_netbsd_386.go
@@ -11,7 +11,7 @@
 	r0, _, e1 := RawSyscall(SYS_GETGROUPS, uintptr(ngid), uintptr(unsafe.Pointer(gid)), 0)
 	n = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -21,7 +21,7 @@
 func setgroups(ngid int, gid *_Gid_t) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETGROUPS, uintptr(ngid), uintptr(unsafe.Pointer(gid)), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -32,7 +32,7 @@
 	r0, _, e1 := Syscall6(SYS_WAIT4, uintptr(pid), uintptr(unsafe.Pointer(wstatus)), uintptr(options), uintptr(unsafe.Pointer(rusage)), 0, 0)
 	wpid = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -43,7 +43,7 @@
 	r0, _, e1 := Syscall(SYS_ACCEPT, uintptr(s), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)))
 	fd = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -53,7 +53,7 @@
 func bind(s int, addr unsafe.Pointer, addrlen _Socklen) (err error) {
 	_, _, e1 := Syscall(SYS_BIND, uintptr(s), uintptr(addr), uintptr(addrlen))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -63,7 +63,7 @@
 func connect(s int, addr unsafe.Pointer, addrlen _Socklen) (err error) {
 	_, _, e1 := Syscall(SYS_CONNECT, uintptr(s), uintptr(addr), uintptr(addrlen))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -74,7 +74,7 @@
 	r0, _, e1 := RawSyscall(SYS_SOCKET, uintptr(domain), uintptr(typ), uintptr(proto))
 	fd = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -84,7 +84,7 @@
 func getsockopt(s int, level int, name int, val unsafe.Pointer, vallen *_Socklen) (err error) {
 	_, _, e1 := Syscall6(SYS_GETSOCKOPT, uintptr(s), uintptr(level), uintptr(name), uintptr(val), uintptr(unsafe.Pointer(vallen)), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -94,7 +94,7 @@
 func setsockopt(s int, level int, name int, val unsafe.Pointer, vallen uintptr) (err error) {
 	_, _, e1 := Syscall6(SYS_SETSOCKOPT, uintptr(s), uintptr(level), uintptr(name), uintptr(val), uintptr(vallen), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -104,7 +104,7 @@
 func getpeername(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (err error) {
 	_, _, e1 := RawSyscall(SYS_GETPEERNAME, uintptr(fd), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -114,7 +114,7 @@
 func getsockname(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (err error) {
 	_, _, e1 := RawSyscall(SYS_GETSOCKNAME, uintptr(fd), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -124,7 +124,7 @@
 func Shutdown(s int, how int) (err error) {
 	_, _, e1 := Syscall(SYS_SHUTDOWN, uintptr(s), uintptr(how), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -134,7 +134,7 @@
 func socketpair(domain int, typ int, proto int, fd *[2]int32) (err error) {
 	_, _, e1 := RawSyscall6(SYS_SOCKETPAIR, uintptr(domain), uintptr(typ), uintptr(proto), uintptr(unsafe.Pointer(fd)), 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -151,7 +151,7 @@
 	r0, _, e1 := Syscall6(SYS_RECVFROM, uintptr(fd), uintptr(_p0), uintptr(len(p)), uintptr(flags), uintptr(unsafe.Pointer(from)), uintptr(unsafe.Pointer(fromlen)))
 	n = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -167,7 +167,7 @@
 	}
 	_, _, e1 := Syscall6(SYS_SENDTO, uintptr(s), uintptr(_p0), uintptr(len(buf)), uintptr(flags), uintptr(to), uintptr(addrlen))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -178,7 +178,7 @@
 	r0, _, e1 := Syscall(SYS_RECVMSG, uintptr(s), uintptr(unsafe.Pointer(msg)), uintptr(flags))
 	n = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -189,7 +189,7 @@
 	r0, _, e1 := Syscall(SYS_SENDMSG, uintptr(s), uintptr(unsafe.Pointer(msg)), uintptr(flags))
 	n = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -200,7 +200,7 @@
 	r0, _, e1 := Syscall6(SYS_KEVENT, uintptr(kq), uintptr(change), uintptr(nchange), uintptr(event), uintptr(nevent), uintptr(unsafe.Pointer(timeout)))
 	n = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -216,7 +216,7 @@
 	}
 	_, _, e1 := Syscall6(SYS___SYSCTL, uintptr(_p0), uintptr(len(mib)), uintptr(unsafe.Pointer(old)), uintptr(unsafe.Pointer(oldlen)), uintptr(unsafe.Pointer(new)), uintptr(newlen))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -232,7 +232,7 @@
 	_, _, e1 := Syscall(SYS_UTIMES, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(timeval)), 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -242,7 +242,7 @@
 func futimes(fd int, timeval *[2]Timeval) (err error) {
 	_, _, e1 := Syscall(SYS_FUTIMES, uintptr(fd), uintptr(unsafe.Pointer(timeval)), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -253,7 +253,7 @@
 	r0, _, e1 := Syscall(SYS_FCNTL, uintptr(fd), uintptr(cmd), uintptr(arg))
 	val = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -265,7 +265,7 @@
 	fd1 = int(r0)
 	fd2 = int(r1)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -282,7 +282,7 @@
 	r0, _, e1 := Syscall(SYS_GETDENTS, uintptr(fd), uintptr(_p0), uintptr(len(buf)))
 	n = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -298,7 +298,7 @@
 	_, _, e1 := Syscall(SYS_ACCESS, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -308,7 +308,7 @@
 func Adjtime(delta *Timeval, olddelta *Timeval) (err error) {
 	_, _, e1 := Syscall(SYS_ADJTIME, uintptr(unsafe.Pointer(delta)), uintptr(unsafe.Pointer(olddelta)), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -324,7 +324,7 @@
 	_, _, e1 := Syscall(SYS_CHDIR, uintptr(unsafe.Pointer(_p0)), 0, 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -340,7 +340,7 @@
 	_, _, e1 := Syscall(SYS_CHFLAGS, uintptr(unsafe.Pointer(_p0)), uintptr(flags), 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -356,7 +356,7 @@
 	_, _, e1 := Syscall(SYS_CHMOD, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -372,7 +372,7 @@
 	_, _, e1 := Syscall(SYS_CHOWN, uintptr(unsafe.Pointer(_p0)), uintptr(uid), uintptr(gid))
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -388,7 +388,7 @@
 	_, _, e1 := Syscall(SYS_CHROOT, uintptr(unsafe.Pointer(_p0)), 0, 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -398,7 +398,7 @@
 func Close(fd int) (err error) {
 	_, _, e1 := Syscall(SYS_CLOSE, uintptr(fd), 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -406,10 +406,10 @@
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
 func Dup(fd int) (nfd int, err error) {
-	r0, _, e1 := RawSyscall(SYS_DUP, uintptr(fd), 0, 0)
+	r0, _, e1 := Syscall(SYS_DUP, uintptr(fd), 0, 0)
 	nfd = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -417,9 +417,9 @@
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
 func Dup2(from int, to int) (err error) {
-	_, _, e1 := RawSyscall(SYS_DUP2, uintptr(from), uintptr(to), 0)
+	_, _, e1 := Syscall(SYS_DUP2, uintptr(from), uintptr(to), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -436,7 +436,7 @@
 func Fchdir(fd int) (err error) {
 	_, _, e1 := Syscall(SYS_FCHDIR, uintptr(fd), 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -446,7 +446,7 @@
 func Fchflags(fd int, flags int) (err error) {
 	_, _, e1 := Syscall(SYS_FCHFLAGS, uintptr(fd), uintptr(flags), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -456,7 +456,7 @@
 func Fchmod(fd int, mode uint32) (err error) {
 	_, _, e1 := Syscall(SYS_FCHMOD, uintptr(fd), uintptr(mode), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -466,7 +466,7 @@
 func Fchown(fd int, uid int, gid int) (err error) {
 	_, _, e1 := Syscall(SYS_FCHOWN, uintptr(fd), uintptr(uid), uintptr(gid))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -476,7 +476,7 @@
 func Flock(fd int, how int) (err error) {
 	_, _, e1 := Syscall(SYS_FLOCK, uintptr(fd), uintptr(how), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -487,7 +487,7 @@
 	r0, _, e1 := Syscall(SYS_FPATHCONF, uintptr(fd), uintptr(name), 0)
 	val = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -497,7 +497,7 @@
 func Fstat(fd int, stat *Stat_t) (err error) {
 	_, _, e1 := Syscall(SYS_FSTAT, uintptr(fd), uintptr(unsafe.Pointer(stat)), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -507,7 +507,7 @@
 func Fsync(fd int) (err error) {
 	_, _, e1 := Syscall(SYS_FSYNC, uintptr(fd), 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -517,7 +517,7 @@
 func Ftruncate(fd int, length int64) (err error) {
 	_, _, e1 := Syscall6(SYS_FTRUNCATE, uintptr(fd), 0, uintptr(length), uintptr(length>>32), 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -552,7 +552,7 @@
 	r0, _, e1 := RawSyscall(SYS_GETPGID, uintptr(pid), 0, 0)
 	pgid = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -587,7 +587,7 @@
 	r0, _, e1 := Syscall(SYS_GETPRIORITY, uintptr(which), uintptr(who), 0)
 	prio = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -597,7 +597,7 @@
 func Getrlimit(which int, lim *Rlimit) (err error) {
 	_, _, e1 := RawSyscall(SYS_GETRLIMIT, uintptr(which), uintptr(unsafe.Pointer(lim)), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -607,7 +607,7 @@
 func Getrusage(who int, rusage *Rusage) (err error) {
 	_, _, e1 := RawSyscall(SYS_GETRUSAGE, uintptr(who), uintptr(unsafe.Pointer(rusage)), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -618,7 +618,7 @@
 	r0, _, e1 := RawSyscall(SYS_GETSID, uintptr(pid), 0, 0)
 	sid = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -628,7 +628,7 @@
 func Gettimeofday(tv *Timeval) (err error) {
 	_, _, e1 := RawSyscall(SYS_GETTIMEOFDAY, uintptr(unsafe.Pointer(tv)), 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -654,7 +654,7 @@
 func Kill(pid int, signum Signal) (err error) {
 	_, _, e1 := Syscall(SYS_KILL, uintptr(pid), uintptr(signum), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -665,7 +665,7 @@
 	r0, _, e1 := Syscall(SYS_KQUEUE, 0, 0, 0)
 	fd = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -681,7 +681,7 @@
 	_, _, e1 := Syscall(SYS_LCHOWN, uintptr(unsafe.Pointer(_p0)), uintptr(uid), uintptr(gid))
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -703,7 +703,7 @@
 	use(unsafe.Pointer(_p0))
 	use(unsafe.Pointer(_p1))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -713,7 +713,7 @@
 func Listen(s int, backlog int) (err error) {
 	_, _, e1 := Syscall(SYS_LISTEN, uintptr(s), uintptr(backlog), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -729,7 +729,7 @@
 	_, _, e1 := Syscall(SYS_LSTAT, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -745,7 +745,7 @@
 	_, _, e1 := Syscall(SYS_MKDIR, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -761,7 +761,7 @@
 	_, _, e1 := Syscall(SYS_MKFIFO, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -777,7 +777,7 @@
 	_, _, e1 := Syscall(SYS_MKNOD, uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(dev))
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -787,7 +787,7 @@
 func Nanosleep(time *Timespec, leftover *Timespec) (err error) {
 	_, _, e1 := Syscall(SYS_NANOSLEEP, uintptr(unsafe.Pointer(time)), uintptr(unsafe.Pointer(leftover)), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -804,7 +804,7 @@
 	use(unsafe.Pointer(_p0))
 	fd = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -821,7 +821,7 @@
 	use(unsafe.Pointer(_p0))
 	val = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -838,7 +838,7 @@
 	r0, _, e1 := Syscall6(SYS_PREAD, uintptr(fd), uintptr(_p0), uintptr(len(p)), 0, uintptr(offset), uintptr(offset>>32))
 	n = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -855,7 +855,7 @@
 	r0, _, e1 := Syscall6(SYS_PWRITE, uintptr(fd), uintptr(_p0), uintptr(len(p)), 0, uintptr(offset), uintptr(offset>>32))
 	n = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -872,7 +872,7 @@
 	r0, _, e1 := Syscall(SYS_READ, uintptr(fd), uintptr(_p0), uintptr(len(p)))
 	n = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -895,7 +895,7 @@
 	use(unsafe.Pointer(_p0))
 	n = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -917,7 +917,7 @@
 	use(unsafe.Pointer(_p0))
 	use(unsafe.Pointer(_p1))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -933,7 +933,7 @@
 	_, _, e1 := Syscall(SYS_REVOKE, uintptr(unsafe.Pointer(_p0)), 0, 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -949,7 +949,7 @@
 	_, _, e1 := Syscall(SYS_RMDIR, uintptr(unsafe.Pointer(_p0)), 0, 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -960,7 +960,7 @@
 	r0, r1, e1 := Syscall6(SYS_LSEEK, uintptr(fd), 0, uintptr(offset), uintptr(offset>>32), uintptr(whence), 0)
 	newoffset = int64(int64(r1)<<32 | int64(r0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -970,7 +970,7 @@
 func Select(n int, r *FdSet, w *FdSet, e *FdSet, timeout *Timeval) (err error) {
 	_, _, e1 := Syscall6(SYS_SELECT, uintptr(n), uintptr(unsafe.Pointer(r)), uintptr(unsafe.Pointer(w)), uintptr(unsafe.Pointer(e)), uintptr(unsafe.Pointer(timeout)), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -980,7 +980,7 @@
 func Setegid(egid int) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETEGID, uintptr(egid), 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -990,7 +990,7 @@
 func Seteuid(euid int) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETEUID, uintptr(euid), 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1000,7 +1000,7 @@
 func Setgid(gid int) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETGID, uintptr(gid), 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1010,7 +1010,7 @@
 func Setpgid(pid int, pgid int) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETPGID, uintptr(pid), uintptr(pgid), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1020,7 +1020,7 @@
 func Setpriority(which int, who int, prio int) (err error) {
 	_, _, e1 := Syscall(SYS_SETPRIORITY, uintptr(which), uintptr(who), uintptr(prio))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1030,7 +1030,7 @@
 func Setregid(rgid int, egid int) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETREGID, uintptr(rgid), uintptr(egid), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1040,7 +1040,7 @@
 func Setreuid(ruid int, euid int) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETREUID, uintptr(ruid), uintptr(euid), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1050,7 +1050,7 @@
 func Setrlimit(which int, lim *Rlimit) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETRLIMIT, uintptr(which), uintptr(unsafe.Pointer(lim)), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1061,7 +1061,7 @@
 	r0, _, e1 := RawSyscall(SYS_SETSID, 0, 0, 0)
 	pid = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1071,7 +1071,7 @@
 func Settimeofday(tp *Timeval) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETTIMEOFDAY, uintptr(unsafe.Pointer(tp)), 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1081,7 +1081,7 @@
 func Setuid(uid int) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETUID, uintptr(uid), 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1097,7 +1097,7 @@
 	_, _, e1 := Syscall(SYS_STAT, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1119,7 +1119,7 @@
 	use(unsafe.Pointer(_p0))
 	use(unsafe.Pointer(_p1))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1129,7 +1129,7 @@
 func Sync() (err error) {
 	_, _, e1 := Syscall(SYS_SYNC, 0, 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1145,7 +1145,7 @@
 	_, _, e1 := Syscall6(SYS_TRUNCATE, uintptr(unsafe.Pointer(_p0)), 0, uintptr(length), uintptr(length>>32), 0, 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1169,7 +1169,7 @@
 	_, _, e1 := Syscall(SYS_UNLINK, uintptr(unsafe.Pointer(_p0)), 0, 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1185,7 +1185,7 @@
 	_, _, e1 := Syscall(SYS_UNMOUNT, uintptr(unsafe.Pointer(_p0)), uintptr(flags), 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1202,7 +1202,7 @@
 	r0, _, e1 := Syscall(SYS_WRITE, uintptr(fd), uintptr(_p0), uintptr(len(p)))
 	n = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1213,7 +1213,7 @@
 	r0, _, e1 := Syscall9(SYS_MMAP, uintptr(addr), uintptr(length), uintptr(prot), uintptr(flag), uintptr(fd), 0, uintptr(pos), uintptr(pos>>32), 0)
 	ret = uintptr(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1223,7 +1223,7 @@
 func munmap(addr uintptr, length uintptr) (err error) {
 	_, _, e1 := Syscall(SYS_MUNMAP, uintptr(addr), uintptr(length), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1234,7 +1234,7 @@
 	r0, _, e1 := Syscall(SYS_READ, uintptr(fd), uintptr(unsafe.Pointer(buf)), uintptr(nbuf))
 	n = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1245,7 +1245,7 @@
 	r0, _, e1 := Syscall(SYS_WRITE, uintptr(fd), uintptr(unsafe.Pointer(buf)), uintptr(nbuf))
 	n = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
diff --git a/src/syscall/zsyscall_netbsd_amd64.go b/src/syscall/zsyscall_netbsd_amd64.go
index 1acd7c2..0e26f68 100644
--- a/src/syscall/zsyscall_netbsd_amd64.go
+++ b/src/syscall/zsyscall_netbsd_amd64.go
@@ -11,7 +11,7 @@
 	r0, _, e1 := RawSyscall(SYS_GETGROUPS, uintptr(ngid), uintptr(unsafe.Pointer(gid)), 0)
 	n = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -21,7 +21,7 @@
 func setgroups(ngid int, gid *_Gid_t) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETGROUPS, uintptr(ngid), uintptr(unsafe.Pointer(gid)), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -32,7 +32,7 @@
 	r0, _, e1 := Syscall6(SYS_WAIT4, uintptr(pid), uintptr(unsafe.Pointer(wstatus)), uintptr(options), uintptr(unsafe.Pointer(rusage)), 0, 0)
 	wpid = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -43,7 +43,7 @@
 	r0, _, e1 := Syscall(SYS_ACCEPT, uintptr(s), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)))
 	fd = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -53,7 +53,7 @@
 func bind(s int, addr unsafe.Pointer, addrlen _Socklen) (err error) {
 	_, _, e1 := Syscall(SYS_BIND, uintptr(s), uintptr(addr), uintptr(addrlen))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -63,7 +63,7 @@
 func connect(s int, addr unsafe.Pointer, addrlen _Socklen) (err error) {
 	_, _, e1 := Syscall(SYS_CONNECT, uintptr(s), uintptr(addr), uintptr(addrlen))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -74,7 +74,7 @@
 	r0, _, e1 := RawSyscall(SYS_SOCKET, uintptr(domain), uintptr(typ), uintptr(proto))
 	fd = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -84,7 +84,7 @@
 func getsockopt(s int, level int, name int, val unsafe.Pointer, vallen *_Socklen) (err error) {
 	_, _, e1 := Syscall6(SYS_GETSOCKOPT, uintptr(s), uintptr(level), uintptr(name), uintptr(val), uintptr(unsafe.Pointer(vallen)), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -94,7 +94,7 @@
 func setsockopt(s int, level int, name int, val unsafe.Pointer, vallen uintptr) (err error) {
 	_, _, e1 := Syscall6(SYS_SETSOCKOPT, uintptr(s), uintptr(level), uintptr(name), uintptr(val), uintptr(vallen), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -104,7 +104,7 @@
 func getpeername(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (err error) {
 	_, _, e1 := RawSyscall(SYS_GETPEERNAME, uintptr(fd), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -114,7 +114,7 @@
 func getsockname(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (err error) {
 	_, _, e1 := RawSyscall(SYS_GETSOCKNAME, uintptr(fd), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -124,7 +124,7 @@
 func Shutdown(s int, how int) (err error) {
 	_, _, e1 := Syscall(SYS_SHUTDOWN, uintptr(s), uintptr(how), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -134,7 +134,7 @@
 func socketpair(domain int, typ int, proto int, fd *[2]int32) (err error) {
 	_, _, e1 := RawSyscall6(SYS_SOCKETPAIR, uintptr(domain), uintptr(typ), uintptr(proto), uintptr(unsafe.Pointer(fd)), 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -151,7 +151,7 @@
 	r0, _, e1 := Syscall6(SYS_RECVFROM, uintptr(fd), uintptr(_p0), uintptr(len(p)), uintptr(flags), uintptr(unsafe.Pointer(from)), uintptr(unsafe.Pointer(fromlen)))
 	n = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -167,7 +167,7 @@
 	}
 	_, _, e1 := Syscall6(SYS_SENDTO, uintptr(s), uintptr(_p0), uintptr(len(buf)), uintptr(flags), uintptr(to), uintptr(addrlen))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -178,7 +178,7 @@
 	r0, _, e1 := Syscall(SYS_RECVMSG, uintptr(s), uintptr(unsafe.Pointer(msg)), uintptr(flags))
 	n = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -189,7 +189,7 @@
 	r0, _, e1 := Syscall(SYS_SENDMSG, uintptr(s), uintptr(unsafe.Pointer(msg)), uintptr(flags))
 	n = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -200,7 +200,7 @@
 	r0, _, e1 := Syscall6(SYS_KEVENT, uintptr(kq), uintptr(change), uintptr(nchange), uintptr(event), uintptr(nevent), uintptr(unsafe.Pointer(timeout)))
 	n = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -216,7 +216,7 @@
 	}
 	_, _, e1 := Syscall6(SYS___SYSCTL, uintptr(_p0), uintptr(len(mib)), uintptr(unsafe.Pointer(old)), uintptr(unsafe.Pointer(oldlen)), uintptr(unsafe.Pointer(new)), uintptr(newlen))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -232,7 +232,7 @@
 	_, _, e1 := Syscall(SYS_UTIMES, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(timeval)), 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -242,7 +242,7 @@
 func futimes(fd int, timeval *[2]Timeval) (err error) {
 	_, _, e1 := Syscall(SYS_FUTIMES, uintptr(fd), uintptr(unsafe.Pointer(timeval)), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -253,7 +253,7 @@
 	r0, _, e1 := Syscall(SYS_FCNTL, uintptr(fd), uintptr(cmd), uintptr(arg))
 	val = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -265,7 +265,7 @@
 	fd1 = int(r0)
 	fd2 = int(r1)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -282,7 +282,7 @@
 	r0, _, e1 := Syscall(SYS_GETDENTS, uintptr(fd), uintptr(_p0), uintptr(len(buf)))
 	n = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -298,7 +298,7 @@
 	_, _, e1 := Syscall(SYS_ACCESS, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -308,7 +308,7 @@
 func Adjtime(delta *Timeval, olddelta *Timeval) (err error) {
 	_, _, e1 := Syscall(SYS_ADJTIME, uintptr(unsafe.Pointer(delta)), uintptr(unsafe.Pointer(olddelta)), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -324,7 +324,7 @@
 	_, _, e1 := Syscall(SYS_CHDIR, uintptr(unsafe.Pointer(_p0)), 0, 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -340,7 +340,7 @@
 	_, _, e1 := Syscall(SYS_CHFLAGS, uintptr(unsafe.Pointer(_p0)), uintptr(flags), 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -356,7 +356,7 @@
 	_, _, e1 := Syscall(SYS_CHMOD, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -372,7 +372,7 @@
 	_, _, e1 := Syscall(SYS_CHOWN, uintptr(unsafe.Pointer(_p0)), uintptr(uid), uintptr(gid))
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -388,7 +388,7 @@
 	_, _, e1 := Syscall(SYS_CHROOT, uintptr(unsafe.Pointer(_p0)), 0, 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -398,7 +398,7 @@
 func Close(fd int) (err error) {
 	_, _, e1 := Syscall(SYS_CLOSE, uintptr(fd), 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -406,10 +406,10 @@
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
 func Dup(fd int) (nfd int, err error) {
-	r0, _, e1 := RawSyscall(SYS_DUP, uintptr(fd), 0, 0)
+	r0, _, e1 := Syscall(SYS_DUP, uintptr(fd), 0, 0)
 	nfd = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -417,9 +417,9 @@
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
 func Dup2(from int, to int) (err error) {
-	_, _, e1 := RawSyscall(SYS_DUP2, uintptr(from), uintptr(to), 0)
+	_, _, e1 := Syscall(SYS_DUP2, uintptr(from), uintptr(to), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -436,7 +436,7 @@
 func Fchdir(fd int) (err error) {
 	_, _, e1 := Syscall(SYS_FCHDIR, uintptr(fd), 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -446,7 +446,7 @@
 func Fchflags(fd int, flags int) (err error) {
 	_, _, e1 := Syscall(SYS_FCHFLAGS, uintptr(fd), uintptr(flags), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -456,7 +456,7 @@
 func Fchmod(fd int, mode uint32) (err error) {
 	_, _, e1 := Syscall(SYS_FCHMOD, uintptr(fd), uintptr(mode), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -466,7 +466,7 @@
 func Fchown(fd int, uid int, gid int) (err error) {
 	_, _, e1 := Syscall(SYS_FCHOWN, uintptr(fd), uintptr(uid), uintptr(gid))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -476,7 +476,7 @@
 func Flock(fd int, how int) (err error) {
 	_, _, e1 := Syscall(SYS_FLOCK, uintptr(fd), uintptr(how), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -487,7 +487,7 @@
 	r0, _, e1 := Syscall(SYS_FPATHCONF, uintptr(fd), uintptr(name), 0)
 	val = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -497,7 +497,7 @@
 func Fstat(fd int, stat *Stat_t) (err error) {
 	_, _, e1 := Syscall(SYS_FSTAT, uintptr(fd), uintptr(unsafe.Pointer(stat)), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -507,7 +507,7 @@
 func Fsync(fd int) (err error) {
 	_, _, e1 := Syscall(SYS_FSYNC, uintptr(fd), 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -517,7 +517,7 @@
 func Ftruncate(fd int, length int64) (err error) {
 	_, _, e1 := Syscall(SYS_FTRUNCATE, uintptr(fd), 0, uintptr(length))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -552,7 +552,7 @@
 	r0, _, e1 := RawSyscall(SYS_GETPGID, uintptr(pid), 0, 0)
 	pgid = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -587,7 +587,7 @@
 	r0, _, e1 := Syscall(SYS_GETPRIORITY, uintptr(which), uintptr(who), 0)
 	prio = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -597,7 +597,7 @@
 func Getrlimit(which int, lim *Rlimit) (err error) {
 	_, _, e1 := RawSyscall(SYS_GETRLIMIT, uintptr(which), uintptr(unsafe.Pointer(lim)), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -607,7 +607,7 @@
 func Getrusage(who int, rusage *Rusage) (err error) {
 	_, _, e1 := RawSyscall(SYS_GETRUSAGE, uintptr(who), uintptr(unsafe.Pointer(rusage)), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -618,7 +618,7 @@
 	r0, _, e1 := RawSyscall(SYS_GETSID, uintptr(pid), 0, 0)
 	sid = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -628,7 +628,7 @@
 func Gettimeofday(tv *Timeval) (err error) {
 	_, _, e1 := RawSyscall(SYS_GETTIMEOFDAY, uintptr(unsafe.Pointer(tv)), 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -654,7 +654,7 @@
 func Kill(pid int, signum Signal) (err error) {
 	_, _, e1 := Syscall(SYS_KILL, uintptr(pid), uintptr(signum), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -665,7 +665,7 @@
 	r0, _, e1 := Syscall(SYS_KQUEUE, 0, 0, 0)
 	fd = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -681,7 +681,7 @@
 	_, _, e1 := Syscall(SYS_LCHOWN, uintptr(unsafe.Pointer(_p0)), uintptr(uid), uintptr(gid))
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -703,7 +703,7 @@
 	use(unsafe.Pointer(_p0))
 	use(unsafe.Pointer(_p1))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -713,7 +713,7 @@
 func Listen(s int, backlog int) (err error) {
 	_, _, e1 := Syscall(SYS_LISTEN, uintptr(s), uintptr(backlog), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -729,7 +729,7 @@
 	_, _, e1 := Syscall(SYS_LSTAT, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -745,7 +745,7 @@
 	_, _, e1 := Syscall(SYS_MKDIR, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -761,7 +761,7 @@
 	_, _, e1 := Syscall(SYS_MKFIFO, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -777,7 +777,7 @@
 	_, _, e1 := Syscall(SYS_MKNOD, uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(dev))
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -787,7 +787,7 @@
 func Nanosleep(time *Timespec, leftover *Timespec) (err error) {
 	_, _, e1 := Syscall(SYS_NANOSLEEP, uintptr(unsafe.Pointer(time)), uintptr(unsafe.Pointer(leftover)), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -804,7 +804,7 @@
 	use(unsafe.Pointer(_p0))
 	fd = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -821,7 +821,7 @@
 	use(unsafe.Pointer(_p0))
 	val = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -838,7 +838,7 @@
 	r0, _, e1 := Syscall6(SYS_PREAD, uintptr(fd), uintptr(_p0), uintptr(len(p)), 0, uintptr(offset), 0)
 	n = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -855,7 +855,7 @@
 	r0, _, e1 := Syscall6(SYS_PWRITE, uintptr(fd), uintptr(_p0), uintptr(len(p)), 0, uintptr(offset), 0)
 	n = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -872,7 +872,7 @@
 	r0, _, e1 := Syscall(SYS_READ, uintptr(fd), uintptr(_p0), uintptr(len(p)))
 	n = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -895,7 +895,7 @@
 	use(unsafe.Pointer(_p0))
 	n = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -917,7 +917,7 @@
 	use(unsafe.Pointer(_p0))
 	use(unsafe.Pointer(_p1))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -933,7 +933,7 @@
 	_, _, e1 := Syscall(SYS_REVOKE, uintptr(unsafe.Pointer(_p0)), 0, 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -949,7 +949,7 @@
 	_, _, e1 := Syscall(SYS_RMDIR, uintptr(unsafe.Pointer(_p0)), 0, 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -960,7 +960,7 @@
 	r0, _, e1 := Syscall6(SYS_LSEEK, uintptr(fd), 0, uintptr(offset), uintptr(whence), 0, 0)
 	newoffset = int64(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -970,7 +970,7 @@
 func Select(n int, r *FdSet, w *FdSet, e *FdSet, timeout *Timeval) (err error) {
 	_, _, e1 := Syscall6(SYS_SELECT, uintptr(n), uintptr(unsafe.Pointer(r)), uintptr(unsafe.Pointer(w)), uintptr(unsafe.Pointer(e)), uintptr(unsafe.Pointer(timeout)), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -980,7 +980,7 @@
 func Setegid(egid int) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETEGID, uintptr(egid), 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -990,7 +990,7 @@
 func Seteuid(euid int) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETEUID, uintptr(euid), 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1000,7 +1000,7 @@
 func Setgid(gid int) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETGID, uintptr(gid), 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1010,7 +1010,7 @@
 func Setpgid(pid int, pgid int) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETPGID, uintptr(pid), uintptr(pgid), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1020,7 +1020,7 @@
 func Setpriority(which int, who int, prio int) (err error) {
 	_, _, e1 := Syscall(SYS_SETPRIORITY, uintptr(which), uintptr(who), uintptr(prio))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1030,7 +1030,7 @@
 func Setregid(rgid int, egid int) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETREGID, uintptr(rgid), uintptr(egid), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1040,7 +1040,7 @@
 func Setreuid(ruid int, euid int) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETREUID, uintptr(ruid), uintptr(euid), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1050,7 +1050,7 @@
 func Setrlimit(which int, lim *Rlimit) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETRLIMIT, uintptr(which), uintptr(unsafe.Pointer(lim)), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1061,7 +1061,7 @@
 	r0, _, e1 := RawSyscall(SYS_SETSID, 0, 0, 0)
 	pid = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1071,7 +1071,7 @@
 func Settimeofday(tp *Timeval) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETTIMEOFDAY, uintptr(unsafe.Pointer(tp)), 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1081,7 +1081,7 @@
 func Setuid(uid int) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETUID, uintptr(uid), 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1097,7 +1097,7 @@
 	_, _, e1 := Syscall(SYS_STAT, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1119,7 +1119,7 @@
 	use(unsafe.Pointer(_p0))
 	use(unsafe.Pointer(_p1))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1129,7 +1129,7 @@
 func Sync() (err error) {
 	_, _, e1 := Syscall(SYS_SYNC, 0, 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1145,7 +1145,7 @@
 	_, _, e1 := Syscall(SYS_TRUNCATE, uintptr(unsafe.Pointer(_p0)), 0, uintptr(length))
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1169,7 +1169,7 @@
 	_, _, e1 := Syscall(SYS_UNLINK, uintptr(unsafe.Pointer(_p0)), 0, 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1185,7 +1185,7 @@
 	_, _, e1 := Syscall(SYS_UNMOUNT, uintptr(unsafe.Pointer(_p0)), uintptr(flags), 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1202,7 +1202,7 @@
 	r0, _, e1 := Syscall(SYS_WRITE, uintptr(fd), uintptr(_p0), uintptr(len(p)))
 	n = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1213,7 +1213,7 @@
 	r0, _, e1 := Syscall9(SYS_MMAP, uintptr(addr), uintptr(length), uintptr(prot), uintptr(flag), uintptr(fd), 0, uintptr(pos), 0, 0)
 	ret = uintptr(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1223,7 +1223,7 @@
 func munmap(addr uintptr, length uintptr) (err error) {
 	_, _, e1 := Syscall(SYS_MUNMAP, uintptr(addr), uintptr(length), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1234,7 +1234,7 @@
 	r0, _, e1 := Syscall(SYS_READ, uintptr(fd), uintptr(unsafe.Pointer(buf)), uintptr(nbuf))
 	n = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1245,7 +1245,7 @@
 	r0, _, e1 := Syscall(SYS_WRITE, uintptr(fd), uintptr(unsafe.Pointer(buf)), uintptr(nbuf))
 	n = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
diff --git a/src/syscall/zsyscall_netbsd_arm.go b/src/syscall/zsyscall_netbsd_arm.go
index 898e0ce..4aae104 100644
--- a/src/syscall/zsyscall_netbsd_arm.go
+++ b/src/syscall/zsyscall_netbsd_arm.go
@@ -11,7 +11,7 @@
 	r0, _, e1 := RawSyscall(SYS_GETGROUPS, uintptr(ngid), uintptr(unsafe.Pointer(gid)), 0)
 	n = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -21,7 +21,7 @@
 func setgroups(ngid int, gid *_Gid_t) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETGROUPS, uintptr(ngid), uintptr(unsafe.Pointer(gid)), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -32,7 +32,7 @@
 	r0, _, e1 := Syscall6(SYS_WAIT4, uintptr(pid), uintptr(unsafe.Pointer(wstatus)), uintptr(options), uintptr(unsafe.Pointer(rusage)), 0, 0)
 	wpid = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -43,7 +43,7 @@
 	r0, _, e1 := Syscall(SYS_ACCEPT, uintptr(s), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)))
 	fd = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -53,7 +53,7 @@
 func bind(s int, addr unsafe.Pointer, addrlen _Socklen) (err error) {
 	_, _, e1 := Syscall(SYS_BIND, uintptr(s), uintptr(addr), uintptr(addrlen))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -63,7 +63,7 @@
 func connect(s int, addr unsafe.Pointer, addrlen _Socklen) (err error) {
 	_, _, e1 := Syscall(SYS_CONNECT, uintptr(s), uintptr(addr), uintptr(addrlen))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -74,7 +74,7 @@
 	r0, _, e1 := RawSyscall(SYS_SOCKET, uintptr(domain), uintptr(typ), uintptr(proto))
 	fd = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -84,7 +84,7 @@
 func getsockopt(s int, level int, name int, val unsafe.Pointer, vallen *_Socklen) (err error) {
 	_, _, e1 := Syscall6(SYS_GETSOCKOPT, uintptr(s), uintptr(level), uintptr(name), uintptr(val), uintptr(unsafe.Pointer(vallen)), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -94,7 +94,7 @@
 func setsockopt(s int, level int, name int, val unsafe.Pointer, vallen uintptr) (err error) {
 	_, _, e1 := Syscall6(SYS_SETSOCKOPT, uintptr(s), uintptr(level), uintptr(name), uintptr(val), uintptr(vallen), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -104,7 +104,7 @@
 func getpeername(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (err error) {
 	_, _, e1 := RawSyscall(SYS_GETPEERNAME, uintptr(fd), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -114,7 +114,7 @@
 func getsockname(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (err error) {
 	_, _, e1 := RawSyscall(SYS_GETSOCKNAME, uintptr(fd), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -124,7 +124,7 @@
 func Shutdown(s int, how int) (err error) {
 	_, _, e1 := Syscall(SYS_SHUTDOWN, uintptr(s), uintptr(how), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -134,7 +134,7 @@
 func socketpair(domain int, typ int, proto int, fd *[2]int32) (err error) {
 	_, _, e1 := RawSyscall6(SYS_SOCKETPAIR, uintptr(domain), uintptr(typ), uintptr(proto), uintptr(unsafe.Pointer(fd)), 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -151,7 +151,7 @@
 	r0, _, e1 := Syscall6(SYS_RECVFROM, uintptr(fd), uintptr(_p0), uintptr(len(p)), uintptr(flags), uintptr(unsafe.Pointer(from)), uintptr(unsafe.Pointer(fromlen)))
 	n = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -167,7 +167,7 @@
 	}
 	_, _, e1 := Syscall6(SYS_SENDTO, uintptr(s), uintptr(_p0), uintptr(len(buf)), uintptr(flags), uintptr(to), uintptr(addrlen))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -178,7 +178,7 @@
 	r0, _, e1 := Syscall(SYS_RECVMSG, uintptr(s), uintptr(unsafe.Pointer(msg)), uintptr(flags))
 	n = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -189,7 +189,7 @@
 	r0, _, e1 := Syscall(SYS_SENDMSG, uintptr(s), uintptr(unsafe.Pointer(msg)), uintptr(flags))
 	n = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -200,7 +200,7 @@
 	r0, _, e1 := Syscall6(SYS_KEVENT, uintptr(kq), uintptr(change), uintptr(nchange), uintptr(event), uintptr(nevent), uintptr(unsafe.Pointer(timeout)))
 	n = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -216,7 +216,7 @@
 	}
 	_, _, e1 := Syscall6(SYS___SYSCTL, uintptr(_p0), uintptr(len(mib)), uintptr(unsafe.Pointer(old)), uintptr(unsafe.Pointer(oldlen)), uintptr(unsafe.Pointer(new)), uintptr(newlen))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -232,7 +232,7 @@
 	_, _, e1 := Syscall(SYS_UTIMES, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(timeval)), 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -242,7 +242,7 @@
 func futimes(fd int, timeval *[2]Timeval) (err error) {
 	_, _, e1 := Syscall(SYS_FUTIMES, uintptr(fd), uintptr(unsafe.Pointer(timeval)), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -253,7 +253,7 @@
 	r0, _, e1 := Syscall(SYS_FCNTL, uintptr(fd), uintptr(cmd), uintptr(arg))
 	val = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -265,7 +265,7 @@
 	fd1 = int(r0)
 	fd2 = int(r1)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -282,7 +282,7 @@
 	r0, _, e1 := Syscall(SYS_GETDENTS, uintptr(fd), uintptr(_p0), uintptr(len(buf)))
 	n = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -298,7 +298,7 @@
 	_, _, e1 := Syscall(SYS_ACCESS, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -308,7 +308,7 @@
 func Adjtime(delta *Timeval, olddelta *Timeval) (err error) {
 	_, _, e1 := Syscall(SYS_ADJTIME, uintptr(unsafe.Pointer(delta)), uintptr(unsafe.Pointer(olddelta)), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -324,7 +324,7 @@
 	_, _, e1 := Syscall(SYS_CHDIR, uintptr(unsafe.Pointer(_p0)), 0, 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -340,7 +340,7 @@
 	_, _, e1 := Syscall(SYS_CHFLAGS, uintptr(unsafe.Pointer(_p0)), uintptr(flags), 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -356,7 +356,7 @@
 	_, _, e1 := Syscall(SYS_CHMOD, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -372,7 +372,7 @@
 	_, _, e1 := Syscall(SYS_CHOWN, uintptr(unsafe.Pointer(_p0)), uintptr(uid), uintptr(gid))
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -388,7 +388,7 @@
 	_, _, e1 := Syscall(SYS_CHROOT, uintptr(unsafe.Pointer(_p0)), 0, 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -398,7 +398,7 @@
 func Close(fd int) (err error) {
 	_, _, e1 := Syscall(SYS_CLOSE, uintptr(fd), 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -406,10 +406,10 @@
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
 func Dup(fd int) (nfd int, err error) {
-	r0, _, e1 := RawSyscall(SYS_DUP, uintptr(fd), 0, 0)
+	r0, _, e1 := Syscall(SYS_DUP, uintptr(fd), 0, 0)
 	nfd = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -417,9 +417,9 @@
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
 func Dup2(from int, to int) (err error) {
-	_, _, e1 := RawSyscall(SYS_DUP2, uintptr(from), uintptr(to), 0)
+	_, _, e1 := Syscall(SYS_DUP2, uintptr(from), uintptr(to), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -436,7 +436,7 @@
 func Fchdir(fd int) (err error) {
 	_, _, e1 := Syscall(SYS_FCHDIR, uintptr(fd), 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -446,7 +446,7 @@
 func Fchflags(fd int, flags int) (err error) {
 	_, _, e1 := Syscall(SYS_FCHFLAGS, uintptr(fd), uintptr(flags), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -456,7 +456,7 @@
 func Fchmod(fd int, mode uint32) (err error) {
 	_, _, e1 := Syscall(SYS_FCHMOD, uintptr(fd), uintptr(mode), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -466,7 +466,7 @@
 func Fchown(fd int, uid int, gid int) (err error) {
 	_, _, e1 := Syscall(SYS_FCHOWN, uintptr(fd), uintptr(uid), uintptr(gid))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -476,7 +476,7 @@
 func Flock(fd int, how int) (err error) {
 	_, _, e1 := Syscall(SYS_FLOCK, uintptr(fd), uintptr(how), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -487,7 +487,7 @@
 	r0, _, e1 := Syscall(SYS_FPATHCONF, uintptr(fd), uintptr(name), 0)
 	val = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -497,7 +497,7 @@
 func Fstat(fd int, stat *Stat_t) (err error) {
 	_, _, e1 := Syscall(SYS_FSTAT, uintptr(fd), uintptr(unsafe.Pointer(stat)), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -507,7 +507,7 @@
 func Fsync(fd int) (err error) {
 	_, _, e1 := Syscall(SYS_FSYNC, uintptr(fd), 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -517,7 +517,7 @@
 func Ftruncate(fd int, length int64) (err error) {
 	_, _, e1 := Syscall6(SYS_FTRUNCATE, uintptr(fd), 0, uintptr(length), uintptr(length>>32), 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -552,7 +552,7 @@
 	r0, _, e1 := RawSyscall(SYS_GETPGID, uintptr(pid), 0, 0)
 	pgid = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -587,7 +587,7 @@
 	r0, _, e1 := Syscall(SYS_GETPRIORITY, uintptr(which), uintptr(who), 0)
 	prio = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -597,7 +597,7 @@
 func Getrlimit(which int, lim *Rlimit) (err error) {
 	_, _, e1 := RawSyscall(SYS_GETRLIMIT, uintptr(which), uintptr(unsafe.Pointer(lim)), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -607,7 +607,7 @@
 func Getrusage(who int, rusage *Rusage) (err error) {
 	_, _, e1 := RawSyscall(SYS_GETRUSAGE, uintptr(who), uintptr(unsafe.Pointer(rusage)), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -618,7 +618,7 @@
 	r0, _, e1 := RawSyscall(SYS_GETSID, uintptr(pid), 0, 0)
 	sid = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -628,7 +628,7 @@
 func Gettimeofday(tv *Timeval) (err error) {
 	_, _, e1 := RawSyscall(SYS_GETTIMEOFDAY, uintptr(unsafe.Pointer(tv)), 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -654,7 +654,7 @@
 func Kill(pid int, signum Signal) (err error) {
 	_, _, e1 := Syscall(SYS_KILL, uintptr(pid), uintptr(signum), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -665,7 +665,7 @@
 	r0, _, e1 := Syscall(SYS_KQUEUE, 0, 0, 0)
 	fd = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -681,7 +681,7 @@
 	_, _, e1 := Syscall(SYS_LCHOWN, uintptr(unsafe.Pointer(_p0)), uintptr(uid), uintptr(gid))
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -703,7 +703,7 @@
 	use(unsafe.Pointer(_p0))
 	use(unsafe.Pointer(_p1))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -713,7 +713,7 @@
 func Listen(s int, backlog int) (err error) {
 	_, _, e1 := Syscall(SYS_LISTEN, uintptr(s), uintptr(backlog), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -729,7 +729,7 @@
 	_, _, e1 := Syscall(SYS_LSTAT, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -745,7 +745,7 @@
 	_, _, e1 := Syscall(SYS_MKDIR, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -761,7 +761,7 @@
 	_, _, e1 := Syscall(SYS_MKFIFO, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -777,7 +777,7 @@
 	_, _, e1 := Syscall(SYS_MKNOD, uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(dev))
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -787,7 +787,7 @@
 func Nanosleep(time *Timespec, leftover *Timespec) (err error) {
 	_, _, e1 := Syscall(SYS_NANOSLEEP, uintptr(unsafe.Pointer(time)), uintptr(unsafe.Pointer(leftover)), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -804,7 +804,7 @@
 	use(unsafe.Pointer(_p0))
 	fd = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -821,7 +821,7 @@
 	use(unsafe.Pointer(_p0))
 	val = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -838,7 +838,7 @@
 	r0, _, e1 := Syscall6(SYS_PREAD, uintptr(fd), uintptr(_p0), uintptr(len(p)), 0, uintptr(offset), uintptr(offset>>32))
 	n = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -855,7 +855,7 @@
 	r0, _, e1 := Syscall6(SYS_PWRITE, uintptr(fd), uintptr(_p0), uintptr(len(p)), 0, uintptr(offset), uintptr(offset>>32))
 	n = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -872,7 +872,7 @@
 	r0, _, e1 := Syscall(SYS_READ, uintptr(fd), uintptr(_p0), uintptr(len(p)))
 	n = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -895,7 +895,7 @@
 	use(unsafe.Pointer(_p0))
 	n = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -917,7 +917,7 @@
 	use(unsafe.Pointer(_p0))
 	use(unsafe.Pointer(_p1))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -933,7 +933,7 @@
 	_, _, e1 := Syscall(SYS_REVOKE, uintptr(unsafe.Pointer(_p0)), 0, 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -949,7 +949,7 @@
 	_, _, e1 := Syscall(SYS_RMDIR, uintptr(unsafe.Pointer(_p0)), 0, 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -960,7 +960,7 @@
 	r0, r1, e1 := Syscall6(SYS_LSEEK, uintptr(fd), 0, uintptr(offset), uintptr(offset>>32), uintptr(whence), 0)
 	newoffset = int64(int64(r1)<<32 | int64(r0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -970,7 +970,7 @@
 func Select(n int, r *FdSet, w *FdSet, e *FdSet, timeout *Timeval) (err error) {
 	_, _, e1 := Syscall6(SYS_SELECT, uintptr(n), uintptr(unsafe.Pointer(r)), uintptr(unsafe.Pointer(w)), uintptr(unsafe.Pointer(e)), uintptr(unsafe.Pointer(timeout)), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -980,7 +980,7 @@
 func Setegid(egid int) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETEGID, uintptr(egid), 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -990,7 +990,7 @@
 func Seteuid(euid int) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETEUID, uintptr(euid), 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1000,7 +1000,7 @@
 func Setgid(gid int) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETGID, uintptr(gid), 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1010,7 +1010,7 @@
 func Setpgid(pid int, pgid int) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETPGID, uintptr(pid), uintptr(pgid), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1020,7 +1020,7 @@
 func Setpriority(which int, who int, prio int) (err error) {
 	_, _, e1 := Syscall(SYS_SETPRIORITY, uintptr(which), uintptr(who), uintptr(prio))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1030,7 +1030,7 @@
 func Setregid(rgid int, egid int) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETREGID, uintptr(rgid), uintptr(egid), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1040,7 +1040,7 @@
 func Setreuid(ruid int, euid int) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETREUID, uintptr(ruid), uintptr(euid), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1050,7 +1050,7 @@
 func Setrlimit(which int, lim *Rlimit) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETRLIMIT, uintptr(which), uintptr(unsafe.Pointer(lim)), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1061,7 +1061,7 @@
 	r0, _, e1 := RawSyscall(SYS_SETSID, 0, 0, 0)
 	pid = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1071,7 +1071,7 @@
 func Settimeofday(tp *Timeval) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETTIMEOFDAY, uintptr(unsafe.Pointer(tp)), 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1081,7 +1081,7 @@
 func Setuid(uid int) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETUID, uintptr(uid), 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1097,7 +1097,7 @@
 	_, _, e1 := Syscall(SYS_STAT, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1119,7 +1119,7 @@
 	use(unsafe.Pointer(_p0))
 	use(unsafe.Pointer(_p1))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1129,7 +1129,7 @@
 func Sync() (err error) {
 	_, _, e1 := Syscall(SYS_SYNC, 0, 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1145,7 +1145,7 @@
 	_, _, e1 := Syscall6(SYS_TRUNCATE, uintptr(unsafe.Pointer(_p0)), 0, uintptr(length), uintptr(length>>32), 0, 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1169,7 +1169,7 @@
 	_, _, e1 := Syscall(SYS_UNLINK, uintptr(unsafe.Pointer(_p0)), 0, 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1185,7 +1185,7 @@
 	_, _, e1 := Syscall(SYS_UNMOUNT, uintptr(unsafe.Pointer(_p0)), uintptr(flags), 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1202,7 +1202,7 @@
 	r0, _, e1 := Syscall(SYS_WRITE, uintptr(fd), uintptr(_p0), uintptr(len(p)))
 	n = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1213,7 +1213,7 @@
 	r0, _, e1 := Syscall9(SYS_MMAP, uintptr(addr), uintptr(length), uintptr(prot), uintptr(flag), uintptr(fd), 0, uintptr(pos), uintptr(pos>>32), 0)
 	ret = uintptr(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1223,7 +1223,7 @@
 func munmap(addr uintptr, length uintptr) (err error) {
 	_, _, e1 := Syscall(SYS_MUNMAP, uintptr(addr), uintptr(length), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1234,7 +1234,7 @@
 	r0, _, e1 := Syscall(SYS_READ, uintptr(fd), uintptr(unsafe.Pointer(buf)), uintptr(nbuf))
 	n = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1245,7 +1245,7 @@
 	r0, _, e1 := Syscall(SYS_WRITE, uintptr(fd), uintptr(unsafe.Pointer(buf)), uintptr(nbuf))
 	n = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
diff --git a/src/syscall/zsyscall_openbsd_386.go b/src/syscall/zsyscall_openbsd_386.go
index 5b005d2..f6a1983 100644
--- a/src/syscall/zsyscall_openbsd_386.go
+++ b/src/syscall/zsyscall_openbsd_386.go
@@ -11,7 +11,7 @@
 	r0, _, e1 := RawSyscall(SYS_GETGROUPS, uintptr(ngid), uintptr(unsafe.Pointer(gid)), 0)
 	n = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -21,7 +21,7 @@
 func setgroups(ngid int, gid *_Gid_t) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETGROUPS, uintptr(ngid), uintptr(unsafe.Pointer(gid)), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -32,7 +32,7 @@
 	r0, _, e1 := Syscall6(SYS_WAIT4, uintptr(pid), uintptr(unsafe.Pointer(wstatus)), uintptr(options), uintptr(unsafe.Pointer(rusage)), 0, 0)
 	wpid = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -43,7 +43,7 @@
 	r0, _, e1 := Syscall(SYS_ACCEPT, uintptr(s), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)))
 	fd = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -53,7 +53,7 @@
 func bind(s int, addr unsafe.Pointer, addrlen _Socklen) (err error) {
 	_, _, e1 := Syscall(SYS_BIND, uintptr(s), uintptr(addr), uintptr(addrlen))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -63,7 +63,7 @@
 func connect(s int, addr unsafe.Pointer, addrlen _Socklen) (err error) {
 	_, _, e1 := Syscall(SYS_CONNECT, uintptr(s), uintptr(addr), uintptr(addrlen))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -74,7 +74,7 @@
 	r0, _, e1 := RawSyscall(SYS_SOCKET, uintptr(domain), uintptr(typ), uintptr(proto))
 	fd = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -84,7 +84,7 @@
 func getsockopt(s int, level int, name int, val unsafe.Pointer, vallen *_Socklen) (err error) {
 	_, _, e1 := Syscall6(SYS_GETSOCKOPT, uintptr(s), uintptr(level), uintptr(name), uintptr(val), uintptr(unsafe.Pointer(vallen)), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -94,7 +94,7 @@
 func setsockopt(s int, level int, name int, val unsafe.Pointer, vallen uintptr) (err error) {
 	_, _, e1 := Syscall6(SYS_SETSOCKOPT, uintptr(s), uintptr(level), uintptr(name), uintptr(val), uintptr(vallen), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -104,7 +104,7 @@
 func getpeername(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (err error) {
 	_, _, e1 := RawSyscall(SYS_GETPEERNAME, uintptr(fd), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -114,7 +114,7 @@
 func getsockname(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (err error) {
 	_, _, e1 := RawSyscall(SYS_GETSOCKNAME, uintptr(fd), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -124,7 +124,7 @@
 func Shutdown(s int, how int) (err error) {
 	_, _, e1 := Syscall(SYS_SHUTDOWN, uintptr(s), uintptr(how), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -134,7 +134,7 @@
 func socketpair(domain int, typ int, proto int, fd *[2]int32) (err error) {
 	_, _, e1 := RawSyscall6(SYS_SOCKETPAIR, uintptr(domain), uintptr(typ), uintptr(proto), uintptr(unsafe.Pointer(fd)), 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -151,7 +151,7 @@
 	r0, _, e1 := Syscall6(SYS_RECVFROM, uintptr(fd), uintptr(_p0), uintptr(len(p)), uintptr(flags), uintptr(unsafe.Pointer(from)), uintptr(unsafe.Pointer(fromlen)))
 	n = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -167,7 +167,7 @@
 	}
 	_, _, e1 := Syscall6(SYS_SENDTO, uintptr(s), uintptr(_p0), uintptr(len(buf)), uintptr(flags), uintptr(to), uintptr(addrlen))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -178,7 +178,7 @@
 	r0, _, e1 := Syscall(SYS_RECVMSG, uintptr(s), uintptr(unsafe.Pointer(msg)), uintptr(flags))
 	n = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -189,7 +189,7 @@
 	r0, _, e1 := Syscall(SYS_SENDMSG, uintptr(s), uintptr(unsafe.Pointer(msg)), uintptr(flags))
 	n = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -200,7 +200,7 @@
 	r0, _, e1 := Syscall6(SYS_KEVENT, uintptr(kq), uintptr(change), uintptr(nchange), uintptr(event), uintptr(nevent), uintptr(unsafe.Pointer(timeout)))
 	n = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -216,7 +216,7 @@
 	}
 	_, _, e1 := Syscall6(SYS___SYSCTL, uintptr(_p0), uintptr(len(mib)), uintptr(unsafe.Pointer(old)), uintptr(unsafe.Pointer(oldlen)), uintptr(unsafe.Pointer(new)), uintptr(newlen))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -232,7 +232,7 @@
 	_, _, e1 := Syscall(SYS_UTIMES, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(timeval)), 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -242,7 +242,7 @@
 func futimes(fd int, timeval *[2]Timeval) (err error) {
 	_, _, e1 := Syscall(SYS_FUTIMES, uintptr(fd), uintptr(unsafe.Pointer(timeval)), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -253,7 +253,7 @@
 	r0, _, e1 := Syscall(SYS_FCNTL, uintptr(fd), uintptr(cmd), uintptr(arg))
 	val = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -263,7 +263,7 @@
 func pipe(p *[2]_C_int) (err error) {
 	_, _, e1 := RawSyscall(SYS_PIPE, uintptr(unsafe.Pointer(p)), 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -280,7 +280,7 @@
 	r0, _, e1 := Syscall(SYS_GETDENTS, uintptr(fd), uintptr(_p0), uintptr(len(buf)))
 	n = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -296,7 +296,7 @@
 	_, _, e1 := Syscall(SYS_ACCESS, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -306,7 +306,7 @@
 func Adjtime(delta *Timeval, olddelta *Timeval) (err error) {
 	_, _, e1 := Syscall(SYS_ADJTIME, uintptr(unsafe.Pointer(delta)), uintptr(unsafe.Pointer(olddelta)), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -322,7 +322,7 @@
 	_, _, e1 := Syscall(SYS_CHDIR, uintptr(unsafe.Pointer(_p0)), 0, 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -338,7 +338,7 @@
 	_, _, e1 := Syscall(SYS_CHFLAGS, uintptr(unsafe.Pointer(_p0)), uintptr(flags), 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -354,7 +354,7 @@
 	_, _, e1 := Syscall(SYS_CHMOD, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -370,7 +370,7 @@
 	_, _, e1 := Syscall(SYS_CHOWN, uintptr(unsafe.Pointer(_p0)), uintptr(uid), uintptr(gid))
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -386,7 +386,7 @@
 	_, _, e1 := Syscall(SYS_CHROOT, uintptr(unsafe.Pointer(_p0)), 0, 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -396,7 +396,7 @@
 func Close(fd int) (err error) {
 	_, _, e1 := Syscall(SYS_CLOSE, uintptr(fd), 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -404,10 +404,10 @@
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
 func Dup(fd int) (nfd int, err error) {
-	r0, _, e1 := RawSyscall(SYS_DUP, uintptr(fd), 0, 0)
+	r0, _, e1 := Syscall(SYS_DUP, uintptr(fd), 0, 0)
 	nfd = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -415,9 +415,9 @@
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
 func Dup2(from int, to int) (err error) {
-	_, _, e1 := RawSyscall(SYS_DUP2, uintptr(from), uintptr(to), 0)
+	_, _, e1 := Syscall(SYS_DUP2, uintptr(from), uintptr(to), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -434,7 +434,7 @@
 func Fchdir(fd int) (err error) {
 	_, _, e1 := Syscall(SYS_FCHDIR, uintptr(fd), 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -444,7 +444,7 @@
 func Fchflags(fd int, flags int) (err error) {
 	_, _, e1 := Syscall(SYS_FCHFLAGS, uintptr(fd), uintptr(flags), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -454,7 +454,7 @@
 func Fchmod(fd int, mode uint32) (err error) {
 	_, _, e1 := Syscall(SYS_FCHMOD, uintptr(fd), uintptr(mode), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -464,7 +464,7 @@
 func Fchown(fd int, uid int, gid int) (err error) {
 	_, _, e1 := Syscall(SYS_FCHOWN, uintptr(fd), uintptr(uid), uintptr(gid))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -474,7 +474,7 @@
 func Flock(fd int, how int) (err error) {
 	_, _, e1 := Syscall(SYS_FLOCK, uintptr(fd), uintptr(how), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -485,7 +485,7 @@
 	r0, _, e1 := Syscall(SYS_FPATHCONF, uintptr(fd), uintptr(name), 0)
 	val = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -495,7 +495,7 @@
 func Fstat(fd int, stat *Stat_t) (err error) {
 	_, _, e1 := Syscall(SYS_FSTAT, uintptr(fd), uintptr(unsafe.Pointer(stat)), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -505,7 +505,7 @@
 func Fstatfs(fd int, stat *Statfs_t) (err error) {
 	_, _, e1 := Syscall(SYS_FSTATFS, uintptr(fd), uintptr(unsafe.Pointer(stat)), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -515,7 +515,7 @@
 func Fsync(fd int) (err error) {
 	_, _, e1 := Syscall(SYS_FSYNC, uintptr(fd), 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -525,7 +525,7 @@
 func Ftruncate(fd int, length int64) (err error) {
 	_, _, e1 := Syscall6(SYS_FTRUNCATE, uintptr(fd), 0, uintptr(length), uintptr(length>>32), 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -560,7 +560,7 @@
 	r0, _, e1 := RawSyscall(SYS_GETPGID, uintptr(pid), 0, 0)
 	pgid = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -595,7 +595,7 @@
 	r0, _, e1 := Syscall(SYS_GETPRIORITY, uintptr(which), uintptr(who), 0)
 	prio = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -605,7 +605,7 @@
 func Getrlimit(which int, lim *Rlimit) (err error) {
 	_, _, e1 := RawSyscall(SYS_GETRLIMIT, uintptr(which), uintptr(unsafe.Pointer(lim)), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -615,7 +615,7 @@
 func Getrusage(who int, rusage *Rusage) (err error) {
 	_, _, e1 := RawSyscall(SYS_GETRUSAGE, uintptr(who), uintptr(unsafe.Pointer(rusage)), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -626,7 +626,7 @@
 	r0, _, e1 := RawSyscall(SYS_GETSID, uintptr(pid), 0, 0)
 	sid = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -636,7 +636,7 @@
 func Gettimeofday(tv *Timeval) (err error) {
 	_, _, e1 := RawSyscall(SYS_GETTIMEOFDAY, uintptr(unsafe.Pointer(tv)), 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -662,7 +662,7 @@
 func Kill(pid int, signum Signal) (err error) {
 	_, _, e1 := Syscall(SYS_KILL, uintptr(pid), uintptr(signum), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -673,7 +673,7 @@
 	r0, _, e1 := Syscall(SYS_KQUEUE, 0, 0, 0)
 	fd = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -689,7 +689,7 @@
 	_, _, e1 := Syscall(SYS_LCHOWN, uintptr(unsafe.Pointer(_p0)), uintptr(uid), uintptr(gid))
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -711,7 +711,7 @@
 	use(unsafe.Pointer(_p0))
 	use(unsafe.Pointer(_p1))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -721,7 +721,7 @@
 func Listen(s int, backlog int) (err error) {
 	_, _, e1 := Syscall(SYS_LISTEN, uintptr(s), uintptr(backlog), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -737,7 +737,7 @@
 	_, _, e1 := Syscall(SYS_LSTAT, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -753,7 +753,7 @@
 	_, _, e1 := Syscall(SYS_MKDIR, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -769,7 +769,7 @@
 	_, _, e1 := Syscall(SYS_MKFIFO, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -785,7 +785,7 @@
 	_, _, e1 := Syscall(SYS_MKNOD, uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(dev))
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -795,7 +795,7 @@
 func Nanosleep(time *Timespec, leftover *Timespec) (err error) {
 	_, _, e1 := Syscall(SYS_NANOSLEEP, uintptr(unsafe.Pointer(time)), uintptr(unsafe.Pointer(leftover)), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -812,7 +812,7 @@
 	use(unsafe.Pointer(_p0))
 	fd = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -829,7 +829,7 @@
 	use(unsafe.Pointer(_p0))
 	val = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -846,7 +846,7 @@
 	r0, _, e1 := Syscall6(SYS_PREAD, uintptr(fd), uintptr(_p0), uintptr(len(p)), 0, uintptr(offset), uintptr(offset>>32))
 	n = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -863,7 +863,7 @@
 	r0, _, e1 := Syscall6(SYS_PWRITE, uintptr(fd), uintptr(_p0), uintptr(len(p)), 0, uintptr(offset), uintptr(offset>>32))
 	n = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -880,7 +880,7 @@
 	r0, _, e1 := Syscall(SYS_READ, uintptr(fd), uintptr(_p0), uintptr(len(p)))
 	n = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -903,7 +903,7 @@
 	use(unsafe.Pointer(_p0))
 	n = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -925,7 +925,7 @@
 	use(unsafe.Pointer(_p0))
 	use(unsafe.Pointer(_p1))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -941,7 +941,7 @@
 	_, _, e1 := Syscall(SYS_REVOKE, uintptr(unsafe.Pointer(_p0)), 0, 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -957,7 +957,7 @@
 	_, _, e1 := Syscall(SYS_RMDIR, uintptr(unsafe.Pointer(_p0)), 0, 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -968,7 +968,7 @@
 	r0, r1, e1 := Syscall6(SYS_LSEEK, uintptr(fd), 0, uintptr(offset), uintptr(offset>>32), uintptr(whence), 0)
 	newoffset = int64(int64(r1)<<32 | int64(r0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -978,7 +978,7 @@
 func Select(n int, r *FdSet, w *FdSet, e *FdSet, timeout *Timeval) (err error) {
 	_, _, e1 := Syscall6(SYS_SELECT, uintptr(n), uintptr(unsafe.Pointer(r)), uintptr(unsafe.Pointer(w)), uintptr(unsafe.Pointer(e)), uintptr(unsafe.Pointer(timeout)), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -988,7 +988,7 @@
 func Setegid(egid int) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETEGID, uintptr(egid), 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -998,7 +998,7 @@
 func Seteuid(euid int) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETEUID, uintptr(euid), 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1008,7 +1008,7 @@
 func Setgid(gid int) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETGID, uintptr(gid), 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1024,7 +1024,7 @@
 	_, _, e1 := Syscall(SYS_SETLOGIN, uintptr(unsafe.Pointer(_p0)), 0, 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1034,7 +1034,7 @@
 func Setpgid(pid int, pgid int) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETPGID, uintptr(pid), uintptr(pgid), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1044,7 +1044,7 @@
 func Setpriority(which int, who int, prio int) (err error) {
 	_, _, e1 := Syscall(SYS_SETPRIORITY, uintptr(which), uintptr(who), uintptr(prio))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1054,7 +1054,7 @@
 func Setregid(rgid int, egid int) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETREGID, uintptr(rgid), uintptr(egid), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1064,7 +1064,7 @@
 func Setreuid(ruid int, euid int) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETREUID, uintptr(ruid), uintptr(euid), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1074,7 +1074,7 @@
 func Setrlimit(which int, lim *Rlimit) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETRLIMIT, uintptr(which), uintptr(unsafe.Pointer(lim)), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1085,7 +1085,7 @@
 	r0, _, e1 := RawSyscall(SYS_SETSID, 0, 0, 0)
 	pid = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1095,7 +1095,7 @@
 func Settimeofday(tp *Timeval) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETTIMEOFDAY, uintptr(unsafe.Pointer(tp)), 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1105,7 +1105,7 @@
 func Setuid(uid int) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETUID, uintptr(uid), 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1121,7 +1121,7 @@
 	_, _, e1 := Syscall(SYS_STAT, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1137,7 +1137,7 @@
 	_, _, e1 := Syscall(SYS_STATFS, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1159,7 +1159,7 @@
 	use(unsafe.Pointer(_p0))
 	use(unsafe.Pointer(_p1))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1169,7 +1169,7 @@
 func Sync() (err error) {
 	_, _, e1 := Syscall(SYS_SYNC, 0, 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1185,7 +1185,7 @@
 	_, _, e1 := Syscall6(SYS_TRUNCATE, uintptr(unsafe.Pointer(_p0)), 0, uintptr(length), uintptr(length>>32), 0, 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1209,7 +1209,7 @@
 	_, _, e1 := Syscall(SYS_UNLINK, uintptr(unsafe.Pointer(_p0)), 0, 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1225,7 +1225,7 @@
 	_, _, e1 := Syscall(SYS_UNMOUNT, uintptr(unsafe.Pointer(_p0)), uintptr(flags), 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1242,7 +1242,7 @@
 	r0, _, e1 := Syscall(SYS_WRITE, uintptr(fd), uintptr(_p0), uintptr(len(p)))
 	n = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1253,7 +1253,7 @@
 	r0, _, e1 := Syscall9(SYS_MMAP, uintptr(addr), uintptr(length), uintptr(prot), uintptr(flag), uintptr(fd), 0, uintptr(pos), uintptr(pos>>32), 0)
 	ret = uintptr(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1263,7 +1263,7 @@
 func munmap(addr uintptr, length uintptr) (err error) {
 	_, _, e1 := Syscall(SYS_MUNMAP, uintptr(addr), uintptr(length), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1274,7 +1274,7 @@
 	r0, _, e1 := Syscall(SYS_READ, uintptr(fd), uintptr(unsafe.Pointer(buf)), uintptr(nbuf))
 	n = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1285,7 +1285,7 @@
 	r0, _, e1 := Syscall(SYS_WRITE, uintptr(fd), uintptr(unsafe.Pointer(buf)), uintptr(nbuf))
 	n = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
diff --git a/src/syscall/zsyscall_openbsd_amd64.go b/src/syscall/zsyscall_openbsd_amd64.go
index ce9397b..93f5fc0 100644
--- a/src/syscall/zsyscall_openbsd_amd64.go
+++ b/src/syscall/zsyscall_openbsd_amd64.go
@@ -11,7 +11,7 @@
 	r0, _, e1 := RawSyscall(SYS_GETGROUPS, uintptr(ngid), uintptr(unsafe.Pointer(gid)), 0)
 	n = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -21,7 +21,7 @@
 func setgroups(ngid int, gid *_Gid_t) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETGROUPS, uintptr(ngid), uintptr(unsafe.Pointer(gid)), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -32,7 +32,7 @@
 	r0, _, e1 := Syscall6(SYS_WAIT4, uintptr(pid), uintptr(unsafe.Pointer(wstatus)), uintptr(options), uintptr(unsafe.Pointer(rusage)), 0, 0)
 	wpid = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -43,7 +43,7 @@
 	r0, _, e1 := Syscall(SYS_ACCEPT, uintptr(s), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)))
 	fd = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -53,7 +53,7 @@
 func bind(s int, addr unsafe.Pointer, addrlen _Socklen) (err error) {
 	_, _, e1 := Syscall(SYS_BIND, uintptr(s), uintptr(addr), uintptr(addrlen))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -63,7 +63,7 @@
 func connect(s int, addr unsafe.Pointer, addrlen _Socklen) (err error) {
 	_, _, e1 := Syscall(SYS_CONNECT, uintptr(s), uintptr(addr), uintptr(addrlen))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -74,7 +74,7 @@
 	r0, _, e1 := RawSyscall(SYS_SOCKET, uintptr(domain), uintptr(typ), uintptr(proto))
 	fd = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -84,7 +84,7 @@
 func getsockopt(s int, level int, name int, val unsafe.Pointer, vallen *_Socklen) (err error) {
 	_, _, e1 := Syscall6(SYS_GETSOCKOPT, uintptr(s), uintptr(level), uintptr(name), uintptr(val), uintptr(unsafe.Pointer(vallen)), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -94,7 +94,7 @@
 func setsockopt(s int, level int, name int, val unsafe.Pointer, vallen uintptr) (err error) {
 	_, _, e1 := Syscall6(SYS_SETSOCKOPT, uintptr(s), uintptr(level), uintptr(name), uintptr(val), uintptr(vallen), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -104,7 +104,7 @@
 func getpeername(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (err error) {
 	_, _, e1 := RawSyscall(SYS_GETPEERNAME, uintptr(fd), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -114,7 +114,7 @@
 func getsockname(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (err error) {
 	_, _, e1 := RawSyscall(SYS_GETSOCKNAME, uintptr(fd), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -124,7 +124,7 @@
 func Shutdown(s int, how int) (err error) {
 	_, _, e1 := Syscall(SYS_SHUTDOWN, uintptr(s), uintptr(how), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -134,7 +134,7 @@
 func socketpair(domain int, typ int, proto int, fd *[2]int32) (err error) {
 	_, _, e1 := RawSyscall6(SYS_SOCKETPAIR, uintptr(domain), uintptr(typ), uintptr(proto), uintptr(unsafe.Pointer(fd)), 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -151,7 +151,7 @@
 	r0, _, e1 := Syscall6(SYS_RECVFROM, uintptr(fd), uintptr(_p0), uintptr(len(p)), uintptr(flags), uintptr(unsafe.Pointer(from)), uintptr(unsafe.Pointer(fromlen)))
 	n = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -167,7 +167,7 @@
 	}
 	_, _, e1 := Syscall6(SYS_SENDTO, uintptr(s), uintptr(_p0), uintptr(len(buf)), uintptr(flags), uintptr(to), uintptr(addrlen))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -178,7 +178,7 @@
 	r0, _, e1 := Syscall(SYS_RECVMSG, uintptr(s), uintptr(unsafe.Pointer(msg)), uintptr(flags))
 	n = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -189,7 +189,7 @@
 	r0, _, e1 := Syscall(SYS_SENDMSG, uintptr(s), uintptr(unsafe.Pointer(msg)), uintptr(flags))
 	n = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -200,7 +200,7 @@
 	r0, _, e1 := Syscall6(SYS_KEVENT, uintptr(kq), uintptr(change), uintptr(nchange), uintptr(event), uintptr(nevent), uintptr(unsafe.Pointer(timeout)))
 	n = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -216,7 +216,7 @@
 	}
 	_, _, e1 := Syscall6(SYS___SYSCTL, uintptr(_p0), uintptr(len(mib)), uintptr(unsafe.Pointer(old)), uintptr(unsafe.Pointer(oldlen)), uintptr(unsafe.Pointer(new)), uintptr(newlen))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -232,7 +232,7 @@
 	_, _, e1 := Syscall(SYS_UTIMES, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(timeval)), 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -242,7 +242,7 @@
 func futimes(fd int, timeval *[2]Timeval) (err error) {
 	_, _, e1 := Syscall(SYS_FUTIMES, uintptr(fd), uintptr(unsafe.Pointer(timeval)), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -253,7 +253,7 @@
 	r0, _, e1 := Syscall(SYS_FCNTL, uintptr(fd), uintptr(cmd), uintptr(arg))
 	val = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -263,7 +263,7 @@
 func pipe(p *[2]_C_int) (err error) {
 	_, _, e1 := RawSyscall(SYS_PIPE, uintptr(unsafe.Pointer(p)), 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -280,7 +280,7 @@
 	r0, _, e1 := Syscall(SYS_GETDENTS, uintptr(fd), uintptr(_p0), uintptr(len(buf)))
 	n = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -296,7 +296,7 @@
 	_, _, e1 := Syscall(SYS_ACCESS, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -306,7 +306,7 @@
 func Adjtime(delta *Timeval, olddelta *Timeval) (err error) {
 	_, _, e1 := Syscall(SYS_ADJTIME, uintptr(unsafe.Pointer(delta)), uintptr(unsafe.Pointer(olddelta)), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -322,7 +322,7 @@
 	_, _, e1 := Syscall(SYS_CHDIR, uintptr(unsafe.Pointer(_p0)), 0, 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -338,7 +338,7 @@
 	_, _, e1 := Syscall(SYS_CHFLAGS, uintptr(unsafe.Pointer(_p0)), uintptr(flags), 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -354,7 +354,7 @@
 	_, _, e1 := Syscall(SYS_CHMOD, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -370,7 +370,7 @@
 	_, _, e1 := Syscall(SYS_CHOWN, uintptr(unsafe.Pointer(_p0)), uintptr(uid), uintptr(gid))
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -386,7 +386,7 @@
 	_, _, e1 := Syscall(SYS_CHROOT, uintptr(unsafe.Pointer(_p0)), 0, 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -396,7 +396,7 @@
 func Close(fd int) (err error) {
 	_, _, e1 := Syscall(SYS_CLOSE, uintptr(fd), 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -404,10 +404,10 @@
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
 func Dup(fd int) (nfd int, err error) {
-	r0, _, e1 := RawSyscall(SYS_DUP, uintptr(fd), 0, 0)
+	r0, _, e1 := Syscall(SYS_DUP, uintptr(fd), 0, 0)
 	nfd = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -415,9 +415,9 @@
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
 func Dup2(from int, to int) (err error) {
-	_, _, e1 := RawSyscall(SYS_DUP2, uintptr(from), uintptr(to), 0)
+	_, _, e1 := Syscall(SYS_DUP2, uintptr(from), uintptr(to), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -434,7 +434,7 @@
 func Fchdir(fd int) (err error) {
 	_, _, e1 := Syscall(SYS_FCHDIR, uintptr(fd), 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -444,7 +444,7 @@
 func Fchflags(fd int, flags int) (err error) {
 	_, _, e1 := Syscall(SYS_FCHFLAGS, uintptr(fd), uintptr(flags), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -454,7 +454,7 @@
 func Fchmod(fd int, mode uint32) (err error) {
 	_, _, e1 := Syscall(SYS_FCHMOD, uintptr(fd), uintptr(mode), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -464,7 +464,7 @@
 func Fchown(fd int, uid int, gid int) (err error) {
 	_, _, e1 := Syscall(SYS_FCHOWN, uintptr(fd), uintptr(uid), uintptr(gid))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -474,7 +474,7 @@
 func Flock(fd int, how int) (err error) {
 	_, _, e1 := Syscall(SYS_FLOCK, uintptr(fd), uintptr(how), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -485,7 +485,7 @@
 	r0, _, e1 := Syscall(SYS_FPATHCONF, uintptr(fd), uintptr(name), 0)
 	val = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -495,7 +495,7 @@
 func Fstat(fd int, stat *Stat_t) (err error) {
 	_, _, e1 := Syscall(SYS_FSTAT, uintptr(fd), uintptr(unsafe.Pointer(stat)), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -505,7 +505,7 @@
 func Fstatfs(fd int, stat *Statfs_t) (err error) {
 	_, _, e1 := Syscall(SYS_FSTATFS, uintptr(fd), uintptr(unsafe.Pointer(stat)), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -515,7 +515,7 @@
 func Fsync(fd int) (err error) {
 	_, _, e1 := Syscall(SYS_FSYNC, uintptr(fd), 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -525,7 +525,7 @@
 func Ftruncate(fd int, length int64) (err error) {
 	_, _, e1 := Syscall(SYS_FTRUNCATE, uintptr(fd), 0, uintptr(length))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -560,7 +560,7 @@
 	r0, _, e1 := RawSyscall(SYS_GETPGID, uintptr(pid), 0, 0)
 	pgid = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -595,7 +595,7 @@
 	r0, _, e1 := Syscall(SYS_GETPRIORITY, uintptr(which), uintptr(who), 0)
 	prio = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -605,7 +605,7 @@
 func Getrlimit(which int, lim *Rlimit) (err error) {
 	_, _, e1 := RawSyscall(SYS_GETRLIMIT, uintptr(which), uintptr(unsafe.Pointer(lim)), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -615,7 +615,7 @@
 func Getrusage(who int, rusage *Rusage) (err error) {
 	_, _, e1 := RawSyscall(SYS_GETRUSAGE, uintptr(who), uintptr(unsafe.Pointer(rusage)), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -626,7 +626,7 @@
 	r0, _, e1 := RawSyscall(SYS_GETSID, uintptr(pid), 0, 0)
 	sid = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -636,7 +636,7 @@
 func Gettimeofday(tv *Timeval) (err error) {
 	_, _, e1 := RawSyscall(SYS_GETTIMEOFDAY, uintptr(unsafe.Pointer(tv)), 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -662,7 +662,7 @@
 func Kill(pid int, signum Signal) (err error) {
 	_, _, e1 := Syscall(SYS_KILL, uintptr(pid), uintptr(signum), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -673,7 +673,7 @@
 	r0, _, e1 := Syscall(SYS_KQUEUE, 0, 0, 0)
 	fd = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -689,7 +689,7 @@
 	_, _, e1 := Syscall(SYS_LCHOWN, uintptr(unsafe.Pointer(_p0)), uintptr(uid), uintptr(gid))
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -711,7 +711,7 @@
 	use(unsafe.Pointer(_p0))
 	use(unsafe.Pointer(_p1))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -721,7 +721,7 @@
 func Listen(s int, backlog int) (err error) {
 	_, _, e1 := Syscall(SYS_LISTEN, uintptr(s), uintptr(backlog), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -737,7 +737,7 @@
 	_, _, e1 := Syscall(SYS_LSTAT, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -753,7 +753,7 @@
 	_, _, e1 := Syscall(SYS_MKDIR, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -769,7 +769,7 @@
 	_, _, e1 := Syscall(SYS_MKFIFO, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -785,7 +785,7 @@
 	_, _, e1 := Syscall(SYS_MKNOD, uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(dev))
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -795,7 +795,7 @@
 func Nanosleep(time *Timespec, leftover *Timespec) (err error) {
 	_, _, e1 := Syscall(SYS_NANOSLEEP, uintptr(unsafe.Pointer(time)), uintptr(unsafe.Pointer(leftover)), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -812,7 +812,7 @@
 	use(unsafe.Pointer(_p0))
 	fd = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -829,7 +829,7 @@
 	use(unsafe.Pointer(_p0))
 	val = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -846,7 +846,7 @@
 	r0, _, e1 := Syscall6(SYS_PREAD, uintptr(fd), uintptr(_p0), uintptr(len(p)), 0, uintptr(offset), 0)
 	n = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -863,7 +863,7 @@
 	r0, _, e1 := Syscall6(SYS_PWRITE, uintptr(fd), uintptr(_p0), uintptr(len(p)), 0, uintptr(offset), 0)
 	n = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -880,7 +880,7 @@
 	r0, _, e1 := Syscall(SYS_READ, uintptr(fd), uintptr(_p0), uintptr(len(p)))
 	n = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -903,7 +903,7 @@
 	use(unsafe.Pointer(_p0))
 	n = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -925,7 +925,7 @@
 	use(unsafe.Pointer(_p0))
 	use(unsafe.Pointer(_p1))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -941,7 +941,7 @@
 	_, _, e1 := Syscall(SYS_REVOKE, uintptr(unsafe.Pointer(_p0)), 0, 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -957,7 +957,7 @@
 	_, _, e1 := Syscall(SYS_RMDIR, uintptr(unsafe.Pointer(_p0)), 0, 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -968,7 +968,7 @@
 	r0, _, e1 := Syscall6(SYS_LSEEK, uintptr(fd), 0, uintptr(offset), uintptr(whence), 0, 0)
 	newoffset = int64(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -978,7 +978,7 @@
 func Select(n int, r *FdSet, w *FdSet, e *FdSet, timeout *Timeval) (err error) {
 	_, _, e1 := Syscall6(SYS_SELECT, uintptr(n), uintptr(unsafe.Pointer(r)), uintptr(unsafe.Pointer(w)), uintptr(unsafe.Pointer(e)), uintptr(unsafe.Pointer(timeout)), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -988,7 +988,7 @@
 func Setegid(egid int) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETEGID, uintptr(egid), 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -998,7 +998,7 @@
 func Seteuid(euid int) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETEUID, uintptr(euid), 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1008,7 +1008,7 @@
 func Setgid(gid int) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETGID, uintptr(gid), 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1024,7 +1024,7 @@
 	_, _, e1 := Syscall(SYS_SETLOGIN, uintptr(unsafe.Pointer(_p0)), 0, 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1034,7 +1034,7 @@
 func Setpgid(pid int, pgid int) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETPGID, uintptr(pid), uintptr(pgid), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1044,7 +1044,7 @@
 func Setpriority(which int, who int, prio int) (err error) {
 	_, _, e1 := Syscall(SYS_SETPRIORITY, uintptr(which), uintptr(who), uintptr(prio))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1054,7 +1054,7 @@
 func Setregid(rgid int, egid int) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETREGID, uintptr(rgid), uintptr(egid), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1064,7 +1064,7 @@
 func Setreuid(ruid int, euid int) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETREUID, uintptr(ruid), uintptr(euid), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1074,7 +1074,7 @@
 func Setrlimit(which int, lim *Rlimit) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETRLIMIT, uintptr(which), uintptr(unsafe.Pointer(lim)), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1085,7 +1085,7 @@
 	r0, _, e1 := RawSyscall(SYS_SETSID, 0, 0, 0)
 	pid = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1095,7 +1095,7 @@
 func Settimeofday(tp *Timeval) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETTIMEOFDAY, uintptr(unsafe.Pointer(tp)), 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1105,7 +1105,7 @@
 func Setuid(uid int) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETUID, uintptr(uid), 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1121,7 +1121,7 @@
 	_, _, e1 := Syscall(SYS_STAT, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1137,7 +1137,7 @@
 	_, _, e1 := Syscall(SYS_STATFS, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1159,7 +1159,7 @@
 	use(unsafe.Pointer(_p0))
 	use(unsafe.Pointer(_p1))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1169,7 +1169,7 @@
 func Sync() (err error) {
 	_, _, e1 := Syscall(SYS_SYNC, 0, 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1185,7 +1185,7 @@
 	_, _, e1 := Syscall(SYS_TRUNCATE, uintptr(unsafe.Pointer(_p0)), 0, uintptr(length))
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1209,7 +1209,7 @@
 	_, _, e1 := Syscall(SYS_UNLINK, uintptr(unsafe.Pointer(_p0)), 0, 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1225,7 +1225,7 @@
 	_, _, e1 := Syscall(SYS_UNMOUNT, uintptr(unsafe.Pointer(_p0)), uintptr(flags), 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1242,7 +1242,7 @@
 	r0, _, e1 := Syscall(SYS_WRITE, uintptr(fd), uintptr(_p0), uintptr(len(p)))
 	n = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1253,7 +1253,7 @@
 	r0, _, e1 := Syscall9(SYS_MMAP, uintptr(addr), uintptr(length), uintptr(prot), uintptr(flag), uintptr(fd), 0, uintptr(pos), 0, 0)
 	ret = uintptr(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1263,7 +1263,7 @@
 func munmap(addr uintptr, length uintptr) (err error) {
 	_, _, e1 := Syscall(SYS_MUNMAP, uintptr(addr), uintptr(length), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1274,7 +1274,7 @@
 	r0, _, e1 := Syscall(SYS_READ, uintptr(fd), uintptr(unsafe.Pointer(buf)), uintptr(nbuf))
 	n = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1285,7 +1285,7 @@
 	r0, _, e1 := Syscall(SYS_WRITE, uintptr(fd), uintptr(unsafe.Pointer(buf)), uintptr(nbuf))
 	n = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
diff --git a/src/syscall/zsyscall_dragonfly_386.go b/src/syscall/zsyscall_openbsd_arm.go
similarity index 90%
rename from src/syscall/zsyscall_dragonfly_386.go
rename to src/syscall/zsyscall_openbsd_arm.go
index 01b0819..f59739c 100644
--- a/src/syscall/zsyscall_dragonfly_386.go
+++ b/src/syscall/zsyscall_openbsd_arm.go
@@ -1,4 +1,4 @@
-// mksyscall.pl -l32 -dragonfly syscall_bsd.go syscall_dragonfly.go syscall_dragonfly_386.go
+// mksyscall.pl -l32 -openbsd -arm syscall_bsd.go syscall_openbsd.go syscall_openbsd_arm.go
 // MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
 
 package syscall
@@ -11,7 +11,7 @@
 	r0, _, e1 := RawSyscall(SYS_GETGROUPS, uintptr(ngid), uintptr(unsafe.Pointer(gid)), 0)
 	n = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -21,7 +21,7 @@
 func setgroups(ngid int, gid *_Gid_t) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETGROUPS, uintptr(ngid), uintptr(unsafe.Pointer(gid)), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -32,7 +32,7 @@
 	r0, _, e1 := Syscall6(SYS_WAIT4, uintptr(pid), uintptr(unsafe.Pointer(wstatus)), uintptr(options), uintptr(unsafe.Pointer(rusage)), 0, 0)
 	wpid = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -43,7 +43,7 @@
 	r0, _, e1 := Syscall(SYS_ACCEPT, uintptr(s), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)))
 	fd = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -53,7 +53,7 @@
 func bind(s int, addr unsafe.Pointer, addrlen _Socklen) (err error) {
 	_, _, e1 := Syscall(SYS_BIND, uintptr(s), uintptr(addr), uintptr(addrlen))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -63,7 +63,7 @@
 func connect(s int, addr unsafe.Pointer, addrlen _Socklen) (err error) {
 	_, _, e1 := Syscall(SYS_CONNECT, uintptr(s), uintptr(addr), uintptr(addrlen))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -74,7 +74,7 @@
 	r0, _, e1 := RawSyscall(SYS_SOCKET, uintptr(domain), uintptr(typ), uintptr(proto))
 	fd = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -84,7 +84,7 @@
 func getsockopt(s int, level int, name int, val unsafe.Pointer, vallen *_Socklen) (err error) {
 	_, _, e1 := Syscall6(SYS_GETSOCKOPT, uintptr(s), uintptr(level), uintptr(name), uintptr(val), uintptr(unsafe.Pointer(vallen)), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -94,7 +94,7 @@
 func setsockopt(s int, level int, name int, val unsafe.Pointer, vallen uintptr) (err error) {
 	_, _, e1 := Syscall6(SYS_SETSOCKOPT, uintptr(s), uintptr(level), uintptr(name), uintptr(val), uintptr(vallen), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -104,7 +104,7 @@
 func getpeername(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (err error) {
 	_, _, e1 := RawSyscall(SYS_GETPEERNAME, uintptr(fd), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -114,7 +114,7 @@
 func getsockname(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (err error) {
 	_, _, e1 := RawSyscall(SYS_GETSOCKNAME, uintptr(fd), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -124,7 +124,7 @@
 func Shutdown(s int, how int) (err error) {
 	_, _, e1 := Syscall(SYS_SHUTDOWN, uintptr(s), uintptr(how), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -134,7 +134,7 @@
 func socketpair(domain int, typ int, proto int, fd *[2]int32) (err error) {
 	_, _, e1 := RawSyscall6(SYS_SOCKETPAIR, uintptr(domain), uintptr(typ), uintptr(proto), uintptr(unsafe.Pointer(fd)), 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -151,7 +151,7 @@
 	r0, _, e1 := Syscall6(SYS_RECVFROM, uintptr(fd), uintptr(_p0), uintptr(len(p)), uintptr(flags), uintptr(unsafe.Pointer(from)), uintptr(unsafe.Pointer(fromlen)))
 	n = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -167,7 +167,7 @@
 	}
 	_, _, e1 := Syscall6(SYS_SENDTO, uintptr(s), uintptr(_p0), uintptr(len(buf)), uintptr(flags), uintptr(to), uintptr(addrlen))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -178,7 +178,7 @@
 	r0, _, e1 := Syscall(SYS_RECVMSG, uintptr(s), uintptr(unsafe.Pointer(msg)), uintptr(flags))
 	n = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -189,7 +189,7 @@
 	r0, _, e1 := Syscall(SYS_SENDMSG, uintptr(s), uintptr(unsafe.Pointer(msg)), uintptr(flags))
 	n = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -200,7 +200,7 @@
 	r0, _, e1 := Syscall6(SYS_KEVENT, uintptr(kq), uintptr(change), uintptr(nchange), uintptr(event), uintptr(nevent), uintptr(unsafe.Pointer(timeout)))
 	n = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -216,7 +216,7 @@
 	}
 	_, _, e1 := Syscall6(SYS___SYSCTL, uintptr(_p0), uintptr(len(mib)), uintptr(unsafe.Pointer(old)), uintptr(unsafe.Pointer(oldlen)), uintptr(unsafe.Pointer(new)), uintptr(newlen))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -232,7 +232,7 @@
 	_, _, e1 := Syscall(SYS_UTIMES, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(timeval)), 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -242,7 +242,7 @@
 func futimes(fd int, timeval *[2]Timeval) (err error) {
 	_, _, e1 := Syscall(SYS_FUTIMES, uintptr(fd), uintptr(unsafe.Pointer(timeval)), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -253,53 +253,34 @@
 	r0, _, e1 := Syscall(SYS_FCNTL, uintptr(fd), uintptr(cmd), uintptr(arg))
 	val = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
-func pipe() (r int, w int, err error) {
-	r0, r1, e1 := RawSyscall(SYS_PIPE, 0, 0, 0)
-	r = int(r0)
-	w = int(r1)
+func pipe(p *[2]_C_int) (err error) {
+	_, _, e1 := RawSyscall(SYS_PIPE, uintptr(unsafe.Pointer(p)), 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
-func extpread(fd int, p []byte, flags int, offset int64) (n int, err error) {
+func getdents(fd int, buf []byte) (n int, err error) {
 	var _p0 unsafe.Pointer
-	if len(p) > 0 {
-		_p0 = unsafe.Pointer(&p[0])
+	if len(buf) > 0 {
+		_p0 = unsafe.Pointer(&buf[0])
 	} else {
 		_p0 = unsafe.Pointer(&_zero)
 	}
-	r0, _, e1 := Syscall6(SYS_EXTPREAD, uintptr(fd), uintptr(_p0), uintptr(len(p)), uintptr(flags), uintptr(offset), uintptr(offset>>32))
+	r0, _, e1 := Syscall(SYS_GETDENTS, uintptr(fd), uintptr(_p0), uintptr(len(buf)))
 	n = int(r0)
 	if e1 != 0 {
-		err = e1
-	}
-	return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
-func extpwrite(fd int, p []byte, flags int, offset int64) (n int, err error) {
-	var _p0 unsafe.Pointer
-	if len(p) > 0 {
-		_p0 = unsafe.Pointer(&p[0])
-	} else {
-		_p0 = unsafe.Pointer(&_zero)
-	}
-	r0, _, e1 := Syscall6(SYS_EXTPWRITE, uintptr(fd), uintptr(_p0), uintptr(len(p)), uintptr(flags), uintptr(offset), uintptr(offset>>32))
-	n = int(r0)
-	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -315,7 +296,7 @@
 	_, _, e1 := Syscall(SYS_ACCESS, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -325,7 +306,7 @@
 func Adjtime(delta *Timeval, olddelta *Timeval) (err error) {
 	_, _, e1 := Syscall(SYS_ADJTIME, uintptr(unsafe.Pointer(delta)), uintptr(unsafe.Pointer(olddelta)), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -341,7 +322,7 @@
 	_, _, e1 := Syscall(SYS_CHDIR, uintptr(unsafe.Pointer(_p0)), 0, 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -357,7 +338,7 @@
 	_, _, e1 := Syscall(SYS_CHFLAGS, uintptr(unsafe.Pointer(_p0)), uintptr(flags), 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -373,7 +354,7 @@
 	_, _, e1 := Syscall(SYS_CHMOD, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -389,7 +370,7 @@
 	_, _, e1 := Syscall(SYS_CHOWN, uintptr(unsafe.Pointer(_p0)), uintptr(uid), uintptr(gid))
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -405,7 +386,7 @@
 	_, _, e1 := Syscall(SYS_CHROOT, uintptr(unsafe.Pointer(_p0)), 0, 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -415,7 +396,7 @@
 func Close(fd int) (err error) {
 	_, _, e1 := Syscall(SYS_CLOSE, uintptr(fd), 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -423,10 +404,10 @@
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
 func Dup(fd int) (nfd int, err error) {
-	r0, _, e1 := RawSyscall(SYS_DUP, uintptr(fd), 0, 0)
+	r0, _, e1 := Syscall(SYS_DUP, uintptr(fd), 0, 0)
 	nfd = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -434,9 +415,9 @@
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
 func Dup2(from int, to int) (err error) {
-	_, _, e1 := RawSyscall(SYS_DUP2, uintptr(from), uintptr(to), 0)
+	_, _, e1 := Syscall(SYS_DUP2, uintptr(from), uintptr(to), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -453,7 +434,7 @@
 func Fchdir(fd int) (err error) {
 	_, _, e1 := Syscall(SYS_FCHDIR, uintptr(fd), 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -463,7 +444,7 @@
 func Fchflags(fd int, flags int) (err error) {
 	_, _, e1 := Syscall(SYS_FCHFLAGS, uintptr(fd), uintptr(flags), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -473,7 +454,7 @@
 func Fchmod(fd int, mode uint32) (err error) {
 	_, _, e1 := Syscall(SYS_FCHMOD, uintptr(fd), uintptr(mode), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -483,7 +464,7 @@
 func Fchown(fd int, uid int, gid int) (err error) {
 	_, _, e1 := Syscall(SYS_FCHOWN, uintptr(fd), uintptr(uid), uintptr(gid))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -493,7 +474,7 @@
 func Flock(fd int, how int) (err error) {
 	_, _, e1 := Syscall(SYS_FLOCK, uintptr(fd), uintptr(how), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -504,7 +485,7 @@
 	r0, _, e1 := Syscall(SYS_FPATHCONF, uintptr(fd), uintptr(name), 0)
 	val = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -514,7 +495,7 @@
 func Fstat(fd int, stat *Stat_t) (err error) {
 	_, _, e1 := Syscall(SYS_FSTAT, uintptr(fd), uintptr(unsafe.Pointer(stat)), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -524,7 +505,7 @@
 func Fstatfs(fd int, stat *Statfs_t) (err error) {
 	_, _, e1 := Syscall(SYS_FSTATFS, uintptr(fd), uintptr(unsafe.Pointer(stat)), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -534,7 +515,7 @@
 func Fsync(fd int) (err error) {
 	_, _, e1 := Syscall(SYS_FSYNC, uintptr(fd), 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -544,38 +525,13 @@
 func Ftruncate(fd int, length int64) (err error) {
 	_, _, e1 := Syscall6(SYS_FTRUNCATE, uintptr(fd), 0, uintptr(length), uintptr(length>>32), 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
-func Getdirentries(fd int, buf []byte, basep *uintptr) (n int, err error) {
-	var _p0 unsafe.Pointer
-	if len(buf) > 0 {
-		_p0 = unsafe.Pointer(&buf[0])
-	} else {
-		_p0 = unsafe.Pointer(&_zero)
-	}
-	r0, _, e1 := Syscall6(SYS_GETDIRENTRIES, uintptr(fd), uintptr(_p0), uintptr(len(buf)), uintptr(unsafe.Pointer(basep)), 0, 0)
-	n = int(r0)
-	if e1 != 0 {
-		err = e1
-	}
-	return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
-func Getdtablesize() (size int) {
-	r0, _, _ := Syscall(SYS_GETDTABLESIZE, 0, 0, 0)
-	size = int(r0)
-	return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
 func Getegid() (egid int) {
 	r0, _, _ := RawSyscall(SYS_GETEGID, 0, 0, 0)
 	egid = int(r0)
@@ -604,7 +560,7 @@
 	r0, _, e1 := RawSyscall(SYS_GETPGID, uintptr(pid), 0, 0)
 	pgid = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -639,7 +595,7 @@
 	r0, _, e1 := Syscall(SYS_GETPRIORITY, uintptr(which), uintptr(who), 0)
 	prio = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -649,7 +605,7 @@
 func Getrlimit(which int, lim *Rlimit) (err error) {
 	_, _, e1 := RawSyscall(SYS_GETRLIMIT, uintptr(which), uintptr(unsafe.Pointer(lim)), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -659,7 +615,7 @@
 func Getrusage(who int, rusage *Rusage) (err error) {
 	_, _, e1 := RawSyscall(SYS_GETRUSAGE, uintptr(who), uintptr(unsafe.Pointer(rusage)), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -670,7 +626,7 @@
 	r0, _, e1 := RawSyscall(SYS_GETSID, uintptr(pid), 0, 0)
 	sid = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -680,7 +636,7 @@
 func Gettimeofday(tv *Timeval) (err error) {
 	_, _, e1 := RawSyscall(SYS_GETTIMEOFDAY, uintptr(unsafe.Pointer(tv)), 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -706,7 +662,7 @@
 func Kill(pid int, signum Signal) (err error) {
 	_, _, e1 := Syscall(SYS_KILL, uintptr(pid), uintptr(signum), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -717,7 +673,7 @@
 	r0, _, e1 := Syscall(SYS_KQUEUE, 0, 0, 0)
 	fd = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -733,7 +689,7 @@
 	_, _, e1 := Syscall(SYS_LCHOWN, uintptr(unsafe.Pointer(_p0)), uintptr(uid), uintptr(gid))
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -755,7 +711,7 @@
 	use(unsafe.Pointer(_p0))
 	use(unsafe.Pointer(_p1))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -765,7 +721,7 @@
 func Listen(s int, backlog int) (err error) {
 	_, _, e1 := Syscall(SYS_LISTEN, uintptr(s), uintptr(backlog), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -781,7 +737,7 @@
 	_, _, e1 := Syscall(SYS_LSTAT, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -797,7 +753,7 @@
 	_, _, e1 := Syscall(SYS_MKDIR, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -813,7 +769,7 @@
 	_, _, e1 := Syscall(SYS_MKFIFO, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -829,7 +785,7 @@
 	_, _, e1 := Syscall(SYS_MKNOD, uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(dev))
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -839,7 +795,7 @@
 func Nanosleep(time *Timespec, leftover *Timespec) (err error) {
 	_, _, e1 := Syscall(SYS_NANOSLEEP, uintptr(unsafe.Pointer(time)), uintptr(unsafe.Pointer(leftover)), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -856,7 +812,7 @@
 	use(unsafe.Pointer(_p0))
 	fd = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -873,7 +829,41 @@
 	use(unsafe.Pointer(_p0))
 	val = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Pread(fd int, p []byte, offset int64) (n int, err error) {
+	var _p0 unsafe.Pointer
+	if len(p) > 0 {
+		_p0 = unsafe.Pointer(&p[0])
+	} else {
+		_p0 = unsafe.Pointer(&_zero)
+	}
+	r0, _, e1 := Syscall6(SYS_PREAD, uintptr(fd), uintptr(_p0), uintptr(len(p)), 0, uintptr(offset), uintptr(offset>>32))
+	n = int(r0)
+	if e1 != 0 {
+		err = errnoErr(e1)
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Pwrite(fd int, p []byte, offset int64) (n int, err error) {
+	var _p0 unsafe.Pointer
+	if len(p) > 0 {
+		_p0 = unsafe.Pointer(&p[0])
+	} else {
+		_p0 = unsafe.Pointer(&_zero)
+	}
+	r0, _, e1 := Syscall6(SYS_PWRITE, uintptr(fd), uintptr(_p0), uintptr(len(p)), 0, uintptr(offset), uintptr(offset>>32))
+	n = int(r0)
+	if e1 != 0 {
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -890,7 +880,7 @@
 	r0, _, e1 := Syscall(SYS_READ, uintptr(fd), uintptr(_p0), uintptr(len(p)))
 	n = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -913,7 +903,7 @@
 	use(unsafe.Pointer(_p0))
 	n = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -935,7 +925,7 @@
 	use(unsafe.Pointer(_p0))
 	use(unsafe.Pointer(_p1))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -951,7 +941,7 @@
 	_, _, e1 := Syscall(SYS_REVOKE, uintptr(unsafe.Pointer(_p0)), 0, 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -967,7 +957,7 @@
 	_, _, e1 := Syscall(SYS_RMDIR, uintptr(unsafe.Pointer(_p0)), 0, 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -978,7 +968,7 @@
 	r0, r1, e1 := Syscall6(SYS_LSEEK, uintptr(fd), 0, uintptr(offset), uintptr(offset>>32), uintptr(whence), 0)
 	newoffset = int64(int64(r1)<<32 | int64(r0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -988,7 +978,7 @@
 func Select(n int, r *FdSet, w *FdSet, e *FdSet, timeout *Timeval) (err error) {
 	_, _, e1 := Syscall6(SYS_SELECT, uintptr(n), uintptr(unsafe.Pointer(r)), uintptr(unsafe.Pointer(w)), uintptr(unsafe.Pointer(e)), uintptr(unsafe.Pointer(timeout)), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -998,7 +988,7 @@
 func Setegid(egid int) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETEGID, uintptr(egid), 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1008,7 +998,7 @@
 func Seteuid(euid int) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETEUID, uintptr(euid), 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1018,7 +1008,7 @@
 func Setgid(gid int) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETGID, uintptr(gid), 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1034,7 +1024,7 @@
 	_, _, e1 := Syscall(SYS_SETLOGIN, uintptr(unsafe.Pointer(_p0)), 0, 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1044,7 +1034,7 @@
 func Setpgid(pid int, pgid int) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETPGID, uintptr(pid), uintptr(pgid), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1054,7 +1044,7 @@
 func Setpriority(which int, who int, prio int) (err error) {
 	_, _, e1 := Syscall(SYS_SETPRIORITY, uintptr(which), uintptr(who), uintptr(prio))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1064,7 +1054,7 @@
 func Setregid(rgid int, egid int) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETREGID, uintptr(rgid), uintptr(egid), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1074,7 +1064,7 @@
 func Setreuid(ruid int, euid int) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETREUID, uintptr(ruid), uintptr(euid), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1084,7 +1074,7 @@
 func Setrlimit(which int, lim *Rlimit) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETRLIMIT, uintptr(which), uintptr(unsafe.Pointer(lim)), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1095,7 +1085,7 @@
 	r0, _, e1 := RawSyscall(SYS_SETSID, 0, 0, 0)
 	pid = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1105,7 +1095,7 @@
 func Settimeofday(tp *Timeval) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETTIMEOFDAY, uintptr(unsafe.Pointer(tp)), 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1115,7 +1105,7 @@
 func Setuid(uid int) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETUID, uintptr(uid), 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1131,7 +1121,7 @@
 	_, _, e1 := Syscall(SYS_STAT, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1147,7 +1137,7 @@
 	_, _, e1 := Syscall(SYS_STATFS, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1169,7 +1159,7 @@
 	use(unsafe.Pointer(_p0))
 	use(unsafe.Pointer(_p1))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1179,7 +1169,7 @@
 func Sync() (err error) {
 	_, _, e1 := Syscall(SYS_SYNC, 0, 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1195,7 +1185,7 @@
 	_, _, e1 := Syscall6(SYS_TRUNCATE, uintptr(unsafe.Pointer(_p0)), 0, uintptr(length), uintptr(length>>32), 0, 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1210,22 +1200,6 @@
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
-func Undelete(path string) (err error) {
-	var _p0 *byte
-	_p0, err = BytePtrFromString(path)
-	if err != nil {
-		return
-	}
-	_, _, e1 := Syscall(SYS_UNDELETE, uintptr(unsafe.Pointer(_p0)), 0, 0)
-	use(unsafe.Pointer(_p0))
-	if e1 != 0 {
-		err = e1
-	}
-	return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
 func Unlink(path string) (err error) {
 	var _p0 *byte
 	_p0, err = BytePtrFromString(path)
@@ -1235,7 +1209,7 @@
 	_, _, e1 := Syscall(SYS_UNLINK, uintptr(unsafe.Pointer(_p0)), 0, 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1251,7 +1225,7 @@
 	_, _, e1 := Syscall(SYS_UNMOUNT, uintptr(unsafe.Pointer(_p0)), uintptr(flags), 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1268,7 +1242,7 @@
 	r0, _, e1 := Syscall(SYS_WRITE, uintptr(fd), uintptr(_p0), uintptr(len(p)))
 	n = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1279,7 +1253,7 @@
 	r0, _, e1 := Syscall9(SYS_MMAP, uintptr(addr), uintptr(length), uintptr(prot), uintptr(flag), uintptr(fd), 0, uintptr(pos), uintptr(pos>>32), 0)
 	ret = uintptr(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1289,7 +1263,7 @@
 func munmap(addr uintptr, length uintptr) (err error) {
 	_, _, e1 := Syscall(SYS_MUNMAP, uintptr(addr), uintptr(length), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1300,7 +1274,7 @@
 	r0, _, e1 := Syscall(SYS_READ, uintptr(fd), uintptr(unsafe.Pointer(buf)), uintptr(nbuf))
 	n = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1311,7 +1285,7 @@
 	r0, _, e1 := Syscall(SYS_WRITE, uintptr(fd), uintptr(unsafe.Pointer(buf)), uintptr(nbuf))
 	n = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
diff --git a/src/syscall/zsyscall_solaris_amd64.go b/src/syscall/zsyscall_solaris_amd64.go
index 43b224a..886d2b0 100644
--- a/src/syscall/zsyscall_solaris_amd64.go
+++ b/src/syscall/zsyscall_solaris_amd64.go
@@ -95,7 +95,7 @@
 	r0, _, e1 := rawSysvicall6(procgetgroups.Addr(), 2, uintptr(ngid), uintptr(unsafe.Pointer(gid)), 0, 0, 0, 0)
 	n = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -103,7 +103,7 @@
 func setgroups(ngid int, gid *_Gid_t) (err error) {
 	_, _, e1 := rawSysvicall6(procsetgroups.Addr(), 2, uintptr(ngid), uintptr(unsafe.Pointer(gid)), 0, 0, 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -112,7 +112,7 @@
 	r0, _, e1 := sysvicall6(procfcntl.Addr(), 3, uintptr(fd), uintptr(cmd), uintptr(arg), 0, 0, 0)
 	val = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -121,7 +121,7 @@
 	r0, _, e1 := sysvicall6(procaccept.Addr(), 3, uintptr(s), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)), 0, 0, 0)
 	fd = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -130,7 +130,7 @@
 	r0, _, e1 := sysvicall6(procsendmsg.Addr(), 3, uintptr(s), uintptr(unsafe.Pointer(msg)), uintptr(flags), 0, 0, 0)
 	n = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -144,7 +144,7 @@
 	_, _, e1 := sysvicall6(procAccess.Addr(), 2, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0, 0, 0, 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -152,7 +152,7 @@
 func Adjtime(delta *Timeval, olddelta *Timeval) (err error) {
 	_, _, e1 := sysvicall6(procAdjtime.Addr(), 2, uintptr(unsafe.Pointer(delta)), uintptr(unsafe.Pointer(olddelta)), 0, 0, 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -166,7 +166,7 @@
 	_, _, e1 := sysvicall6(procChdir.Addr(), 1, uintptr(unsafe.Pointer(_p0)), 0, 0, 0, 0, 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -180,7 +180,7 @@
 	_, _, e1 := sysvicall6(procChmod.Addr(), 2, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0, 0, 0, 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -194,7 +194,7 @@
 	_, _, e1 := sysvicall6(procChown.Addr(), 3, uintptr(unsafe.Pointer(_p0)), uintptr(uid), uintptr(gid), 0, 0, 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -208,7 +208,7 @@
 	_, _, e1 := sysvicall6(procChroot.Addr(), 1, uintptr(unsafe.Pointer(_p0)), 0, 0, 0, 0, 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -216,7 +216,7 @@
 func Close(fd int) (err error) {
 	_, _, e1 := sysvicall6(procClose.Addr(), 1, uintptr(fd), 0, 0, 0, 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -225,7 +225,7 @@
 	r0, _, e1 := sysvicall6(procDup.Addr(), 1, uintptr(fd), 0, 0, 0, 0, 0)
 	nfd = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -238,7 +238,7 @@
 func Fchdir(fd int) (err error) {
 	_, _, e1 := sysvicall6(procFchdir.Addr(), 1, uintptr(fd), 0, 0, 0, 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -246,7 +246,7 @@
 func Fchmod(fd int, mode uint32) (err error) {
 	_, _, e1 := sysvicall6(procFchmod.Addr(), 2, uintptr(fd), uintptr(mode), 0, 0, 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -254,7 +254,7 @@
 func Fchown(fd int, uid int, gid int) (err error) {
 	_, _, e1 := sysvicall6(procFchown.Addr(), 3, uintptr(fd), uintptr(uid), uintptr(gid), 0, 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -263,7 +263,7 @@
 	r0, _, e1 := sysvicall6(procFpathconf.Addr(), 2, uintptr(fd), uintptr(name), 0, 0, 0, 0)
 	val = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -271,7 +271,7 @@
 func Fstat(fd int, stat *Stat_t) (err error) {
 	_, _, e1 := sysvicall6(procFstat.Addr(), 2, uintptr(fd), uintptr(unsafe.Pointer(stat)), 0, 0, 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -284,7 +284,7 @@
 	r0, _, e1 := sysvicall6(procGetdents.Addr(), 4, uintptr(fd), uintptr(unsafe.Pointer(_p0)), uintptr(len(buf)), uintptr(unsafe.Pointer(basep)), 0, 0)
 	n = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -323,7 +323,7 @@
 	r0, _, e1 := sysvicall6(procGetpriority.Addr(), 2, uintptr(which), uintptr(who), 0, 0, 0, 0)
 	n = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -331,7 +331,7 @@
 func Getrlimit(which int, lim *Rlimit) (err error) {
 	_, _, e1 := rawSysvicall6(procGetrlimit.Addr(), 2, uintptr(which), uintptr(unsafe.Pointer(lim)), 0, 0, 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -339,7 +339,7 @@
 func Gettimeofday(tv *Timeval) (err error) {
 	_, _, e1 := rawSysvicall6(procGettimeofday.Addr(), 1, uintptr(unsafe.Pointer(tv)), 0, 0, 0, 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -353,7 +353,7 @@
 func Kill(pid int, signum Signal) (err error) {
 	_, _, e1 := sysvicall6(procKill.Addr(), 2, uintptr(pid), uintptr(signum), 0, 0, 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -367,7 +367,7 @@
 	_, _, e1 := sysvicall6(procLchown.Addr(), 3, uintptr(unsafe.Pointer(_p0)), uintptr(uid), uintptr(gid), 0, 0, 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -387,7 +387,7 @@
 	use(unsafe.Pointer(_p0))
 	use(unsafe.Pointer(_p1))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -395,7 +395,7 @@
 func Listen(s int, backlog int) (err error) {
 	_, _, e1 := sysvicall6(proclisten.Addr(), 2, uintptr(s), uintptr(backlog), 0, 0, 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -409,7 +409,7 @@
 	_, _, e1 := sysvicall6(procLstat.Addr(), 2, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0, 0, 0, 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -423,7 +423,7 @@
 	_, _, e1 := sysvicall6(procMkdir.Addr(), 2, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0, 0, 0, 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -437,7 +437,7 @@
 	_, _, e1 := sysvicall6(procMknod.Addr(), 3, uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(dev), 0, 0, 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -445,7 +445,7 @@
 func Nanosleep(time *Timespec, leftover *Timespec) (err error) {
 	_, _, e1 := sysvicall6(procNanosleep.Addr(), 2, uintptr(unsafe.Pointer(time)), uintptr(unsafe.Pointer(leftover)), 0, 0, 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -460,7 +460,7 @@
 	use(unsafe.Pointer(_p0))
 	fd = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -475,7 +475,7 @@
 	use(unsafe.Pointer(_p0))
 	val = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -488,7 +488,7 @@
 	r0, _, e1 := sysvicall6(procPread.Addr(), 4, uintptr(fd), uintptr(unsafe.Pointer(_p0)), uintptr(len(p)), uintptr(offset), 0, 0)
 	n = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -501,7 +501,7 @@
 	r0, _, e1 := sysvicall6(procPwrite.Addr(), 4, uintptr(fd), uintptr(unsafe.Pointer(_p0)), uintptr(len(p)), uintptr(offset), 0, 0)
 	n = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -514,7 +514,7 @@
 	r0, _, e1 := sysvicall6(procread.Addr(), 3, uintptr(fd), uintptr(unsafe.Pointer(_p0)), uintptr(len(p)), 0, 0, 0)
 	n = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -533,7 +533,7 @@
 	use(unsafe.Pointer(_p0))
 	n = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -553,7 +553,7 @@
 	use(unsafe.Pointer(_p0))
 	use(unsafe.Pointer(_p1))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -567,7 +567,7 @@
 	_, _, e1 := sysvicall6(procRmdir.Addr(), 1, uintptr(unsafe.Pointer(_p0)), 0, 0, 0, 0, 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -576,7 +576,7 @@
 	r0, _, e1 := sysvicall6(proclseek.Addr(), 3, uintptr(fd), uintptr(offset), uintptr(whence), 0, 0, 0)
 	newoffset = int64(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -584,7 +584,7 @@
 func Setegid(egid int) (err error) {
 	_, _, e1 := rawSysvicall6(procSetegid.Addr(), 1, uintptr(egid), 0, 0, 0, 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -592,7 +592,7 @@
 func Seteuid(euid int) (err error) {
 	_, _, e1 := rawSysvicall6(procSeteuid.Addr(), 1, uintptr(euid), 0, 0, 0, 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -600,7 +600,7 @@
 func Setgid(gid int) (err error) {
 	_, _, e1 := rawSysvicall6(procSetgid.Addr(), 1, uintptr(gid), 0, 0, 0, 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -608,7 +608,7 @@
 func Setpgid(pid int, pgid int) (err error) {
 	_, _, e1 := rawSysvicall6(procSetpgid.Addr(), 2, uintptr(pid), uintptr(pgid), 0, 0, 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -616,7 +616,7 @@
 func Setpriority(which int, who int, prio int) (err error) {
 	_, _, e1 := sysvicall6(procSetpriority.Addr(), 3, uintptr(which), uintptr(who), uintptr(prio), 0, 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -624,7 +624,7 @@
 func Setregid(rgid int, egid int) (err error) {
 	_, _, e1 := rawSysvicall6(procSetregid.Addr(), 2, uintptr(rgid), uintptr(egid), 0, 0, 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -632,7 +632,7 @@
 func Setreuid(ruid int, euid int) (err error) {
 	_, _, e1 := rawSysvicall6(procSetreuid.Addr(), 2, uintptr(ruid), uintptr(euid), 0, 0, 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -640,7 +640,7 @@
 func Setrlimit(which int, lim *Rlimit) (err error) {
 	_, _, e1 := rawSysvicall6(procSetrlimit.Addr(), 2, uintptr(which), uintptr(unsafe.Pointer(lim)), 0, 0, 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -649,7 +649,7 @@
 	r0, _, e1 := rawSysvicall6(procSetsid.Addr(), 0, 0, 0, 0, 0, 0, 0)
 	pid = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -657,7 +657,7 @@
 func Setuid(uid int) (err error) {
 	_, _, e1 := rawSysvicall6(procSetuid.Addr(), 1, uintptr(uid), 0, 0, 0, 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -665,7 +665,7 @@
 func Shutdown(s int, how int) (err error) {
 	_, _, e1 := sysvicall6(procshutdown.Addr(), 2, uintptr(s), uintptr(how), 0, 0, 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -679,7 +679,7 @@
 	_, _, e1 := sysvicall6(procStat.Addr(), 2, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0, 0, 0, 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -699,7 +699,7 @@
 	use(unsafe.Pointer(_p0))
 	use(unsafe.Pointer(_p1))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -707,7 +707,7 @@
 func Sync() (err error) {
 	_, _, e1 := sysvicall6(procSync.Addr(), 0, 0, 0, 0, 0, 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -721,7 +721,7 @@
 	_, _, e1 := sysvicall6(procTruncate.Addr(), 2, uintptr(unsafe.Pointer(_p0)), uintptr(length), 0, 0, 0, 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -729,7 +729,7 @@
 func Fsync(fd int) (err error) {
 	_, _, e1 := sysvicall6(procFsync.Addr(), 1, uintptr(fd), 0, 0, 0, 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -737,7 +737,7 @@
 func Ftruncate(fd int, length int64) (err error) {
 	_, _, e1 := sysvicall6(procFtruncate.Addr(), 2, uintptr(fd), uintptr(length), 0, 0, 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -757,7 +757,7 @@
 	_, _, e1 := sysvicall6(procUnlink.Addr(), 1, uintptr(unsafe.Pointer(_p0)), 0, 0, 0, 0, 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -771,7 +771,7 @@
 	_, _, e1 := sysvicall6(procUtimes.Addr(), 2, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(times)), 0, 0, 0, 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -779,7 +779,7 @@
 func bind(s int, addr unsafe.Pointer, addrlen _Socklen) (err error) {
 	_, _, e1 := sysvicall6(procbind.Addr(), 3, uintptr(s), uintptr(addr), uintptr(addrlen), 0, 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -787,7 +787,7 @@
 func connect(s int, addr unsafe.Pointer, addrlen _Socklen) (err error) {
 	_, _, e1 := sysvicall6(procconnect.Addr(), 3, uintptr(s), uintptr(addr), uintptr(addrlen), 0, 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -796,7 +796,7 @@
 	r0, _, e1 := sysvicall6(procmmap.Addr(), 6, uintptr(addr), uintptr(length), uintptr(prot), uintptr(flag), uintptr(fd), uintptr(pos))
 	ret = uintptr(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -804,7 +804,7 @@
 func munmap(addr uintptr, length uintptr) (err error) {
 	_, _, e1 := sysvicall6(procmunmap.Addr(), 2, uintptr(addr), uintptr(length), 0, 0, 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -816,7 +816,7 @@
 	}
 	_, _, e1 := sysvicall6(procsendto.Addr(), 6, uintptr(s), uintptr(unsafe.Pointer(_p0)), uintptr(len(buf)), uintptr(flags), uintptr(to), uintptr(addrlen))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -825,7 +825,7 @@
 	r0, _, e1 := sysvicall6(procsocket.Addr(), 3, uintptr(domain), uintptr(typ), uintptr(proto), 0, 0, 0)
 	fd = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -833,7 +833,7 @@
 func socketpair(domain int, typ int, proto int, fd *[2]int32) (err error) {
 	_, _, e1 := rawSysvicall6(procsocketpair.Addr(), 4, uintptr(domain), uintptr(typ), uintptr(proto), uintptr(unsafe.Pointer(fd)), 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -846,7 +846,7 @@
 	r0, _, e1 := sysvicall6(procwrite.Addr(), 3, uintptr(fd), uintptr(unsafe.Pointer(_p0)), uintptr(len(p)), 0, 0, 0)
 	n = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -854,7 +854,7 @@
 func getsockopt(s int, level int, name int, val unsafe.Pointer, vallen *_Socklen) (err error) {
 	_, _, e1 := sysvicall6(procgetsockopt.Addr(), 5, uintptr(s), uintptr(level), uintptr(name), uintptr(val), uintptr(unsafe.Pointer(vallen)), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -862,7 +862,7 @@
 func getpeername(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (err error) {
 	_, _, e1 := rawSysvicall6(procgetpeername.Addr(), 3, uintptr(fd), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)), 0, 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -870,7 +870,7 @@
 func getsockname(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (err error) {
 	_, _, e1 := sysvicall6(procgetsockname.Addr(), 3, uintptr(fd), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)), 0, 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -878,7 +878,7 @@
 func setsockopt(s int, level int, name int, val unsafe.Pointer, vallen uintptr) (err error) {
 	_, _, e1 := sysvicall6(procsetsockopt.Addr(), 5, uintptr(s), uintptr(level), uintptr(name), uintptr(val), uintptr(vallen), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -891,7 +891,7 @@
 	r0, _, e1 := sysvicall6(procrecvfrom.Addr(), 6, uintptr(fd), uintptr(unsafe.Pointer(_p0)), uintptr(len(p)), uintptr(flags), uintptr(unsafe.Pointer(from)), uintptr(unsafe.Pointer(fromlen)))
 	n = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -900,7 +900,7 @@
 	r0, _, e1 := sysvicall6(procrecvmsg.Addr(), 3, uintptr(s), uintptr(unsafe.Pointer(msg)), uintptr(flags), 0, 0, 0)
 	n = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
diff --git a/src/syscall/zsysnum_dragonfly_386.go b/src/syscall/zsysnum_dragonfly_386.go
deleted file mode 100644
index 4b086b9..0000000
--- a/src/syscall/zsysnum_dragonfly_386.go
+++ /dev/null
@@ -1,302 +0,0 @@
-// mksysnum_dragonfly.pl
-// MACHINE GENERATED BY THE ABOVE COMMAND; DO NOT EDIT
-
-package syscall
-
-const (
-	// SYS_NOSYS = 0;  // { int nosys(void); } syscall nosys_args int
-	SYS_EXIT          = 1   // { void exit(int rval); }
-	SYS_FORK          = 2   // { int fork(void); }
-	SYS_READ          = 3   // { ssize_t read(int fd, void *buf, size_t nbyte); }
-	SYS_WRITE         = 4   // { ssize_t write(int fd, const void *buf, size_t nbyte); }
-	SYS_OPEN          = 5   // { int open(char *path, int flags, int mode); }
-	SYS_CLOSE         = 6   // { int close(int fd); }
-	SYS_WAIT4         = 7   // { int wait4(int pid, int *status, int options, \
-	SYS_LINK          = 9   // { int link(char *path, char *link); }
-	SYS_UNLINK        = 10  // { int unlink(char *path); }
-	SYS_CHDIR         = 12  // { int chdir(char *path); }
-	SYS_FCHDIR        = 13  // { int fchdir(int fd); }
-	SYS_MKNOD         = 14  // { int mknod(char *path, int mode, int dev); }
-	SYS_CHMOD         = 15  // { int chmod(char *path, int mode); }
-	SYS_CHOWN         = 16  // { int chown(char *path, int uid, int gid); }
-	SYS_OBREAK        = 17  // { int obreak(char *nsize); } break obreak_args int
-	SYS_GETFSSTAT     = 18  // { int getfsstat(struct statfs *buf, long bufsize, \
-	SYS_GETPID        = 20  // { pid_t getpid(void); }
-	SYS_MOUNT         = 21  // { int mount(char *type, char *path, int flags, \
-	SYS_UNMOUNT       = 22  // { int unmount(char *path, int flags); }
-	SYS_SETUID        = 23  // { int setuid(uid_t uid); }
-	SYS_GETUID        = 24  // { uid_t getuid(void); }
-	SYS_GETEUID       = 25  // { uid_t geteuid(void); }
-	SYS_PTRACE        = 26  // { int ptrace(int req, pid_t pid, caddr_t addr, \
-	SYS_RECVMSG       = 27  // { int recvmsg(int s, struct msghdr *msg, int flags); }
-	SYS_SENDMSG       = 28  // { int sendmsg(int s, caddr_t msg, int flags); }
-	SYS_RECVFROM      = 29  // { int recvfrom(int s, caddr_t buf, size_t len, \
-	SYS_ACCEPT        = 30  // { int accept(int s, caddr_t name, int *anamelen); }
-	SYS_GETPEERNAME   = 31  // { int getpeername(int fdes, caddr_t asa, int *alen); }
-	SYS_GETSOCKNAME   = 32  // { int getsockname(int fdes, caddr_t asa, int *alen); }
-	SYS_ACCESS        = 33  // { int access(char *path, int flags); }
-	SYS_CHFLAGS       = 34  // { int chflags(char *path, int flags); }
-	SYS_FCHFLAGS      = 35  // { int fchflags(int fd, int flags); }
-	SYS_SYNC          = 36  // { int sync(void); }
-	SYS_KILL          = 37  // { int kill(int pid, int signum); }
-	SYS_GETPPID       = 39  // { pid_t getppid(void); }
-	SYS_DUP           = 41  // { int dup(u_int fd); }
-	SYS_PIPE          = 42  // { int pipe(void); }
-	SYS_GETEGID       = 43  // { gid_t getegid(void); }
-	SYS_PROFIL        = 44  // { int profil(caddr_t samples, size_t size, \
-	SYS_KTRACE        = 45  // { int ktrace(const char *fname, int ops, int facs, \
-	SYS_GETGID        = 47  // { gid_t getgid(void); }
-	SYS_GETLOGIN      = 49  // { int getlogin(char *namebuf, u_int namelen); }
-	SYS_SETLOGIN      = 50  // { int setlogin(char *namebuf); }
-	SYS_ACCT          = 51  // { int acct(char *path); }
-	SYS_SIGALTSTACK   = 53  // { int sigaltstack(stack_t *ss, stack_t *oss); }
-	SYS_IOCTL         = 54  // { int ioctl(int fd, u_long com, caddr_t data); }
-	SYS_REBOOT        = 55  // { int reboot(int opt); }
-	SYS_REVOKE        = 56  // { int revoke(char *path); }
-	SYS_SYMLINK       = 57  // { int symlink(char *path, char *link); }
-	SYS_READLINK      = 58  // { int readlink(char *path, char *buf, int count); }
-	SYS_EXECVE        = 59  // { int execve(char *fname, char **argv, char **envv); }
-	SYS_UMASK         = 60  // { int umask(int newmask); } umask umask_args int
-	SYS_CHROOT        = 61  // { int chroot(char *path); }
-	SYS_MSYNC         = 65  // { int msync(void *addr, size_t len, int flags); }
-	SYS_VFORK         = 66  // { pid_t vfork(void); }
-	SYS_SBRK          = 69  // { int sbrk(int incr); }
-	SYS_SSTK          = 70  // { int sstk(int incr); }
-	SYS_MUNMAP        = 73  // { int munmap(void *addr, size_t len); }
-	SYS_MPROTECT      = 74  // { int mprotect(void *addr, size_t len, int prot); }
-	SYS_MADVISE       = 75  // { int madvise(void *addr, size_t len, int behav); }
-	SYS_MINCORE       = 78  // { int mincore(const void *addr, size_t len, \
-	SYS_GETGROUPS     = 79  // { int getgroups(u_int gidsetsize, gid_t *gidset); }
-	SYS_SETGROUPS     = 80  // { int setgroups(u_int gidsetsize, gid_t *gidset); }
-	SYS_GETPGRP       = 81  // { int getpgrp(void); }
-	SYS_SETPGID       = 82  // { int setpgid(int pid, int pgid); }
-	SYS_SETITIMER     = 83  // { int setitimer(u_int which, struct itimerval *itv, \
-	SYS_SWAPON        = 85  // { int swapon(char *name); }
-	SYS_GETITIMER     = 86  // { int getitimer(u_int which, struct itimerval *itv); }
-	SYS_GETDTABLESIZE = 89  // { int getdtablesize(void); }
-	SYS_DUP2          = 90  // { int dup2(u_int from, u_int to); }
-	SYS_FCNTL         = 92  // { int fcntl(int fd, int cmd, long arg); }
-	SYS_SELECT        = 93  // { int select(int nd, fd_set *in, fd_set *ou, \
-	SYS_FSYNC         = 95  // { int fsync(int fd); }
-	SYS_SETPRIORITY   = 96  // { int setpriority(int which, int who, int prio); }
-	SYS_SOCKET        = 97  // { int socket(int domain, int type, int protocol); }
-	SYS_CONNECT       = 98  // { int connect(int s, caddr_t name, int namelen); }
-	SYS_GETPRIORITY   = 100 // { int getpriority(int which, int who); }
-	SYS_BIND          = 104 // { int bind(int s, caddr_t name, int namelen); }
-	SYS_SETSOCKOPT    = 105 // { int setsockopt(int s, int level, int name, \
-	SYS_LISTEN        = 106 // { int listen(int s, int backlog); }
-	SYS_GETTIMEOFDAY  = 116 // { int gettimeofday(struct timeval *tp, \
-	SYS_GETRUSAGE     = 117 // { int getrusage(int who, struct rusage *rusage); }
-	SYS_GETSOCKOPT    = 118 // { int getsockopt(int s, int level, int name, \
-	SYS_READV         = 120 // { int readv(int fd, struct iovec *iovp, u_int iovcnt); }
-	SYS_WRITEV        = 121 // { int writev(int fd, struct iovec *iovp, \
-	SYS_SETTIMEOFDAY  = 122 // { int settimeofday(struct timeval *tv, \
-	SYS_FCHOWN        = 123 // { int fchown(int fd, int uid, int gid); }
-	SYS_FCHMOD        = 124 // { int fchmod(int fd, int mode); }
-	SYS_SETREUID      = 126 // { int setreuid(int ruid, int euid); }
-	SYS_SETREGID      = 127 // { int setregid(int rgid, int egid); }
-	SYS_RENAME        = 128 // { int rename(char *from, char *to); }
-	SYS_FLOCK         = 131 // { int flock(int fd, int how); }
-	SYS_MKFIFO        = 132 // { int mkfifo(char *path, int mode); }
-	SYS_SENDTO        = 133 // { int sendto(int s, caddr_t buf, size_t len, \
-	SYS_SHUTDOWN      = 134 // { int shutdown(int s, int how); }
-	SYS_SOCKETPAIR    = 135 // { int socketpair(int domain, int type, int protocol, \
-	SYS_MKDIR         = 136 // { int mkdir(char *path, int mode); }
-	SYS_RMDIR         = 137 // { int rmdir(char *path); }
-	SYS_UTIMES        = 138 // { int utimes(char *path, struct timeval *tptr); }
-	SYS_ADJTIME       = 140 // { int adjtime(struct timeval *delta, \
-	SYS_SETSID        = 147 // { int setsid(void); }
-	SYS_QUOTACTL      = 148 // { int quotactl(char *path, int cmd, int uid, \
-	SYS_STATFS        = 157 // { int statfs(char *path, struct statfs *buf); }
-	SYS_FSTATFS       = 158 // { int fstatfs(int fd, struct statfs *buf); }
-	SYS_GETFH         = 161 // { int getfh(char *fname, struct fhandle *fhp); }
-	SYS_GETDOMAINNAME = 162 // { int getdomainname(char *domainname, int len); }
-	SYS_SETDOMAINNAME = 163 // { int setdomainname(char *domainname, int len); }
-	SYS_UNAME         = 164 // { int uname(struct utsname *name); }
-	SYS_SYSARCH       = 165 // { int sysarch(int op, char *parms); }
-	SYS_RTPRIO        = 166 // { int rtprio(int function, pid_t pid, \
-	SYS_EXTPREAD      = 173 // { ssize_t extpread(int fd, void *buf, \
-	SYS_EXTPWRITE     = 174 // { ssize_t extpwrite(int fd, const void *buf, \
-	SYS_NTP_ADJTIME   = 176 // { int ntp_adjtime(struct timex *tp); }
-	SYS_SETGID        = 181 // { int setgid(gid_t gid); }
-	SYS_SETEGID       = 182 // { int setegid(gid_t egid); }
-	SYS_SETEUID       = 183 // { int seteuid(uid_t euid); }
-	SYS_PATHCONF      = 191 // { int pathconf(char *path, int name); }
-	SYS_FPATHCONF     = 192 // { int fpathconf(int fd, int name); }
-	SYS_GETRLIMIT     = 194 // { int getrlimit(u_int which, \
-	SYS_SETRLIMIT     = 195 // { int setrlimit(u_int which, \
-	SYS_MMAP          = 197 // { caddr_t mmap(caddr_t addr, size_t len, int prot, \
-	// SYS_NOSYS = 198;  // { int nosys(void); } __syscall __syscall_args int
-	SYS_LSEEK                  = 199 // { off_t lseek(int fd, int pad, off_t offset, \
-	SYS_TRUNCATE               = 200 // { int truncate(char *path, int pad, off_t length); }
-	SYS_FTRUNCATE              = 201 // { int ftruncate(int fd, int pad, off_t length); }
-	SYS___SYSCTL               = 202 // { int __sysctl(int *name, u_int namelen, void *old, \
-	SYS_MLOCK                  = 203 // { int mlock(const void *addr, size_t len); }
-	SYS_MUNLOCK                = 204 // { int munlock(const void *addr, size_t len); }
-	SYS_UNDELETE               = 205 // { int undelete(char *path); }
-	SYS_FUTIMES                = 206 // { int futimes(int fd, struct timeval *tptr); }
-	SYS_GETPGID                = 207 // { int getpgid(pid_t pid); }
-	SYS_POLL                   = 209 // { int poll(struct pollfd *fds, u_int nfds, \
-	SYS___SEMCTL               = 220 // { int __semctl(int semid, int semnum, int cmd, \
-	SYS_SEMGET                 = 221 // { int semget(key_t key, int nsems, int semflg); }
-	SYS_SEMOP                  = 222 // { int semop(int semid, struct sembuf *sops, \
-	SYS_MSGCTL                 = 224 // { int msgctl(int msqid, int cmd, \
-	SYS_MSGGET                 = 225 // { int msgget(key_t key, int msgflg); }
-	SYS_MSGSND                 = 226 // { int msgsnd(int msqid, void *msgp, size_t msgsz, \
-	SYS_MSGRCV                 = 227 // { int msgrcv(int msqid, void *msgp, size_t msgsz, \
-	SYS_SHMAT                  = 228 // { caddr_t shmat(int shmid, const void *shmaddr, \
-	SYS_SHMCTL                 = 229 // { int shmctl(int shmid, int cmd, \
-	SYS_SHMDT                  = 230 // { int shmdt(const void *shmaddr); }
-	SYS_SHMGET                 = 231 // { int shmget(key_t key, size_t size, int shmflg); }
-	SYS_CLOCK_GETTIME          = 232 // { int clock_gettime(clockid_t clock_id, \
-	SYS_CLOCK_SETTIME          = 233 // { int clock_settime(clockid_t clock_id, \
-	SYS_CLOCK_GETRES           = 234 // { int clock_getres(clockid_t clock_id, \
-	SYS_NANOSLEEP              = 240 // { int nanosleep(const struct timespec *rqtp, \
-	SYS_MINHERIT               = 250 // { int minherit(void *addr, size_t len, int inherit); }
-	SYS_RFORK                  = 251 // { int rfork(int flags); }
-	SYS_OPENBSD_POLL           = 252 // { int openbsd_poll(struct pollfd *fds, u_int nfds, \
-	SYS_ISSETUGID              = 253 // { int issetugid(void); }
-	SYS_LCHOWN                 = 254 // { int lchown(char *path, int uid, int gid); }
-	SYS_LCHMOD                 = 274 // { int lchmod(char *path, mode_t mode); }
-	SYS_LUTIMES                = 276 // { int lutimes(char *path, struct timeval *tptr); }
-	SYS_EXTPREADV              = 289 // { ssize_t extpreadv(int fd, struct iovec *iovp, \
-	SYS_EXTPWRITEV             = 290 // { ssize_t extpwritev(int fd, struct iovec *iovp,\
-	SYS_FHSTATFS               = 297 // { int fhstatfs(const struct fhandle *u_fhp, struct statfs *buf); }
-	SYS_FHOPEN                 = 298 // { int fhopen(const struct fhandle *u_fhp, int flags); }
-	SYS_MODNEXT                = 300 // { int modnext(int modid); }
-	SYS_MODSTAT                = 301 // { int modstat(int modid, struct module_stat* stat); }
-	SYS_MODFNEXT               = 302 // { int modfnext(int modid); }
-	SYS_MODFIND                = 303 // { int modfind(const char *name); }
-	SYS_KLDLOAD                = 304 // { int kldload(const char *file); }
-	SYS_KLDUNLOAD              = 305 // { int kldunload(int fileid); }
-	SYS_KLDFIND                = 306 // { int kldfind(const char *file); }
-	SYS_KLDNEXT                = 307 // { int kldnext(int fileid); }
-	SYS_KLDSTAT                = 308 // { int kldstat(int fileid, struct kld_file_stat* stat); }
-	SYS_KLDFIRSTMOD            = 309 // { int kldfirstmod(int fileid); }
-	SYS_GETSID                 = 310 // { int getsid(pid_t pid); }
-	SYS_SETRESUID              = 311 // { int setresuid(uid_t ruid, uid_t euid, uid_t suid); }
-	SYS_SETRESGID              = 312 // { int setresgid(gid_t rgid, gid_t egid, gid_t sgid); }
-	SYS_AIO_RETURN             = 314 // { int aio_return(struct aiocb *aiocbp); }
-	SYS_AIO_SUSPEND            = 315 // { int aio_suspend(struct aiocb * const * aiocbp, int nent, const struct timespec *timeout); }
-	SYS_AIO_CANCEL             = 316 // { int aio_cancel(int fd, struct aiocb *aiocbp); }
-	SYS_AIO_ERROR              = 317 // { int aio_error(struct aiocb *aiocbp); }
-	SYS_AIO_READ               = 318 // { int aio_read(struct aiocb *aiocbp); }
-	SYS_AIO_WRITE              = 319 // { int aio_write(struct aiocb *aiocbp); }
-	SYS_LIO_LISTIO             = 320 // { int lio_listio(int mode, struct aiocb * const *acb_list, int nent, struct sigevent *sig); }
-	SYS_YIELD                  = 321 // { int yield(void); }
-	SYS_MLOCKALL               = 324 // { int mlockall(int how); }
-	SYS_MUNLOCKALL             = 325 // { int munlockall(void); }
-	SYS___GETCWD               = 326 // { int __getcwd(u_char *buf, u_int buflen); }
-	SYS_SCHED_SETPARAM         = 327 // { int sched_setparam (pid_t pid, const struct sched_param *param); }
-	SYS_SCHED_GETPARAM         = 328 // { int sched_getparam (pid_t pid, struct sched_param *param); }
-	SYS_SCHED_SETSCHEDULER     = 329 // { int sched_setscheduler (pid_t pid, int policy, const struct sched_param *param); }
-	SYS_SCHED_GETSCHEDULER     = 330 // { int sched_getscheduler (pid_t pid); }
-	SYS_SCHED_YIELD            = 331 // { int sched_yield (void); }
-	SYS_SCHED_GET_PRIORITY_MAX = 332 // { int sched_get_priority_max (int policy); }
-	SYS_SCHED_GET_PRIORITY_MIN = 333 // { int sched_get_priority_min (int policy); }
-	SYS_SCHED_RR_GET_INTERVAL  = 334 // { int sched_rr_get_interval (pid_t pid, struct timespec *interval); }
-	SYS_UTRACE                 = 335 // { int utrace(const void *addr, size_t len); }
-	SYS_KLDSYM                 = 337 // { int kldsym(int fileid, int cmd, void *data); }
-	SYS_JAIL                   = 338 // { int jail(struct jail *jail); }
-	SYS_SIGPROCMASK            = 340 // { int sigprocmask(int how, const sigset_t *set, \
-	SYS_SIGSUSPEND             = 341 // { int sigsuspend(const sigset_t *sigmask); }
-	SYS_SIGACTION              = 342 // { int sigaction(int sig, const struct sigaction *act, \
-	SYS_SIGPENDING             = 343 // { int sigpending(sigset_t *set); }
-	SYS_SIGRETURN              = 344 // { int sigreturn(ucontext_t *sigcntxp); }
-	SYS_SIGTIMEDWAIT           = 345 // { int sigtimedwait(const sigset_t *set,\
-	SYS_SIGWAITINFO            = 346 // { int sigwaitinfo(const sigset_t *set,\
-	SYS___ACL_GET_FILE         = 347 // { int __acl_get_file(const char *path, \
-	SYS___ACL_SET_FILE         = 348 // { int __acl_set_file(const char *path, \
-	SYS___ACL_GET_FD           = 349 // { int __acl_get_fd(int filedes, acl_type_t type, \
-	SYS___ACL_SET_FD           = 350 // { int __acl_set_fd(int filedes, acl_type_t type, \
-	SYS___ACL_DELETE_FILE      = 351 // { int __acl_delete_file(const char *path, \
-	SYS___ACL_DELETE_FD        = 352 // { int __acl_delete_fd(int filedes, acl_type_t type); }
-	SYS___ACL_ACLCHECK_FILE    = 353 // { int __acl_aclcheck_file(const char *path, \
-	SYS___ACL_ACLCHECK_FD      = 354 // { int __acl_aclcheck_fd(int filedes, acl_type_t type, \
-	SYS_EXTATTRCTL             = 355 // { int extattrctl(const char *path, int cmd, \
-	SYS_EXTATTR_SET_FILE       = 356 // { int extattr_set_file(const char *path, \
-	SYS_EXTATTR_GET_FILE       = 357 // { int extattr_get_file(const char *path, \
-	SYS_EXTATTR_DELETE_FILE    = 358 // { int extattr_delete_file(const char *path, \
-	SYS_AIO_WAITCOMPLETE       = 359 // { int aio_waitcomplete(struct aiocb **aiocbp, struct timespec *timeout); }
-	SYS_GETRESUID              = 360 // { int getresuid(uid_t *ruid, uid_t *euid, uid_t *suid); }
-	SYS_GETRESGID              = 361 // { int getresgid(gid_t *rgid, gid_t *egid, gid_t *sgid); }
-	SYS_KQUEUE                 = 362 // { int kqueue(void); }
-	SYS_KEVENT                 = 363 // { int kevent(int fd, \
-	SYS_SCTP_PEELOFF           = 364 // { int sctp_peeloff(int sd, caddr_t name ); }
-	SYS_LCHFLAGS               = 391 // { int lchflags(char *path, int flags); }
-	SYS_UUIDGEN                = 392 // { int uuidgen(struct uuid *store, int count); }
-	SYS_SENDFILE               = 393 // { int sendfile(int fd, int s, off_t offset, size_t nbytes, \
-	SYS_VARSYM_SET             = 450 // { int varsym_set(int level, const char *name, const char *data); }
-	SYS_VARSYM_GET             = 451 // { int varsym_get(int mask, const char *wild, char *buf, int bufsize); }
-	SYS_VARSYM_LIST            = 452 // { int varsym_list(int level, char *buf, int maxsize, int *marker); }
-	SYS_EXEC_SYS_REGISTER      = 465 // { int exec_sys_register(void *entry); }
-	SYS_EXEC_SYS_UNREGISTER    = 466 // { int exec_sys_unregister(int id); }
-	SYS_SYS_CHECKPOINT         = 467 // { int sys_checkpoint(int type, int fd, pid_t pid, int retval); }
-	SYS_MOUNTCTL               = 468 // { int mountctl(const char *path, int op, int fd, const void *ctl, int ctllen, void *buf, int buflen); }
-	SYS_UMTX_SLEEP             = 469 // { int umtx_sleep(volatile const int *ptr, int value, int timeout); }
-	SYS_UMTX_WAKEUP            = 470 // { int umtx_wakeup(volatile const int *ptr, int count); }
-	SYS_JAIL_ATTACH            = 471 // { int jail_attach(int jid); }
-	SYS_SET_TLS_AREA           = 472 // { int set_tls_area(int which, struct tls_info *info, size_t infosize); }
-	SYS_GET_TLS_AREA           = 473 // { int get_tls_area(int which, struct tls_info *info, size_t infosize); }
-	SYS_CLOSEFROM              = 474 // { int closefrom(int fd); }
-	SYS_STAT                   = 475 // { int stat(const char *path, struct stat *ub); }
-	SYS_FSTAT                  = 476 // { int fstat(int fd, struct stat *sb); }
-	SYS_LSTAT                  = 477 // { int lstat(const char *path, struct stat *ub); }
-	SYS_FHSTAT                 = 478 // { int fhstat(const struct fhandle *u_fhp, struct stat *sb); }
-	SYS_GETDIRENTRIES          = 479 // { int getdirentries(int fd, char *buf, u_int count, \
-	SYS_GETDENTS               = 480 // { int getdents(int fd, char *buf, size_t count); }
-	SYS_USCHED_SET             = 481 // { int usched_set(pid_t pid, int cmd, void *data, \
-	SYS_EXTACCEPT              = 482 // { int extaccept(int s, int flags, caddr_t name, int *anamelen); }
-	SYS_EXTCONNECT             = 483 // { int extconnect(int s, int flags, caddr_t name, int namelen); }
-	SYS_MCONTROL               = 485 // { int mcontrol(void *addr, size_t len, int behav, off_t value); }
-	SYS_VMSPACE_CREATE         = 486 // { int vmspace_create(void *id, int type, void *data); }
-	SYS_VMSPACE_DESTROY        = 487 // { int vmspace_destroy(void *id); }
-	SYS_VMSPACE_CTL            = 488 // { int vmspace_ctl(void *id, int cmd, 		\
-	SYS_VMSPACE_MMAP           = 489 // { int vmspace_mmap(void *id, void *addr, size_t len, \
-	SYS_VMSPACE_MUNMAP         = 490 // { int vmspace_munmap(void *id, void *addr,	\
-	SYS_VMSPACE_MCONTROL       = 491 // { int vmspace_mcontrol(void *id, void *addr, 	\
-	SYS_VMSPACE_PREAD          = 492 // { ssize_t vmspace_pread(void *id, void *buf, \
-	SYS_VMSPACE_PWRITE         = 493 // { ssize_t vmspace_pwrite(void *id, const void *buf, \
-	SYS_EXTEXIT                = 494 // { void extexit(int how, int status, void *addr); }
-	SYS_LWP_CREATE             = 495 // { int lwp_create(struct lwp_params *params); }
-	SYS_LWP_GETTID             = 496 // { lwpid_t lwp_gettid(void); }
-	SYS_LWP_KILL               = 497 // { int lwp_kill(pid_t pid, lwpid_t tid, int signum); }
-	SYS_LWP_RTPRIO             = 498 // { int lwp_rtprio(int function, pid_t pid, lwpid_t tid, struct rtprio *rtp); }
-	SYS_PSELECT                = 499 // { int pselect(int nd, fd_set *in, fd_set *ou, \
-	SYS_STATVFS                = 500 // { int statvfs(const char *path, struct statvfs *buf); }
-	SYS_FSTATVFS               = 501 // { int fstatvfs(int fd, struct statvfs *buf); }
-	SYS_FHSTATVFS              = 502 // { int fhstatvfs(const struct fhandle *u_fhp, struct statvfs *buf); }
-	SYS_GETVFSSTAT             = 503 // { int getvfsstat(struct statfs *buf,          \
-	SYS_OPENAT                 = 504 // { int openat(int fd, char *path, int flags, int mode); }
-	SYS_FSTATAT                = 505 // { int fstatat(int fd, char *path, 	\
-	SYS_FCHMODAT               = 506 // { int fchmodat(int fd, char *path, int mode, \
-	SYS_FCHOWNAT               = 507 // { int fchownat(int fd, char *path, int uid, int gid, \
-	SYS_UNLINKAT               = 508 // { int unlinkat(int fd, char *path, int flags); }
-	SYS_FACCESSAT              = 509 // { int faccessat(int fd, char *path, int amode, \
-	SYS_MQ_OPEN                = 510 // { mqd_t mq_open(const char * name, int oflag, \
-	SYS_MQ_CLOSE               = 511 // { int mq_close(mqd_t mqdes); }
-	SYS_MQ_UNLINK              = 512 // { int mq_unlink(const char *name); }
-	SYS_MQ_GETATTR             = 513 // { int mq_getattr(mqd_t mqdes, \
-	SYS_MQ_SETATTR             = 514 // { int mq_setattr(mqd_t mqdes, \
-	SYS_MQ_NOTIFY              = 515 // { int mq_notify(mqd_t mqdes, \
-	SYS_MQ_SEND                = 516 // { int mq_send(mqd_t mqdes, const char *msg_ptr, \
-	SYS_MQ_RECEIVE             = 517 // { ssize_t mq_receive(mqd_t mqdes, char *msg_ptr, \
-	SYS_MQ_TIMEDSEND           = 518 // { int mq_timedsend(mqd_t mqdes, \
-	SYS_MQ_TIMEDRECEIVE        = 519 // { ssize_t mq_timedreceive(mqd_t mqdes, \
-	SYS_IOPRIO_SET             = 520 // { int ioprio_set(int which, int who, int prio); }
-	SYS_IOPRIO_GET             = 521 // { int ioprio_get(int which, int who); }
-	SYS_CHROOT_KERNEL          = 522 // { int chroot_kernel(char *path); }
-	SYS_RENAMEAT               = 523 // { int renameat(int oldfd, char *old, int newfd, \
-	SYS_MKDIRAT                = 524 // { int mkdirat(int fd, char *path, mode_t mode); }
-	SYS_MKFIFOAT               = 525 // { int mkfifoat(int fd, char *path, mode_t mode); }
-	SYS_MKNODAT                = 526 // { int mknodat(int fd, char *path, mode_t mode, \
-	SYS_READLINKAT             = 527 // { int readlinkat(int fd, char *path, char *buf, \
-	SYS_SYMLINKAT              = 528 // { int symlinkat(char *path1, int fd, char *path2); }
-	SYS_SWAPOFF                = 529 // { int swapoff(char *name); }
-	SYS_VQUOTACTL              = 530 // { int vquotactl(const char *path, \
-	SYS_LINKAT                 = 531 // { int linkat(int fd1, char *path1, int fd2, \
-	SYS_EACCESS                = 532 // { int eaccess(char *path, int flags); }
-	SYS_LPATHCONF              = 533 // { int lpathconf(char *path, int name); }
-	SYS_VMM_GUEST_CTL          = 534 // { int vmm_guest_ctl(int op, struct vmm_guest_options *options); }
-	SYS_VMM_GUEST_SYNC_ADDR    = 535 // { int vmm_guest_sync_addr(long *dstaddr, long *srcaddr); }
-)
diff --git a/src/syscall/zsysnum_linux_arm64.go b/src/syscall/zsysnum_linux_arm64.go
new file mode 100644
index 0000000..4bcf057
--- /dev/null
+++ b/src/syscall/zsysnum_linux_arm64.go
@@ -0,0 +1,275 @@
+// mksysnum_linux.pl /usr/include/asm-generic/unistd.h
+// MACHINE GENERATED BY THE ABOVE COMMAND; DO NOT EDIT
+
+package syscall
+
+const (
+	SYS_IO_SETUP               = 0
+	SYS_IO_DESTROY             = 1
+	SYS_IO_SUBMIT              = 2
+	SYS_IO_CANCEL              = 3
+	SYS_IO_GETEVENTS           = 4
+	SYS_SETXATTR               = 5
+	SYS_LSETXATTR              = 6
+	SYS_FSETXATTR              = 7
+	SYS_GETXATTR               = 8
+	SYS_LGETXATTR              = 9
+	SYS_FGETXATTR              = 10
+	SYS_LISTXATTR              = 11
+	SYS_LLISTXATTR             = 12
+	SYS_FLISTXATTR             = 13
+	SYS_REMOVEXATTR            = 14
+	SYS_LREMOVEXATTR           = 15
+	SYS_FREMOVEXATTR           = 16
+	SYS_GETCWD                 = 17
+	SYS_LOOKUP_DCOOKIE         = 18
+	SYS_EVENTFD2               = 19
+	SYS_EPOLL_CREATE1          = 20
+	SYS_EPOLL_CTL              = 21
+	SYS_EPOLL_PWAIT            = 22
+	SYS_DUP                    = 23
+	SYS_DUP3                   = 24
+	SYS_FCNTL                  = 25
+	SYS_INOTIFY_INIT1          = 26
+	SYS_INOTIFY_ADD_WATCH      = 27
+	SYS_INOTIFY_RM_WATCH       = 28
+	SYS_IOCTL                  = 29
+	SYS_IOPRIO_SET             = 30
+	SYS_IOPRIO_GET             = 31
+	SYS_FLOCK                  = 32
+	SYS_MKNODAT                = 33
+	SYS_MKDIRAT                = 34
+	SYS_UNLINKAT               = 35
+	SYS_SYMLINKAT              = 36
+	SYS_LINKAT                 = 37
+	SYS_RENAMEAT               = 38
+	SYS_UMOUNT2                = 39
+	SYS_MOUNT                  = 40
+	SYS_PIVOT_ROOT             = 41
+	SYS_NFSSERVCTL             = 42
+	SYS_STATFS                 = 43
+	SYS_FSTATFS                = 44
+	SYS_TRUNCATE               = 45
+	SYS_FTRUNCATE              = 46
+	SYS_FALLOCATE              = 47
+	SYS_FACCESSAT              = 48
+	SYS_CHDIR                  = 49
+	SYS_FCHDIR                 = 50
+	SYS_CHROOT                 = 51
+	SYS_FCHMOD                 = 52
+	SYS_FCHMODAT               = 53
+	SYS_FCHOWNAT               = 54
+	SYS_FCHOWN                 = 55
+	SYS_OPENAT                 = 56
+	SYS_CLOSE                  = 57
+	SYS_VHANGUP                = 58
+	SYS_PIPE2                  = 59
+	SYS_QUOTACTL               = 60
+	SYS_GETDENTS64             = 61
+	SYS_LSEEK                  = 62
+	SYS_READ                   = 63
+	SYS_WRITE                  = 64
+	SYS_READV                  = 65
+	SYS_WRITEV                 = 66
+	SYS_PREAD64                = 67
+	SYS_PWRITE64               = 68
+	SYS_PREADV                 = 69
+	SYS_PWRITEV                = 70
+	SYS_SENDFILE               = 71
+	SYS_PSELECT6               = 72
+	SYS_PPOLL                  = 73
+	SYS_SIGNALFD4              = 74
+	SYS_VMSPLICE               = 75
+	SYS_SPLICE                 = 76
+	SYS_TEE                    = 77
+	SYS_READLINKAT             = 78
+	SYS_FSTATAT                = 79
+	SYS_FSTAT                  = 80
+	SYS_SYNC                   = 81
+	SYS_FSYNC                  = 82
+	SYS_FDATASYNC              = 83
+	SYS_SYNC_FILE_RANGE2       = 84
+	SYS_SYNC_FILE_RANGE        = 84
+	SYS_TIMERFD_CREATE         = 85
+	SYS_TIMERFD_SETTIME        = 86
+	SYS_TIMERFD_GETTIME        = 87
+	SYS_UTIMENSAT              = 88
+	SYS_ACCT                   = 89
+	SYS_CAPGET                 = 90
+	SYS_CAPSET                 = 91
+	SYS_PERSONALITY            = 92
+	SYS_EXIT                   = 93
+	SYS_EXIT_GROUP             = 94
+	SYS_WAITID                 = 95
+	SYS_SET_TID_ADDRESS        = 96
+	SYS_UNSHARE                = 97
+	SYS_FUTEX                  = 98
+	SYS_SET_ROBUST_LIST        = 99
+	SYS_GET_ROBUST_LIST        = 100
+	SYS_NANOSLEEP              = 101
+	SYS_GETITIMER              = 102
+	SYS_SETITIMER              = 103
+	SYS_KEXEC_LOAD             = 104
+	SYS_INIT_MODULE            = 105
+	SYS_DELETE_MODULE          = 106
+	SYS_TIMER_CREATE           = 107
+	SYS_TIMER_GETTIME          = 108
+	SYS_TIMER_GETOVERRUN       = 109
+	SYS_TIMER_SETTIME          = 110
+	SYS_TIMER_DELETE           = 111
+	SYS_CLOCK_SETTIME          = 112
+	SYS_CLOCK_GETTIME          = 113
+	SYS_CLOCK_GETRES           = 114
+	SYS_CLOCK_NANOSLEEP        = 115
+	SYS_SYSLOG                 = 116
+	SYS_PTRACE                 = 117
+	SYS_SCHED_SETPARAM         = 118
+	SYS_SCHED_SETSCHEDULER     = 119
+	SYS_SCHED_GETSCHEDULER     = 120
+	SYS_SCHED_GETPARAM         = 121
+	SYS_SCHED_SETAFFINITY      = 122
+	SYS_SCHED_GETAFFINITY      = 123
+	SYS_SCHED_YIELD            = 124
+	SYS_SCHED_GET_PRIORITY_MAX = 125
+	SYS_SCHED_GET_PRIORITY_MIN = 126
+	SYS_SCHED_RR_GET_INTERVAL  = 127
+	SYS_RESTART_SYSCALL        = 128
+	SYS_KILL                   = 129
+	SYS_TKILL                  = 130
+	SYS_TGKILL                 = 131
+	SYS_SIGALTSTACK            = 132
+	SYS_RT_SIGSUSPEND          = 133
+	SYS_RT_SIGACTION           = 134
+	SYS_RT_SIGPROCMASK         = 135
+	SYS_RT_SIGPENDING          = 136
+	SYS_RT_SIGTIMEDWAIT        = 137
+	SYS_RT_SIGQUEUEINFO        = 138
+	SYS_RT_SIGRETURN           = 139
+	SYS_SETPRIORITY            = 140
+	SYS_GETPRIORITY            = 141
+	SYS_REBOOT                 = 142
+	SYS_SETREGID               = 143
+	SYS_SETGID                 = 144
+	SYS_SETREUID               = 145
+	SYS_SETUID                 = 146
+	SYS_SETRESUID              = 147
+	SYS_GETRESUID              = 148
+	SYS_SETRESGID              = 149
+	SYS_GETRESGID              = 150
+	SYS_SETFSUID               = 151
+	SYS_SETFSGID               = 152
+	SYS_TIMES                  = 153
+	SYS_SETPGID                = 154
+	SYS_GETPGID                = 155
+	SYS_GETSID                 = 156
+	SYS_SETSID                 = 157
+	SYS_GETGROUPS              = 158
+	SYS_SETGROUPS              = 159
+	SYS_UNAME                  = 160
+	SYS_SETHOSTNAME            = 161
+	SYS_SETDOMAINNAME          = 162
+	SYS_GETRLIMIT              = 163
+	SYS_SETRLIMIT              = 164
+	SYS_GETRUSAGE              = 165
+	SYS_UMASK                  = 166
+	SYS_PRCTL                  = 167
+	SYS_GETCPU                 = 168
+	SYS_GETTIMEOFDAY           = 169
+	SYS_SETTIMEOFDAY           = 170
+	SYS_ADJTIMEX               = 171
+	SYS_GETPID                 = 172
+	SYS_GETPPID                = 173
+	SYS_GETUID                 = 174
+	SYS_GETEUID                = 175
+	SYS_GETGID                 = 176
+	SYS_GETEGID                = 177
+	SYS_GETTID                 = 178
+	SYS_SYSINFO                = 179
+	SYS_MQ_OPEN                = 180
+	SYS_MQ_UNLINK              = 181
+	SYS_MQ_TIMEDSEND           = 182
+	SYS_MQ_TIMEDRECEIVE        = 183
+	SYS_MQ_NOTIFY              = 184
+	SYS_MQ_GETSETATTR          = 185
+	SYS_MSGGET                 = 186
+	SYS_MSGCTL                 = 187
+	SYS_MSGRCV                 = 188
+	SYS_MSGSND                 = 189
+	SYS_SEMGET                 = 190
+	SYS_SEMCTL                 = 191
+	SYS_SEMTIMEDOP             = 192
+	SYS_SEMOP                  = 193
+	SYS_SHMGET                 = 194
+	SYS_SHMCTL                 = 195
+	SYS_SHMAT                  = 196
+	SYS_SHMDT                  = 197
+	SYS_SOCKET                 = 198
+	SYS_SOCKETPAIR             = 199
+	SYS_BIND                   = 200
+	SYS_LISTEN                 = 201
+	SYS_ACCEPT                 = 202
+	SYS_CONNECT                = 203
+	SYS_GETSOCKNAME            = 204
+	SYS_GETPEERNAME            = 205
+	SYS_SENDTO                 = 206
+	SYS_RECVFROM               = 207
+	SYS_SETSOCKOPT             = 208
+	SYS_GETSOCKOPT             = 209
+	SYS_SHUTDOWN               = 210
+	SYS_SENDMSG                = 211
+	SYS_RECVMSG                = 212
+	SYS_READAHEAD              = 213
+	SYS_BRK                    = 214
+	SYS_MUNMAP                 = 215
+	SYS_MREMAP                 = 216
+	SYS_ADD_KEY                = 217
+	SYS_REQUEST_KEY            = 218
+	SYS_KEYCTL                 = 219
+	SYS_CLONE                  = 220
+	SYS_EXECVE                 = 221
+	SYS_MMAP                   = 222
+	SYS_FADVISE64              = 223
+	SYS_SWAPON                 = 224
+	SYS_SWAPOFF                = 225
+	SYS_MPROTECT               = 226
+	SYS_MSYNC                  = 227
+	SYS_MLOCK                  = 228
+	SYS_MUNLOCK                = 229
+	SYS_MLOCKALL               = 230
+	SYS_MUNLOCKALL             = 231
+	SYS_MINCORE                = 232
+	SYS_MADVISE                = 233
+	SYS_REMAP_FILE_PAGES       = 234
+	SYS_MBIND                  = 235
+	SYS_GET_MEMPOLICY          = 236
+	SYS_SET_MEMPOLICY          = 237
+	SYS_MIGRATE_PAGES          = 238
+	SYS_MOVE_PAGES             = 239
+	SYS_RT_TGSIGQUEUEINFO      = 240
+	SYS_PERF_EVENT_OPEN        = 241
+	SYS_ACCEPT4                = 242
+	SYS_RECVMMSG               = 243
+	SYS_ARCH_SPECIFIC_SYSCALL  = 244
+	SYS_WAIT4                  = 260
+	SYS_PRLIMIT64              = 261
+	SYS_FANOTIFY_INIT          = 262
+	SYS_FANOTIFY_MARK          = 263
+	SYS_NAME_TO_HANDLE_AT      = 264
+	SYS_OPEN_BY_HANDLE_AT      = 265
+	SYS_CLOCK_ADJTIME          = 266
+	SYS_SYNCFS                 = 267
+	SYS_SETNS                  = 268
+	SYS_SENDMMSG               = 269
+	SYS_PROCESS_VM_READV       = 270
+	SYS_PROCESS_VM_WRITEV      = 271
+	SYS_KCMP                   = 272
+	SYS_FINIT_MODULE           = 273
+	SYS_SCHED_SETATTR          = 274
+	SYS_SCHED_GETATTR          = 275
+	SYS_RENAMEAT2              = 276
+	SYS_SECCOMP                = 277
+	SYS_GETRANDOM              = 278
+	SYS_MEMFD_CREATE           = 279
+	SYS_BPF                    = 280
+	SYS_EXECVEAT               = 281
+)
diff --git a/src/syscall/zsysnum_openbsd_arm.go b/src/syscall/zsysnum_openbsd_arm.go
new file mode 100644
index 0000000..8457c14
--- /dev/null
+++ b/src/syscall/zsysnum_openbsd_arm.go
@@ -0,0 +1,211 @@
+// mksysnum_openbsd.pl
+// MACHINE GENERATED BY THE ABOVE COMMAND; DO NOT EDIT
+
+package syscall
+
+const (
+	SYS_EXIT           = 1   // { void sys_exit(int rval); }
+	SYS_FORK           = 2   // { int sys_fork(void); }
+	SYS_READ           = 3   // { ssize_t sys_read(int fd, void *buf, size_t nbyte); }
+	SYS_WRITE          = 4   // { ssize_t sys_write(int fd, const void *buf, \
+	SYS_OPEN           = 5   // { int sys_open(const char *path, \
+	SYS_CLOSE          = 6   // { int sys_close(int fd); }
+	SYS_GETENTROPY     = 7   // { int sys_getentropy(void *buf, size_t nbyte); }
+	SYS___TFORK        = 8   // { int sys___tfork(const struct __tfork *param, \
+	SYS_LINK           = 9   // { int sys_link(const char *path, const char *link); }
+	SYS_UNLINK         = 10  // { int sys_unlink(const char *path); }
+	SYS_WAIT4          = 11  // { pid_t sys_wait4(pid_t pid, int *status, \
+	SYS_CHDIR          = 12  // { int sys_chdir(const char *path); }
+	SYS_FCHDIR         = 13  // { int sys_fchdir(int fd); }
+	SYS_MKNOD          = 14  // { int sys_mknod(const char *path, mode_t mode, \
+	SYS_CHMOD          = 15  // { int sys_chmod(const char *path, mode_t mode); }
+	SYS_CHOWN          = 16  // { int sys_chown(const char *path, uid_t uid, \
+	SYS_OBREAK         = 17  // { int sys_obreak(char *nsize); } break
+	SYS_GETDTABLECOUNT = 18  // { int sys_getdtablecount(void); }
+	SYS_GETRUSAGE      = 19  // { int sys_getrusage(int who, \
+	SYS_GETPID         = 20  // { pid_t sys_getpid(void); }
+	SYS_MOUNT          = 21  // { int sys_mount(const char *type, const char *path, \
+	SYS_UNMOUNT        = 22  // { int sys_unmount(const char *path, int flags); }
+	SYS_SETUID         = 23  // { int sys_setuid(uid_t uid); }
+	SYS_GETUID         = 24  // { uid_t sys_getuid(void); }
+	SYS_GETEUID        = 25  // { uid_t sys_geteuid(void); }
+	SYS_PTRACE         = 26  // { int sys_ptrace(int req, pid_t pid, caddr_t addr, \
+	SYS_RECVMSG        = 27  // { ssize_t sys_recvmsg(int s, struct msghdr *msg, \
+	SYS_SENDMSG        = 28  // { ssize_t sys_sendmsg(int s, \
+	SYS_RECVFROM       = 29  // { ssize_t sys_recvfrom(int s, void *buf, size_t len, \
+	SYS_ACCEPT         = 30  // { int sys_accept(int s, struct sockaddr *name, \
+	SYS_GETPEERNAME    = 31  // { int sys_getpeername(int fdes, struct sockaddr *asa, \
+	SYS_GETSOCKNAME    = 32  // { int sys_getsockname(int fdes, struct sockaddr *asa, \
+	SYS_ACCESS         = 33  // { int sys_access(const char *path, int amode); }
+	SYS_CHFLAGS        = 34  // { int sys_chflags(const char *path, u_int flags); }
+	SYS_FCHFLAGS       = 35  // { int sys_fchflags(int fd, u_int flags); }
+	SYS_SYNC           = 36  // { void sys_sync(void); }
+	SYS_KILL           = 37  // { int sys_kill(int pid, int signum); }
+	SYS_STAT           = 38  // { int sys_stat(const char *path, struct stat *ub); }
+	SYS_GETPPID        = 39  // { pid_t sys_getppid(void); }
+	SYS_LSTAT          = 40  // { int sys_lstat(const char *path, struct stat *ub); }
+	SYS_DUP            = 41  // { int sys_dup(int fd); }
+	SYS_FSTATAT        = 42  // { int sys_fstatat(int fd, const char *path, \
+	SYS_GETEGID        = 43  // { gid_t sys_getegid(void); }
+	SYS_PROFIL         = 44  // { int sys_profil(caddr_t samples, size_t size, \
+	SYS_KTRACE         = 45  // { int sys_ktrace(const char *fname, int ops, \
+	SYS_SIGACTION      = 46  // { int sys_sigaction(int signum, \
+	SYS_GETGID         = 47  // { gid_t sys_getgid(void); }
+	SYS_SIGPROCMASK    = 48  // { int sys_sigprocmask(int how, sigset_t mask); }
+	SYS_GETLOGIN       = 49  // { int sys_getlogin(char *namebuf, u_int namelen); }
+	SYS_SETLOGIN       = 50  // { int sys_setlogin(const char *namebuf); }
+	SYS_ACCT           = 51  // { int sys_acct(const char *path); }
+	SYS_SIGPENDING     = 52  // { int sys_sigpending(void); }
+	SYS_FSTAT          = 53  // { int sys_fstat(int fd, struct stat *sb); }
+	SYS_IOCTL          = 54  // { int sys_ioctl(int fd, \
+	SYS_REBOOT         = 55  // { int sys_reboot(int opt); }
+	SYS_REVOKE         = 56  // { int sys_revoke(const char *path); }
+	SYS_SYMLINK        = 57  // { int sys_symlink(const char *path, \
+	SYS_READLINK       = 58  // { ssize_t sys_readlink(const char *path, \
+	SYS_EXECVE         = 59  // { int sys_execve(const char *path, \
+	SYS_UMASK          = 60  // { mode_t sys_umask(mode_t newmask); }
+	SYS_CHROOT         = 61  // { int sys_chroot(const char *path); }
+	SYS_GETFSSTAT      = 62  // { int sys_getfsstat(struct statfs *buf, size_t bufsize, \
+	SYS_STATFS         = 63  // { int sys_statfs(const char *path, \
+	SYS_FSTATFS        = 64  // { int sys_fstatfs(int fd, struct statfs *buf); }
+	SYS_FHSTATFS       = 65  // { int sys_fhstatfs(const fhandle_t *fhp, \
+	SYS_VFORK          = 66  // { int sys_vfork(void); }
+	SYS_GETTIMEOFDAY   = 67  // { int sys_gettimeofday(struct timeval *tp, \
+	SYS_SETTIMEOFDAY   = 68  // { int sys_settimeofday(const struct timeval *tv, \
+	SYS_SETITIMER      = 69  // { int sys_setitimer(int which, \
+	SYS_GETITIMER      = 70  // { int sys_getitimer(int which, \
+	SYS_SELECT         = 71  // { int sys_select(int nd, fd_set *in, fd_set *ou, \
+	SYS_KEVENT         = 72  // { int sys_kevent(int fd, \
+	SYS_MUNMAP         = 73  // { int sys_munmap(void *addr, size_t len); }
+	SYS_MPROTECT       = 74  // { int sys_mprotect(void *addr, size_t len, \
+	SYS_MADVISE        = 75  // { int sys_madvise(void *addr, size_t len, \
+	SYS_UTIMES         = 76  // { int sys_utimes(const char *path, \
+	SYS_FUTIMES        = 77  // { int sys_futimes(int fd, \
+	SYS_MINCORE        = 78  // { int sys_mincore(void *addr, size_t len, \
+	SYS_GETGROUPS      = 79  // { int sys_getgroups(int gidsetsize, \
+	SYS_SETGROUPS      = 80  // { int sys_setgroups(int gidsetsize, \
+	SYS_GETPGRP        = 81  // { int sys_getpgrp(void); }
+	SYS_SETPGID        = 82  // { int sys_setpgid(pid_t pid, pid_t pgid); }
+	SYS_SENDSYSLOG     = 83  // { int sys_sendsyslog(const void *buf, size_t nbyte); }
+	SYS_UTIMENSAT      = 84  // { int sys_utimensat(int fd, const char *path, \
+	SYS_FUTIMENS       = 85  // { int sys_futimens(int fd, \
+	SYS_CLOCK_GETTIME  = 87  // { int sys_clock_gettime(clockid_t clock_id, \
+	SYS_CLOCK_SETTIME  = 88  // { int sys_clock_settime(clockid_t clock_id, \
+	SYS_CLOCK_GETRES   = 89  // { int sys_clock_getres(clockid_t clock_id, \
+	SYS_DUP2           = 90  // { int sys_dup2(int from, int to); }
+	SYS_NANOSLEEP      = 91  // { int sys_nanosleep(const struct timespec *rqtp, \
+	SYS_FCNTL          = 92  // { int sys_fcntl(int fd, int cmd, ... void *arg); }
+	SYS_ACCEPT4        = 93  // { int sys_accept4(int s, struct sockaddr *name, \
+	SYS___THRSLEEP     = 94  // { int sys___thrsleep(const volatile void *ident, \
+	SYS_FSYNC          = 95  // { int sys_fsync(int fd); }
+	SYS_SETPRIORITY    = 96  // { int sys_setpriority(int which, id_t who, int prio); }
+	SYS_SOCKET         = 97  // { int sys_socket(int domain, int type, int protocol); }
+	SYS_CONNECT        = 98  // { int sys_connect(int s, const struct sockaddr *name, \
+	SYS_GETDENTS       = 99  // { int sys_getdents(int fd, void *buf, size_t buflen); }
+	SYS_GETPRIORITY    = 100 // { int sys_getpriority(int which, id_t who); }
+	SYS_PIPE2          = 101 // { int sys_pipe2(int *fdp, int flags); }
+	SYS_DUP3           = 102 // { int sys_dup3(int from, int to, int flags); }
+	SYS_SIGRETURN      = 103 // { int sys_sigreturn(struct sigcontext *sigcntxp); }
+	SYS_BIND           = 104 // { int sys_bind(int s, const struct sockaddr *name, \
+	SYS_SETSOCKOPT     = 105 // { int sys_setsockopt(int s, int level, int name, \
+	SYS_LISTEN         = 106 // { int sys_listen(int s, int backlog); }
+	SYS_CHFLAGSAT      = 107 // { int sys_chflagsat(int fd, const char *path, \
+	SYS_PPOLL          = 109 // { int sys_ppoll(struct pollfd *fds, \
+	SYS_PSELECT        = 110 // { int sys_pselect(int nd, fd_set *in, fd_set *ou, \
+	SYS_SIGSUSPEND     = 111 // { int sys_sigsuspend(int mask); }
+	SYS_GETSOCKOPT     = 118 // { int sys_getsockopt(int s, int level, int name, \
+	SYS_READV          = 120 // { ssize_t sys_readv(int fd, \
+	SYS_WRITEV         = 121 // { ssize_t sys_writev(int fd, \
+	SYS_FCHOWN         = 123 // { int sys_fchown(int fd, uid_t uid, gid_t gid); }
+	SYS_FCHMOD         = 124 // { int sys_fchmod(int fd, mode_t mode); }
+	SYS_SETREUID       = 126 // { int sys_setreuid(uid_t ruid, uid_t euid); }
+	SYS_SETREGID       = 127 // { int sys_setregid(gid_t rgid, gid_t egid); }
+	SYS_RENAME         = 128 // { int sys_rename(const char *from, const char *to); }
+	SYS_FLOCK          = 131 // { int sys_flock(int fd, int how); }
+	SYS_MKFIFO         = 132 // { int sys_mkfifo(const char *path, mode_t mode); }
+	SYS_SENDTO         = 133 // { ssize_t sys_sendto(int s, const void *buf, \
+	SYS_SHUTDOWN       = 134 // { int sys_shutdown(int s, int how); }
+	SYS_SOCKETPAIR     = 135 // { int sys_socketpair(int domain, int type, \
+	SYS_MKDIR          = 136 // { int sys_mkdir(const char *path, mode_t mode); }
+	SYS_RMDIR          = 137 // { int sys_rmdir(const char *path); }
+	SYS_ADJTIME        = 140 // { int sys_adjtime(const struct timeval *delta, \
+	SYS_SETSID         = 147 // { int sys_setsid(void); }
+	SYS_QUOTACTL       = 148 // { int sys_quotactl(const char *path, int cmd, \
+	SYS_NFSSVC         = 155 // { int sys_nfssvc(int flag, void *argp); }
+	SYS_GETFH          = 161 // { int sys_getfh(const char *fname, fhandle_t *fhp); }
+	SYS_SYSARCH        = 165 // { int sys_sysarch(int op, void *parms); }
+	SYS_PREAD          = 173 // { ssize_t sys_pread(int fd, void *buf, \
+	SYS_PWRITE         = 174 // { ssize_t sys_pwrite(int fd, const void *buf, \
+	SYS_SETGID         = 181 // { int sys_setgid(gid_t gid); }
+	SYS_SETEGID        = 182 // { int sys_setegid(gid_t egid); }
+	SYS_SETEUID        = 183 // { int sys_seteuid(uid_t euid); }
+	SYS_PATHCONF       = 191 // { long sys_pathconf(const char *path, int name); }
+	SYS_FPATHCONF      = 192 // { long sys_fpathconf(int fd, int name); }
+	SYS_SWAPCTL        = 193 // { int sys_swapctl(int cmd, const void *arg, int misc); }
+	SYS_GETRLIMIT      = 194 // { int sys_getrlimit(int which, \
+	SYS_SETRLIMIT      = 195 // { int sys_setrlimit(int which, \
+	SYS_MMAP           = 197 // { void *sys_mmap(void *addr, size_t len, int prot, \
+	SYS_LSEEK          = 199 // { off_t sys_lseek(int fd, int pad, off_t offset, \
+	SYS_TRUNCATE       = 200 // { int sys_truncate(const char *path, int pad, \
+	SYS_FTRUNCATE      = 201 // { int sys_ftruncate(int fd, int pad, off_t length); }
+	SYS___SYSCTL       = 202 // { int sys___sysctl(const int *name, u_int namelen, \
+	SYS_MLOCK          = 203 // { int sys_mlock(const void *addr, size_t len); }
+	SYS_MUNLOCK        = 204 // { int sys_munlock(const void *addr, size_t len); }
+	SYS_GETPGID        = 207 // { pid_t sys_getpgid(pid_t pid); }
+	SYS_UTRACE         = 209 // { int sys_utrace(const char *label, const void *addr, \
+	SYS_SEMGET         = 221 // { int sys_semget(key_t key, int nsems, int semflg); }
+	SYS_MSGGET         = 225 // { int sys_msgget(key_t key, int msgflg); }
+	SYS_MSGSND         = 226 // { int sys_msgsnd(int msqid, const void *msgp, size_t msgsz, \
+	SYS_MSGRCV         = 227 // { int sys_msgrcv(int msqid, void *msgp, size_t msgsz, \
+	SYS_SHMAT          = 228 // { void *sys_shmat(int shmid, const void *shmaddr, \
+	SYS_SHMDT          = 230 // { int sys_shmdt(const void *shmaddr); }
+	SYS_MINHERIT       = 250 // { int sys_minherit(void *addr, size_t len, \
+	SYS_POLL           = 252 // { int sys_poll(struct pollfd *fds, \
+	SYS_ISSETUGID      = 253 // { int sys_issetugid(void); }
+	SYS_LCHOWN         = 254 // { int sys_lchown(const char *path, uid_t uid, gid_t gid); }
+	SYS_GETSID         = 255 // { pid_t sys_getsid(pid_t pid); }
+	SYS_MSYNC          = 256 // { int sys_msync(void *addr, size_t len, int flags); }
+	SYS_PIPE           = 263 // { int sys_pipe(int *fdp); }
+	SYS_FHOPEN         = 264 // { int sys_fhopen(const fhandle_t *fhp, int flags); }
+	SYS_PREADV         = 267 // { ssize_t sys_preadv(int fd, \
+	SYS_PWRITEV        = 268 // { ssize_t sys_pwritev(int fd, \
+	SYS_KQUEUE         = 269 // { int sys_kqueue(void); }
+	SYS_MLOCKALL       = 271 // { int sys_mlockall(int flags); }
+	SYS_MUNLOCKALL     = 272 // { int sys_munlockall(void); }
+	SYS_GETRESUID      = 281 // { int sys_getresuid(uid_t *ruid, uid_t *euid, \
+	SYS_SETRESUID      = 282 // { int sys_setresuid(uid_t ruid, uid_t euid, \
+	SYS_GETRESGID      = 283 // { int sys_getresgid(gid_t *rgid, gid_t *egid, \
+	SYS_SETRESGID      = 284 // { int sys_setresgid(gid_t rgid, gid_t egid, \
+	SYS_MQUERY         = 286 // { void *sys_mquery(void *addr, size_t len, int prot, \
+	SYS_CLOSEFROM      = 287 // { int sys_closefrom(int fd); }
+	SYS_SIGALTSTACK    = 288 // { int sys_sigaltstack(const struct sigaltstack *nss, \
+	SYS_SHMGET         = 289 // { int sys_shmget(key_t key, size_t size, int shmflg); }
+	SYS_SEMOP          = 290 // { int sys_semop(int semid, struct sembuf *sops, \
+	SYS_FHSTAT         = 294 // { int sys_fhstat(const fhandle_t *fhp, \
+	SYS___SEMCTL       = 295 // { int sys___semctl(int semid, int semnum, int cmd, \
+	SYS_SHMCTL         = 296 // { int sys_shmctl(int shmid, int cmd, \
+	SYS_MSGCTL         = 297 // { int sys_msgctl(int msqid, int cmd, \
+	SYS_SCHED_YIELD    = 298 // { int sys_sched_yield(void); }
+	SYS_GETTHRID       = 299 // { pid_t sys_getthrid(void); }
+	SYS___THRWAKEUP    = 301 // { int sys___thrwakeup(const volatile void *ident, \
+	SYS___THREXIT      = 302 // { void sys___threxit(pid_t *notdead); }
+	SYS___THRSIGDIVERT = 303 // { int sys___thrsigdivert(sigset_t sigmask, \
+	SYS___GETCWD       = 304 // { int sys___getcwd(char *buf, size_t len); }
+	SYS_ADJFREQ        = 305 // { int sys_adjfreq(const int64_t *freq, \
+	SYS_SETRTABLE      = 310 // { int sys_setrtable(int rtableid); }
+	SYS_GETRTABLE      = 311 // { int sys_getrtable(void); }
+	SYS_FACCESSAT      = 313 // { int sys_faccessat(int fd, const char *path, \
+	SYS_FCHMODAT       = 314 // { int sys_fchmodat(int fd, const char *path, \
+	SYS_FCHOWNAT       = 315 // { int sys_fchownat(int fd, const char *path, \
+	SYS_LINKAT         = 317 // { int sys_linkat(int fd1, const char *path1, int fd2, \
+	SYS_MKDIRAT        = 318 // { int sys_mkdirat(int fd, const char *path, \
+	SYS_MKFIFOAT       = 319 // { int sys_mkfifoat(int fd, const char *path, \
+	SYS_MKNODAT        = 320 // { int sys_mknodat(int fd, const char *path, \
+	SYS_OPENAT         = 321 // { int sys_openat(int fd, const char *path, int flags, \
+	SYS_READLINKAT     = 322 // { ssize_t sys_readlinkat(int fd, const char *path, \
+	SYS_RENAMEAT       = 323 // { int sys_renameat(int fromfd, const char *from, \
+	SYS_SYMLINKAT      = 324 // { int sys_symlinkat(const char *path, int fd, \
+	SYS_UNLINKAT       = 325 // { int sys_unlinkat(int fd, const char *path, \
+	SYS___SET_TCB      = 329 // { void sys___set_tcb(void *tcb); }
+	SYS___GET_TCB      = 330 // { void *sys___get_tcb(void); }
+)
diff --git a/src/syscall/ztypes_dragonfly_386.go b/src/syscall/ztypes_dragonfly_386.go
deleted file mode 100644
index 6b6ec15..0000000
--- a/src/syscall/ztypes_dragonfly_386.go
+++ /dev/null
@@ -1,435 +0,0 @@
-// Created by cgo -godefs - DO NOT EDIT
-// cgo -godefs types_dragonfly.go
-
-package syscall
-
-const (
-	sizeofPtr      = 0x4
-	sizeofShort    = 0x2
-	sizeofInt      = 0x4
-	sizeofLong     = 0x4
-	sizeofLongLong = 0x8
-)
-
-type (
-	_C_short     int16
-	_C_int       int32
-	_C_long      int32
-	_C_long_long int64
-)
-
-type Timespec struct {
-	Sec  int32
-	Nsec int32
-}
-
-type Timeval struct {
-	Sec  int32
-	Usec int32
-}
-
-type Rusage struct {
-	Utime    Timeval
-	Stime    Timeval
-	Maxrss   int32
-	Ixrss    int32
-	Idrss    int32
-	Isrss    int32
-	Minflt   int32
-	Majflt   int32
-	Nswap    int32
-	Inblock  int32
-	Oublock  int32
-	Msgsnd   int32
-	Msgrcv   int32
-	Nsignals int32
-	Nvcsw    int32
-	Nivcsw   int32
-}
-
-type Rlimit struct {
-	Cur int64
-	Max int64
-}
-
-type _Gid_t uint32
-
-const (
-	S_IFMT   = 0xf000
-	S_IFIFO  = 0x1000
-	S_IFCHR  = 0x2000
-	S_IFDIR  = 0x4000
-	S_IFBLK  = 0x6000
-	S_IFREG  = 0x8000
-	S_IFLNK  = 0xa000
-	S_IFSOCK = 0xc000
-	S_ISUID  = 0x800
-	S_ISGID  = 0x400
-	S_ISVTX  = 0x200
-	S_IRUSR  = 0x100
-	S_IWUSR  = 0x80
-	S_IXUSR  = 0x40
-)
-
-type Stat_t struct {
-	Ino      uint64
-	Nlink    uint32
-	Dev      uint32
-	Mode     uint16
-	Padding1 uint16
-	Uid      uint32
-	Gid      uint32
-	Rdev     uint32
-	Atim     Timespec
-	Mtim     Timespec
-	Ctim     Timespec
-	Size     int64
-	Blocks   int64
-	Blksize  uint32
-	Flags    uint32
-	Gen      uint32
-	Lspare   int32
-	Qspare1  int64
-	Qspare2  int64
-}
-
-type Statfs_t struct {
-	Spare2      int32
-	Bsize       int32
-	Iosize      int32
-	Blocks      int32
-	Bfree       int32
-	Bavail      int32
-	Files       int32
-	Ffree       int32
-	Fsid        Fsid
-	Owner       uint32
-	Type        int32
-	Flags       int32
-	Syncwrites  int32
-	Asyncwrites int32
-	Fstypename  [16]int8
-	Mntonname   [80]int8
-	Syncreads   int32
-	Asyncreads  int32
-	Spares1     int16
-	Mntfromname [80]int8
-	Spares2     int16
-	Spare       [2]int32
-}
-
-type Flock_t struct {
-	Start  int64
-	Len    int64
-	Pid    int32
-	Type   int16
-	Whence int16
-}
-
-type Dirent struct {
-	Fileno  uint64
-	Namlen  uint16
-	Type    uint8
-	Unused1 uint8
-	Unused2 uint32
-	Name    [256]int8
-}
-
-type Fsid struct {
-	Val [2]int32
-}
-
-type RawSockaddrInet4 struct {
-	Len    uint8
-	Family uint8
-	Port   uint16
-	Addr   [4]byte /* in_addr */
-	Zero   [8]int8
-}
-
-type RawSockaddrInet6 struct {
-	Len      uint8
-	Family   uint8
-	Port     uint16
-	Flowinfo uint32
-	Addr     [16]byte /* in6_addr */
-	Scope_id uint32
-}
-
-type RawSockaddrUnix struct {
-	Len    uint8
-	Family uint8
-	Path   [104]int8
-}
-
-type RawSockaddrDatalink struct {
-	Len    uint8
-	Family uint8
-	Index  uint16
-	Type   uint8
-	Nlen   uint8
-	Alen   uint8
-	Slen   uint8
-	Data   [12]int8
-	Rcf    uint16
-	Route  [16]uint16
-}
-
-type RawSockaddr struct {
-	Len    uint8
-	Family uint8
-	Data   [14]int8
-}
-
-type RawSockaddrAny struct {
-	Addr RawSockaddr
-	Pad  [92]int8
-}
-
-type _Socklen uint32
-
-type Linger struct {
-	Onoff  int32
-	Linger int32
-}
-
-type Iovec struct {
-	Base *byte
-	Len  uint32
-}
-
-type IPMreq struct {
-	Multiaddr [4]byte /* in_addr */
-	Interface [4]byte /* in_addr */
-}
-
-type IPv6Mreq struct {
-	Multiaddr [16]byte /* in6_addr */
-	Interface uint32
-}
-
-type Msghdr struct {
-	Name       *byte
-	Namelen    uint32
-	Iov        *Iovec
-	Iovlen     int32
-	Control    *byte
-	Controllen uint32
-	Flags      int32
-}
-
-type Cmsghdr struct {
-	Len   uint32
-	Level int32
-	Type  int32
-}
-
-type Inet6Pktinfo struct {
-	Addr    [16]byte /* in6_addr */
-	Ifindex uint32
-}
-
-type IPv6MTUInfo struct {
-	Addr RawSockaddrInet6
-	Mtu  uint32
-}
-
-type ICMPv6Filter struct {
-	Filt [8]uint32
-}
-
-const (
-	SizeofSockaddrInet4    = 0x10
-	SizeofSockaddrInet6    = 0x1c
-	SizeofSockaddrAny      = 0x6c
-	SizeofSockaddrUnix     = 0x6a
-	SizeofSockaddrDatalink = 0x36
-	SizeofLinger           = 0x8
-	SizeofIPMreq           = 0x8
-	SizeofIPv6Mreq         = 0x14
-	SizeofMsghdr           = 0x1c
-	SizeofCmsghdr          = 0xc
-	SizeofInet6Pktinfo     = 0x14
-	SizeofIPv6MTUInfo      = 0x20
-	SizeofICMPv6Filter     = 0x20
-)
-
-const (
-	PTRACE_TRACEME = 0x0
-	PTRACE_CONT    = 0x7
-	PTRACE_KILL    = 0x8
-)
-
-type Kevent_t struct {
-	Ident  uint32
-	Filter int16
-	Flags  uint16
-	Fflags uint32
-	Data   int32
-	Udata  *byte
-}
-
-type FdSet struct {
-	Bits [32]uint32
-}
-
-const (
-	SizeofIfMsghdr         = 0x68
-	SizeofIfData           = 0x58
-	SizeofIfaMsghdr        = 0x14
-	SizeofIfmaMsghdr       = 0x10
-	SizeofIfAnnounceMsghdr = 0x18
-	SizeofRtMsghdr         = 0x5c
-	SizeofRtMetrics        = 0x38
-)
-
-type IfMsghdr struct {
-	Msglen    uint16
-	Version   uint8
-	Type      uint8
-	Addrs     int32
-	Flags     int32
-	Index     uint16
-	Pad_cgo_0 [2]byte
-	Data      IfData
-}
-
-type IfData struct {
-	Type       uint8
-	Physical   uint8
-	Addrlen    uint8
-	Hdrlen     uint8
-	Recvquota  uint8
-	Xmitquota  uint8
-	Pad_cgo_0  [2]byte
-	Mtu        uint32
-	Metric     uint32
-	Link_state uint32
-	Baudrate   uint64
-	Ipackets   uint32
-	Ierrors    uint32
-	Opackets   uint32
-	Oerrors    uint32
-	Collisions uint32
-	Ibytes     uint32
-	Obytes     uint32
-	Imcasts    uint32
-	Omcasts    uint32
-	Iqdrops    uint32
-	Noproto    uint32
-	Hwassist   uint32
-	Unused     uint32
-	Lastchange Timeval
-}
-
-type IfaMsghdr struct {
-	Msglen    uint16
-	Version   uint8
-	Type      uint8
-	Addrs     int32
-	Flags     int32
-	Index     uint16
-	Pad_cgo_0 [2]byte
-	Metric    int32
-}
-
-type IfmaMsghdr struct {
-	Msglen    uint16
-	Version   uint8
-	Type      uint8
-	Addrs     int32
-	Flags     int32
-	Index     uint16
-	Pad_cgo_0 [2]byte
-}
-
-type IfAnnounceMsghdr struct {
-	Msglen  uint16
-	Version uint8
-	Type    uint8
-	Index   uint16
-	Name    [16]int8
-	What    uint16
-}
-
-type RtMsghdr struct {
-	Msglen    uint16
-	Version   uint8
-	Type      uint8
-	Index     uint16
-	Pad_cgo_0 [2]byte
-	Flags     int32
-	Addrs     int32
-	Pid       int32
-	Seq       int32
-	Errno     int32
-	Use       int32
-	Inits     uint32
-	Rmx       RtMetrics
-}
-
-type RtMetrics struct {
-	Locks     uint32
-	Mtu       uint32
-	Pksent    uint32
-	Expire    uint32
-	Sendpipe  uint32
-	Ssthresh  uint32
-	Rtt       uint32
-	Rttvar    uint32
-	Recvpipe  uint32
-	Hopcount  uint32
-	Mssopt    uint16
-	Pad       uint16
-	Msl       uint32
-	Iwmaxsegs uint32
-	Iwcapsegs uint32
-}
-
-const (
-	SizeofBpfVersion = 0x4
-	SizeofBpfStat    = 0x8
-	SizeofBpfProgram = 0x8
-	SizeofBpfInsn    = 0x8
-	SizeofBpfHdr     = 0x14
-)
-
-type BpfVersion struct {
-	Major uint16
-	Minor uint16
-}
-
-type BpfStat struct {
-	Recv uint32
-	Drop uint32
-}
-
-type BpfProgram struct {
-	Len   uint32
-	Insns *BpfInsn
-}
-
-type BpfInsn struct {
-	Code uint16
-	Jt   uint8
-	Jf   uint8
-	K    uint32
-}
-
-type BpfHdr struct {
-	Tstamp    Timeval
-	Caplen    uint32
-	Datalen   uint32
-	Hdrlen    uint16
-	Pad_cgo_0 [2]byte
-}
-
-type Termios struct {
-	Iflag  uint32
-	Oflag  uint32
-	Cflag  uint32
-	Lflag  uint32
-	Cc     [20]uint8
-	Ispeed uint32
-	Ospeed uint32
-}
diff --git a/src/syscall/ztypes_linux_arm64.go b/src/syscall/ztypes_linux_arm64.go
new file mode 100644
index 0000000..1cb1d43
--- /dev/null
+++ b/src/syscall/ztypes_linux_arm64.go
@@ -0,0 +1,594 @@
+// Created by cgo -godefs - DO NOT EDIT
+// cgo -godefs -- -fsigned-char types_linux.go
+
+package syscall
+
+const (
+	sizeofPtr      = 0x8
+	sizeofShort    = 0x2
+	sizeofInt      = 0x4
+	sizeofLong     = 0x8
+	sizeofLongLong = 0x8
+	PathMax        = 0x1000
+)
+
+type (
+	_C_short     int16
+	_C_int       int32
+	_C_long      int64
+	_C_long_long int64
+)
+
+type Timespec struct {
+	Sec  int64
+	Nsec int64
+}
+
+type Timeval struct {
+	Sec  int64
+	Usec int64
+}
+
+type Timex struct {
+	Modes     uint32
+	Pad_cgo_0 [4]byte
+	Offset    int64
+	Freq      int64
+	Maxerror  int64
+	Esterror  int64
+	Status    int32
+	Pad_cgo_1 [4]byte
+	Constant  int64
+	Precision int64
+	Tolerance int64
+	Time      Timeval
+	Tick      int64
+	Ppsfreq   int64
+	Jitter    int64
+	Shift     int32
+	Pad_cgo_2 [4]byte
+	Stabil    int64
+	Jitcnt    int64
+	Calcnt    int64
+	Errcnt    int64
+	Stbcnt    int64
+	Tai       int32
+	Pad_cgo_3 [44]byte
+}
+
+type Time_t int64
+
+type Tms struct {
+	Utime  int64
+	Stime  int64
+	Cutime int64
+	Cstime int64
+}
+
+type Utimbuf struct {
+	Actime  int64
+	Modtime int64
+}
+
+type Rusage struct {
+	Utime    Timeval
+	Stime    Timeval
+	Maxrss   int64
+	Ixrss    int64
+	Idrss    int64
+	Isrss    int64
+	Minflt   int64
+	Majflt   int64
+	Nswap    int64
+	Inblock  int64
+	Oublock  int64
+	Msgsnd   int64
+	Msgrcv   int64
+	Nsignals int64
+	Nvcsw    int64
+	Nivcsw   int64
+}
+
+type Rlimit struct {
+	Cur uint64
+	Max uint64
+}
+
+type _Gid_t uint32
+
+type Stat_t struct {
+	Dev               uint64
+	Ino               uint64
+	Mode              uint32
+	Nlink             uint32
+	Uid               uint32
+	Gid               uint32
+	Rdev              uint64
+	X__pad1           uint64
+	Size              int64
+	Blksize           int32
+	X__pad2           int32
+	Blocks            int64
+	Atim              Timespec
+	Mtim              Timespec
+	Ctim              Timespec
+	X__glibc_reserved [2]int32
+}
+
+type Statfs_t struct {
+	Type    int64
+	Bsize   int64
+	Blocks  uint64
+	Bfree   uint64
+	Bavail  uint64
+	Files   uint64
+	Ffree   uint64
+	Fsid    Fsid
+	Namelen int64
+	Frsize  int64
+	Flags   int64
+	Spare   [4]int64
+}
+
+type Dirent struct {
+	Ino       uint64
+	Off       int64
+	Reclen    uint16
+	Type      uint8
+	Name      [256]int8
+	Pad_cgo_0 [5]byte
+}
+
+type Fsid struct {
+	X__val [2]int32
+}
+
+type Flock_t struct {
+	Type      int16
+	Whence    int16
+	Pad_cgo_0 [4]byte
+	Start     int64
+	Len       int64
+	Pid       int32
+	Pad_cgo_1 [4]byte
+}
+
+type RawSockaddrInet4 struct {
+	Family uint16
+	Port   uint16
+	Addr   [4]byte /* in_addr */
+	Zero   [8]uint8
+}
+
+type RawSockaddrInet6 struct {
+	Family   uint16
+	Port     uint16
+	Flowinfo uint32
+	Addr     [16]byte /* in6_addr */
+	Scope_id uint32
+}
+
+type RawSockaddrUnix struct {
+	Family uint16
+	Path   [108]int8
+}
+
+type RawSockaddrLinklayer struct {
+	Family   uint16
+	Protocol uint16
+	Ifindex  int32
+	Hatype   uint16
+	Pkttype  uint8
+	Halen    uint8
+	Addr     [8]uint8
+}
+
+type RawSockaddrNetlink struct {
+	Family uint16
+	Pad    uint16
+	Pid    uint32
+	Groups uint32
+}
+
+type RawSockaddr struct {
+	Family uint16
+	Data   [14]int8
+}
+
+type RawSockaddrAny struct {
+	Addr RawSockaddr
+	Pad  [96]int8
+}
+
+type _Socklen uint32
+
+type Linger struct {
+	Onoff  int32
+	Linger int32
+}
+
+type Iovec struct {
+	Base *byte
+	Len  uint64
+}
+
+type IPMreq struct {
+	Multiaddr [4]byte /* in_addr */
+	Interface [4]byte /* in_addr */
+}
+
+type IPMreqn struct {
+	Multiaddr [4]byte /* in_addr */
+	Address   [4]byte /* in_addr */
+	Ifindex   int32
+}
+
+type IPv6Mreq struct {
+	Multiaddr [16]byte /* in6_addr */
+	Interface uint32
+}
+
+type Msghdr struct {
+	Name       *byte
+	Namelen    uint32
+	Pad_cgo_0  [4]byte
+	Iov        *Iovec
+	Iovlen     uint64
+	Control    *byte
+	Controllen uint64
+	Flags      int32
+	Pad_cgo_1  [4]byte
+}
+
+type Cmsghdr struct {
+	Len          uint64
+	Level        int32
+	Type         int32
+	X__cmsg_data [0]uint8
+}
+
+type Inet4Pktinfo struct {
+	Ifindex  int32
+	Spec_dst [4]byte /* in_addr */
+	Addr     [4]byte /* in_addr */
+}
+
+type Inet6Pktinfo struct {
+	Addr    [16]byte /* in6_addr */
+	Ifindex uint32
+}
+
+type IPv6MTUInfo struct {
+	Addr RawSockaddrInet6
+	Mtu  uint32
+}
+
+type ICMPv6Filter struct {
+	Data [8]uint32
+}
+
+type Ucred struct {
+	Pid int32
+	Uid uint32
+	Gid uint32
+}
+
+type TCPInfo struct {
+	State          uint8
+	Ca_state       uint8
+	Retransmits    uint8
+	Probes         uint8
+	Backoff        uint8
+	Options        uint8
+	Pad_cgo_0      [2]byte
+	Rto            uint32
+	Ato            uint32
+	Snd_mss        uint32
+	Rcv_mss        uint32
+	Unacked        uint32
+	Sacked         uint32
+	Lost           uint32
+	Retrans        uint32
+	Fackets        uint32
+	Last_data_sent uint32
+	Last_ack_sent  uint32
+	Last_data_recv uint32
+	Last_ack_recv  uint32
+	Pmtu           uint32
+	Rcv_ssthresh   uint32
+	Rtt            uint32
+	Rttvar         uint32
+	Snd_ssthresh   uint32
+	Snd_cwnd       uint32
+	Advmss         uint32
+	Reordering     uint32
+	Rcv_rtt        uint32
+	Rcv_space      uint32
+	Total_retrans  uint32
+}
+
+const (
+	SizeofSockaddrInet4     = 0x10
+	SizeofSockaddrInet6     = 0x1c
+	SizeofSockaddrAny       = 0x70
+	SizeofSockaddrUnix      = 0x6e
+	SizeofSockaddrLinklayer = 0x14
+	SizeofSockaddrNetlink   = 0xc
+	SizeofLinger            = 0x8
+	SizeofIPMreq            = 0x8
+	SizeofIPMreqn           = 0xc
+	SizeofIPv6Mreq          = 0x14
+	SizeofMsghdr            = 0x38
+	SizeofCmsghdr           = 0x10
+	SizeofInet4Pktinfo      = 0xc
+	SizeofInet6Pktinfo      = 0x14
+	SizeofIPv6MTUInfo       = 0x20
+	SizeofICMPv6Filter      = 0x20
+	SizeofUcred             = 0xc
+	SizeofTCPInfo           = 0x68
+)
+
+const (
+	IFA_UNSPEC          = 0x0
+	IFA_ADDRESS         = 0x1
+	IFA_LOCAL           = 0x2
+	IFA_LABEL           = 0x3
+	IFA_BROADCAST       = 0x4
+	IFA_ANYCAST         = 0x5
+	IFA_CACHEINFO       = 0x6
+	IFA_MULTICAST       = 0x7
+	IFLA_UNSPEC         = 0x0
+	IFLA_ADDRESS        = 0x1
+	IFLA_BROADCAST      = 0x2
+	IFLA_IFNAME         = 0x3
+	IFLA_MTU            = 0x4
+	IFLA_LINK           = 0x5
+	IFLA_QDISC          = 0x6
+	IFLA_STATS          = 0x7
+	IFLA_COST           = 0x8
+	IFLA_PRIORITY       = 0x9
+	IFLA_MASTER         = 0xa
+	IFLA_WIRELESS       = 0xb
+	IFLA_PROTINFO       = 0xc
+	IFLA_TXQLEN         = 0xd
+	IFLA_MAP            = 0xe
+	IFLA_WEIGHT         = 0xf
+	IFLA_OPERSTATE      = 0x10
+	IFLA_LINKMODE       = 0x11
+	IFLA_LINKINFO       = 0x12
+	IFLA_NET_NS_PID     = 0x13
+	IFLA_IFALIAS        = 0x14
+	IFLA_MAX            = 0x24
+	RT_SCOPE_UNIVERSE   = 0x0
+	RT_SCOPE_SITE       = 0xc8
+	RT_SCOPE_LINK       = 0xfd
+	RT_SCOPE_HOST       = 0xfe
+	RT_SCOPE_NOWHERE    = 0xff
+	RT_TABLE_UNSPEC     = 0x0
+	RT_TABLE_COMPAT     = 0xfc
+	RT_TABLE_DEFAULT    = 0xfd
+	RT_TABLE_MAIN       = 0xfe
+	RT_TABLE_LOCAL      = 0xff
+	RT_TABLE_MAX        = 0xffffffff
+	RTA_UNSPEC          = 0x0
+	RTA_DST             = 0x1
+	RTA_SRC             = 0x2
+	RTA_IIF             = 0x3
+	RTA_OIF             = 0x4
+	RTA_GATEWAY         = 0x5
+	RTA_PRIORITY        = 0x6
+	RTA_PREFSRC         = 0x7
+	RTA_METRICS         = 0x8
+	RTA_MULTIPATH       = 0x9
+	RTA_FLOW            = 0xb
+	RTA_CACHEINFO       = 0xc
+	RTA_TABLE           = 0xf
+	RTN_UNSPEC          = 0x0
+	RTN_UNICAST         = 0x1
+	RTN_LOCAL           = 0x2
+	RTN_BROADCAST       = 0x3
+	RTN_ANYCAST         = 0x4
+	RTN_MULTICAST       = 0x5
+	RTN_BLACKHOLE       = 0x6
+	RTN_UNREACHABLE     = 0x7
+	RTN_PROHIBIT        = 0x8
+	RTN_THROW           = 0x9
+	RTN_NAT             = 0xa
+	RTN_XRESOLVE        = 0xb
+	RTNLGRP_NONE        = 0x0
+	RTNLGRP_LINK        = 0x1
+	RTNLGRP_NOTIFY      = 0x2
+	RTNLGRP_NEIGH       = 0x3
+	RTNLGRP_TC          = 0x4
+	RTNLGRP_IPV4_IFADDR = 0x5
+	RTNLGRP_IPV4_MROUTE = 0x6
+	RTNLGRP_IPV4_ROUTE  = 0x7
+	RTNLGRP_IPV4_RULE   = 0x8
+	RTNLGRP_IPV6_IFADDR = 0x9
+	RTNLGRP_IPV6_MROUTE = 0xa
+	RTNLGRP_IPV6_ROUTE  = 0xb
+	RTNLGRP_IPV6_IFINFO = 0xc
+	RTNLGRP_IPV6_PREFIX = 0x12
+	RTNLGRP_IPV6_RULE   = 0x13
+	RTNLGRP_ND_USEROPT  = 0x14
+	SizeofNlMsghdr      = 0x10
+	SizeofNlMsgerr      = 0x14
+	SizeofRtGenmsg      = 0x1
+	SizeofNlAttr        = 0x4
+	SizeofRtAttr        = 0x4
+	SizeofIfInfomsg     = 0x10
+	SizeofIfAddrmsg     = 0x8
+	SizeofRtMsg         = 0xc
+	SizeofRtNexthop     = 0x8
+)
+
+type NlMsghdr struct {
+	Len   uint32
+	Type  uint16
+	Flags uint16
+	Seq   uint32
+	Pid   uint32
+}
+
+type NlMsgerr struct {
+	Error int32
+	Msg   NlMsghdr
+}
+
+type RtGenmsg struct {
+	Family uint8
+}
+
+type NlAttr struct {
+	Len  uint16
+	Type uint16
+}
+
+type RtAttr struct {
+	Len  uint16
+	Type uint16
+}
+
+type IfInfomsg struct {
+	Family     uint8
+	X__ifi_pad uint8
+	Type       uint16
+	Index      int32
+	Flags      uint32
+	Change     uint32
+}
+
+type IfAddrmsg struct {
+	Family    uint8
+	Prefixlen uint8
+	Flags     uint8
+	Scope     uint8
+	Index     uint32
+}
+
+type RtMsg struct {
+	Family   uint8
+	Dst_len  uint8
+	Src_len  uint8
+	Tos      uint8
+	Table    uint8
+	Protocol uint8
+	Scope    uint8
+	Type     uint8
+	Flags    uint32
+}
+
+type RtNexthop struct {
+	Len     uint16
+	Flags   uint8
+	Hops    uint8
+	Ifindex int32
+}
+
+const (
+	SizeofSockFilter = 0x8
+	SizeofSockFprog  = 0x10
+)
+
+type SockFilter struct {
+	Code uint16
+	Jt   uint8
+	Jf   uint8
+	K    uint32
+}
+
+type SockFprog struct {
+	Len       uint16
+	Pad_cgo_0 [6]byte
+	Filter    *SockFilter
+}
+
+type InotifyEvent struct {
+	Wd     int32
+	Mask   uint32
+	Cookie uint32
+	Len    uint32
+	Name   [0]int8
+}
+
+const SizeofInotifyEvent = 0x10
+
+type PtraceRegs struct {
+	Regs   [31]uint64
+	Sp     uint64
+	Pc     uint64
+	Pstate uint64
+}
+
+type FdSet struct {
+	Bits [16]int64
+}
+
+type Sysinfo_t struct {
+	Uptime    int64
+	Loads     [3]uint64
+	Totalram  uint64
+	Freeram   uint64
+	Sharedram uint64
+	Bufferram uint64
+	Totalswap uint64
+	Freeswap  uint64
+	Procs     uint16
+	Pad       uint16
+	Pad_cgo_0 [4]byte
+	Totalhigh uint64
+	Freehigh  uint64
+	Unit      uint32
+	X_f       [0]int8
+	Pad_cgo_1 [4]byte
+}
+
+type Utsname struct {
+	Sysname    [65]int8
+	Nodename   [65]int8
+	Release    [65]int8
+	Version    [65]int8
+	Machine    [65]int8
+	Domainname [65]int8
+}
+
+type Ustat_t struct {
+	Tfree     int32
+	Pad_cgo_0 [4]byte
+	Tinode    uint64
+	Fname     [6]int8
+	Fpack     [6]int8
+	Pad_cgo_1 [4]byte
+}
+
+type EpollEvent struct {
+	Events uint32
+	Fd     int32
+	Pad    int32
+}
+
+const (
+	_AT_FDCWD            = -0x64
+	_AT_REMOVEDIR        = 0x200
+	_AT_SYMLINK_NOFOLLOW = 0x100
+)
+
+type Termios struct {
+	Iflag     uint32
+	Oflag     uint32
+	Cflag     uint32
+	Lflag     uint32
+	Line      uint8
+	Cc        [32]uint8
+	Pad_cgo_0 [3]byte
+	Ispeed    uint32
+	Ospeed    uint32
+}
+
+const (
+	IUCLC  = 0x200
+	OLCUC  = 0x2
+	TCGETS = 0x5401
+	TCSETS = 0x5402
+	XCASE  = 0x4
+)
diff --git a/src/syscall/ztypes_openbsd_arm.go b/src/syscall/ztypes_openbsd_arm.go
new file mode 100644
index 0000000..5f8fb12
--- /dev/null
+++ b/src/syscall/ztypes_openbsd_arm.go
@@ -0,0 +1,432 @@
+// Created by cgo -godefs - DO NOT EDIT
+// cgo -godefs types_openbsd.go
+
+package syscall
+
+const (
+	sizeofPtr      = 0x4
+	sizeofShort    = 0x2
+	sizeofInt      = 0x4
+	sizeofLong     = 0x4
+	sizeofLongLong = 0x8
+)
+
+type (
+	_C_short     int16
+	_C_int       int32
+	_C_long      int32
+	_C_long_long int64
+)
+
+type Timespec struct {
+	Sec  int64
+	Nsec int32
+}
+
+type Timeval struct {
+	Sec  int64
+	Usec int32
+}
+
+type Rusage struct {
+	Utime    Timeval
+	Stime    Timeval
+	Maxrss   int32
+	Ixrss    int32
+	Idrss    int32
+	Isrss    int32
+	Minflt   int32
+	Majflt   int32
+	Nswap    int32
+	Inblock  int32
+	Oublock  int32
+	Msgsnd   int32
+	Msgrcv   int32
+	Nsignals int32
+	Nvcsw    int32
+	Nivcsw   int32
+}
+
+type Rlimit struct {
+	Cur uint64
+	Max uint64
+}
+
+type _Gid_t uint32
+
+const (
+	S_IFMT   = 0xf000
+	S_IFIFO  = 0x1000
+	S_IFCHR  = 0x2000
+	S_IFDIR  = 0x4000
+	S_IFBLK  = 0x6000
+	S_IFREG  = 0x8000
+	S_IFLNK  = 0xa000
+	S_IFSOCK = 0xc000
+	S_ISUID  = 0x800
+	S_ISGID  = 0x400
+	S_ISVTX  = 0x200
+	S_IRUSR  = 0x100
+	S_IWUSR  = 0x80
+	S_IXUSR  = 0x40
+)
+
+type Stat_t struct {
+	Mode           uint32
+	Dev            int32
+	Ino            uint64
+	Nlink          uint32
+	Uid            uint32
+	Gid            uint32
+	Rdev           int32
+	Atim           Timespec
+	Mtim           Timespec
+	Ctim           Timespec
+	Size           int64
+	Blocks         int64
+	Blksize        int32
+	Flags          uint32
+	Gen            uint32
+	X__st_birthtim Timespec
+}
+
+type Statfs_t struct {
+	F_flags       uint32
+	F_bsize       uint32
+	F_iosize      uint32
+	F_blocks      uint64
+	F_bfree       uint64
+	F_bavail      int64
+	F_files       uint64
+	F_ffree       uint64
+	F_favail      int64
+	F_syncwrites  uint64
+	F_syncreads   uint64
+	F_asyncwrites uint64
+	F_asyncreads  uint64
+	F_fsid        Fsid
+	F_namemax     uint32
+	F_owner       uint32
+	F_ctime       uint64
+	F_fstypename  [16]uint8
+	F_mntonname   [90]uint8
+	F_mntfromname [90]uint8
+	F_mntfromspec [90]uint8
+	Pad_cgo_0     [2]byte
+	Mount_info    [160]byte
+}
+
+type Flock_t struct {
+	Start  int64
+	Len    int64
+	Pid    int32
+	Type   int16
+	Whence int16
+}
+
+type Dirent struct {
+	Fileno       uint64
+	Off          int64
+	Reclen       uint16
+	Type         uint8
+	Namlen       uint8
+	X__d_padding [4]uint8
+	Name         [256]uint8
+}
+
+type Fsid struct {
+	Val [2]int32
+}
+
+type RawSockaddrInet4 struct {
+	Len    uint8
+	Family uint8
+	Port   uint16
+	Addr   [4]byte /* in_addr */
+	Zero   [8]int8
+}
+
+type RawSockaddrInet6 struct {
+	Len      uint8
+	Family   uint8
+	Port     uint16
+	Flowinfo uint32
+	Addr     [16]byte /* in6_addr */
+	Scope_id uint32
+}
+
+type RawSockaddrUnix struct {
+	Len    uint8
+	Family uint8
+	Path   [104]int8
+}
+
+type RawSockaddrDatalink struct {
+	Len    uint8
+	Family uint8
+	Index  uint16
+	Type   uint8
+	Nlen   uint8
+	Alen   uint8
+	Slen   uint8
+	Data   [24]int8
+}
+
+type RawSockaddr struct {
+	Len    uint8
+	Family uint8
+	Data   [14]int8
+}
+
+type RawSockaddrAny struct {
+	Addr RawSockaddr
+	Pad  [92]int8
+}
+
+type _Socklen uint32
+
+type Linger struct {
+	Onoff  int32
+	Linger int32
+}
+
+type Iovec struct {
+	Base *byte
+	Len  uint32
+}
+
+type IPMreq struct {
+	Multiaddr [4]byte /* in_addr */
+	Interface [4]byte /* in_addr */
+}
+
+type IPv6Mreq struct {
+	Multiaddr [16]byte /* in6_addr */
+	Interface uint32
+}
+
+type Msghdr struct {
+	Name       *byte
+	Namelen    uint32
+	Iov        *Iovec
+	Iovlen     uint32
+	Control    *byte
+	Controllen uint32
+	Flags      int32
+}
+
+type Cmsghdr struct {
+	Len   uint32
+	Level int32
+	Type  int32
+}
+
+type Inet6Pktinfo struct {
+	Addr    [16]byte /* in6_addr */
+	Ifindex uint32
+}
+
+type IPv6MTUInfo struct {
+	Addr RawSockaddrInet6
+	Mtu  uint32
+}
+
+type ICMPv6Filter struct {
+	Filt [8]uint32
+}
+
+const (
+	SizeofSockaddrInet4    = 0x10
+	SizeofSockaddrInet6    = 0x1c
+	SizeofSockaddrAny      = 0x6c
+	SizeofSockaddrUnix     = 0x6a
+	SizeofSockaddrDatalink = 0x20
+	SizeofLinger           = 0x8
+	SizeofIPMreq           = 0x8
+	SizeofIPv6Mreq         = 0x14
+	SizeofMsghdr           = 0x1c
+	SizeofCmsghdr          = 0xc
+	SizeofInet6Pktinfo     = 0x14
+	SizeofIPv6MTUInfo      = 0x20
+	SizeofICMPv6Filter     = 0x20
+)
+
+const (
+	PTRACE_TRACEME = 0x0
+	PTRACE_CONT    = 0x7
+	PTRACE_KILL    = 0x8
+)
+
+type Kevent_t struct {
+	Ident  uint32
+	Filter int16
+	Flags  uint16
+	Fflags uint32
+	Data   int64
+	Udata  *byte
+}
+
+type FdSet struct {
+	Bits [32]uint32
+}
+
+const (
+	SizeofIfMsghdr         = 0x98
+	SizeofIfData           = 0x80
+	SizeofIfaMsghdr        = 0x18
+	SizeofIfAnnounceMsghdr = 0x1a
+	SizeofRtMsghdr         = 0x60
+	SizeofRtMetrics        = 0x38
+)
+
+type IfMsghdr struct {
+	Msglen  uint16
+	Version uint8
+	Type    uint8
+	Hdrlen  uint16
+	Index   uint16
+	Tableid uint16
+	Pad1    uint8
+	Pad2    uint8
+	Addrs   int32
+	Flags   int32
+	Xflags  int32
+	Data    IfData
+}
+
+type IfData struct {
+	Type         uint8
+	Addrlen      uint8
+	Hdrlen       uint8
+	Link_state   uint8
+	Mtu          uint32
+	Metric       uint32
+	Pad          uint32
+	Baudrate     uint64
+	Ipackets     uint64
+	Ierrors      uint64
+	Opackets     uint64
+	Oerrors      uint64
+	Collisions   uint64
+	Ibytes       uint64
+	Obytes       uint64
+	Imcasts      uint64
+	Omcasts      uint64
+	Iqdrops      uint64
+	Noproto      uint64
+	Capabilities uint32
+	Lastchange   Timeval
+}
+
+type IfaMsghdr struct {
+	Msglen  uint16
+	Version uint8
+	Type    uint8
+	Hdrlen  uint16
+	Index   uint16
+	Tableid uint16
+	Pad1    uint8
+	Pad2    uint8
+	Addrs   int32
+	Flags   int32
+	Metric  int32
+}
+
+type IfAnnounceMsghdr struct {
+	Msglen  uint16
+	Version uint8
+	Type    uint8
+	Hdrlen  uint16
+	Index   uint16
+	What    uint16
+	Name    [16]uint8
+}
+
+type RtMsghdr struct {
+	Msglen   uint16
+	Version  uint8
+	Type     uint8
+	Hdrlen   uint16
+	Index    uint16
+	Tableid  uint16
+	Priority uint8
+	Mpls     uint8
+	Addrs    int32
+	Flags    int32
+	Fmask    int32
+	Pid      int32
+	Seq      int32
+	Errno    int32
+	Inits    uint32
+	Rmx      RtMetrics
+}
+
+type RtMetrics struct {
+	Pksent   uint64
+	Expire   int64
+	Locks    uint32
+	Mtu      uint32
+	Refcnt   uint32
+	Hopcount uint32
+	Recvpipe uint32
+	Sendpipe uint32
+	Ssthresh uint32
+	Rtt      uint32
+	Rttvar   uint32
+	Pad      uint32
+}
+
+type Mclpool struct{}
+
+const (
+	SizeofBpfVersion = 0x4
+	SizeofBpfStat    = 0x8
+	SizeofBpfProgram = 0x8
+	SizeofBpfInsn    = 0x8
+	SizeofBpfHdr     = 0x14
+)
+
+type BpfVersion struct {
+	Major uint16
+	Minor uint16
+}
+
+type BpfStat struct {
+	Recv uint32
+	Drop uint32
+}
+
+type BpfProgram struct {
+	Len   uint32
+	Insns *BpfInsn
+}
+
+type BpfInsn struct {
+	Code uint16
+	Jt   uint8
+	Jf   uint8
+	K    uint32
+}
+
+type BpfHdr struct {
+	Tstamp    BpfTimeval
+	Caplen    uint32
+	Datalen   uint32
+	Hdrlen    uint16
+	Pad_cgo_0 [2]byte
+}
+
+type BpfTimeval struct {
+	Sec  uint32
+	Usec uint32
+}
+
+type Termios struct {
+	Iflag  uint32
+	Oflag  uint32
+	Cflag  uint32
+	Lflag  uint32
+	Cc     [20]uint8
+	Ispeed int32
+	Ospeed int32
+}
diff --git a/src/testing/quick/quick.go b/src/testing/quick/quick.go
index edcaaa0..35b7b63 100644
--- a/src/testing/quick/quick.go
+++ b/src/testing/quick/quick.go
@@ -161,7 +161,7 @@
 	Rand *rand.Rand
 	// If non-nil, the Values function generates a slice of arbitrary
 	// reflect.Values that are congruent with the arguments to the function
-	// being tested. Otherwise, the top-level Values function is used
+	// being tested. Otherwise, the top-level Value function is used
 	// to generate them.
 	Values func([]reflect.Value, *rand.Rand)
 }
diff --git a/src/testing/testing.go b/src/testing/testing.go
index 966b546..5163123 100644
--- a/src/testing/testing.go
+++ b/src/testing/testing.go
@@ -130,13 +130,17 @@
 // then the generated test will call TestMain(m) instead of running the tests
 // directly. TestMain runs in the main goroutine and can do whatever setup
 // and teardown is necessary around a call to m.Run. It should then call
-// os.Exit with the result of m.Run.
+// os.Exit with the result of m.Run. When TestMain is called, flag.Parse has
+// not been run. If TestMain depends on command-line flags, including those
+// of the testing package, it should call flag.Parse explicitly.
 //
-// The minimal implementation of TestMain is:
+// A simple implementation of TestMain is:
 //
-//	func TestMain(m *testing.M) { os.Exit(m.Run()) }
+//	func TestMain(m *testing.M) {
+//		flag.Parse()
+//		os.Exit(m.Run())
+//	}
 //
-// In effect, that is the implementation used when no TestMain is explicitly defined.
 package testing
 
 import (
diff --git a/src/text/scanner/scanner.go b/src/text/scanner/scanner.go
index 5199ee4..d3eadfd 100644
--- a/src/text/scanner/scanner.go
+++ b/src/text/scanner/scanner.go
@@ -43,7 +43,7 @@
 	Column   int    // column number, starting at 1 (character count per line)
 }
 
-// IsValid returns true if the position is valid.
+// IsValid reports whether the position is valid.
 func (pos *Position) IsValid() bool { return pos.Line > 0 }
 
 func (pos Position) String() string {
@@ -208,7 +208,7 @@
 	s.tokPos = -1
 
 	// initialize one character look-ahead
-	s.ch = -1 // no char read yet
+	s.ch = -2 // no char read yet, not EOF
 
 	// initialize public fields
 	s.Error = nil
@@ -322,7 +322,7 @@
 // the scanner. It returns EOF if the scanner's position is at the last
 // character of the source.
 func (s *Scanner) Peek() rune {
-	if s.ch < 0 {
+	if s.ch == -2 {
 		// this code is only run for the very first character
 		s.ch = s.next()
 		if s.ch == '\uFEFF' {
diff --git a/src/text/scanner/scanner_test.go b/src/text/scanner/scanner_test.go
index 702fac2..aca17b1 100644
--- a/src/text/scanner/scanner_test.go
+++ b/src/text/scanner/scanner_test.go
@@ -616,3 +616,32 @@
 		t.Errorf("%d errors", s.ErrorCount)
 	}
 }
+
+type countReader int
+
+func (c *countReader) Read([]byte) (int, error) {
+	*c++
+
+	return 0, io.EOF
+}
+
+func TestPeekEOFHandling(t *testing.T) {
+	var r countReader
+
+	// corner case: empty source
+	s := new(Scanner).Init(&r)
+
+	tok := s.Next()
+	if tok != EOF {
+		t.Errorf("EOF not reported")
+	}
+
+	tok = s.Peek()
+	if tok != EOF {
+		t.Errorf("EOF not reported")
+	}
+
+	if r != 2 {
+		t.Errorf("scanner called Read %d times, not twice", r)
+	}
+}
diff --git a/src/text/template/exec.go b/src/text/template/exec.go
index b00e10c..613a778 100644
--- a/src/text/template/exec.go
+++ b/src/text/template/exec.go
@@ -136,26 +136,37 @@
 	}
 	t.init()
 	if t.Tree == nil || t.Root == nil {
-		var b bytes.Buffer
-		for name, tmpl := range t.tmpl {
-			if tmpl.Tree == nil || tmpl.Root == nil {
-				continue
-			}
-			if b.Len() > 0 {
-				b.WriteString(", ")
-			}
-			fmt.Fprintf(&b, "%q", name)
-		}
-		var s string
-		if b.Len() > 0 {
-			s = "; defined templates are: " + b.String()
-		}
-		state.errorf("%q is an incomplete or empty template%s", t.Name(), s)
+		state.errorf("%q is an incomplete or empty template%s", t.Name(), t.DefinedTemplates())
 	}
 	state.walk(value, t.Root)
 	return
 }
 
+// DefinedTemplates returns a string listing the defined templates,
+// prefixed by the string "defined templates are: ". If there are none,
+// it returns the empty string. For generating an error message here
+// and in html/template.
+func (t *Template) DefinedTemplates() string {
+	if t.common == nil {
+		return ""
+	}
+	var b bytes.Buffer
+	for name, tmpl := range t.tmpl {
+		if tmpl.Tree == nil || tmpl.Root == nil {
+			continue
+		}
+		if b.Len() > 0 {
+			b.WriteString(", ")
+		}
+		fmt.Fprintf(&b, "%q", name)
+	}
+	var s string
+	if b.Len() > 0 {
+		s = "; defined templates are: " + b.String()
+	}
+	return s
+}
+
 // Walk functions step through the major pieces of the template structure,
 // generating output as they go.
 func (s *state) walk(dot reflect.Value, node parse.Node) {
@@ -418,11 +429,14 @@
 
 func (s *state) evalChainNode(dot reflect.Value, chain *parse.ChainNode, args []parse.Node, final reflect.Value) reflect.Value {
 	s.at(chain)
-	// (pipe).Field1.Field2 has pipe as .Node, fields as .Field. Eval the pipeline, then the fields.
-	pipe := s.evalArg(dot, nil, chain.Node)
 	if len(chain.Field) == 0 {
 		s.errorf("internal error: no fields in evalChainNode")
 	}
+	if chain.Node.Type() == parse.NodeNil {
+		s.errorf("indirection through explicit nil in %s", chain)
+	}
+	// (pipe).Field1.Field2 has pipe as .Node, fields as .Field. Eval the pipeline, then the fields.
+	pipe := s.evalArg(dot, nil, chain.Node)
 	return s.evalFieldChain(dot, pipe, chain, chain.Field, args, final)
 }
 
diff --git a/src/text/template/exec_test.go b/src/text/template/exec_test.go
index 69c213e..b1f7787 100644
--- a/src/text/template/exec_test.go
+++ b/src/text/template/exec_test.go
@@ -527,6 +527,8 @@
 	{"bug12XE", "{{printf `%T` 0XEE}}", "int", T{}, true},
 	// Chained nodes did not work as arguments. Issue 8473.
 	{"bug13", "{{print (.Copy).I}}", "17", tVal, true},
+	// Didn't protect against explicit nil in field chains.
+	{"bug14", "{{nil.True}}", "", tVal, false},
 }
 
 func zeroArgs() string {
diff --git a/src/time/example_test.go b/src/time/example_test.go
index a37e8b8..f76fdcd 100644
--- a/src/time/example_test.go
+++ b/src/time/example_test.go
@@ -58,17 +58,127 @@
 }
 
 func ExampleTime_Format() {
-	// layout shows by example how the reference time should be represented.
-	const layout = "Jan 2, 2006 at 3:04pm (MST)"
-	t := time.Date(2009, time.November, 10, 15, 0, 0, 0, time.Local)
-	fmt.Println(t.Format(layout))
-	fmt.Println(t.UTC().Format(layout))
+	// Parse a time value from a string in the standard Unix format.
+	t, err := time.Parse(time.UnixDate, "Sat Mar  7 11:06:39 PST 2015")
+	if err != nil { // Always check errors even if they should not happen.
+		panic(err)
+	}
+
+	// time.Time's Stringer method is useful without any format.
+	fmt.Println("default format:", t)
+
+	// Predefined constants in the package implement common layouts.
+	fmt.Println("Unix format:", t.Format(time.UnixDate))
+
+	// The time zone attached to the time value affects its output.
+	fmt.Println("Same, in UTC:", t.UTC().Format(time.UnixDate))
+
+	// The rest of this function demonstrates the properties of the
+	// layout string used in the format.
+
+	// The layout string used by the Parse function and Format method
+	// shows by example how the reference time should be represented.
+	// We stress that one must show how the reference time is formatted,
+	// not a time of the user's choosing. Thus each layout string is a
+	// representation of the time stamp,
+	//	Jan 2 15:04:05 2006 MST
+	// An easy way to remember this value is that it holds, when presented
+	// in this order, the values (lined up with the elements above):
+	//	  1 2  3  4  5    6  -7
+	// There are some wrinkles illustrated below.
+
+	// Most uses of Format and Parse use constant layout strings such as
+	// the ones defined in this package, but the interface is flexible,
+	// as these examples show.
+
+	// Define a helper function to make the examples' output look nice.
+	do := func(name, layout, want string) {
+		got := t.Format(layout)
+		if want != got {
+			fmt.Printf("error: for %q got %q; expected %q\n", layout, got, want)
+			return
+		}
+		fmt.Printf("%-15s %q gives %q\n", name, layout, got)
+	}
+
+	// Print a header in our output.
+	fmt.Printf("\nFormats:\n\n")
+
+	// A simple starter example.
+	do("Basic", "Mon Jan 2 15:04:05 MST 2006", "Sat Mar 7 11:06:39 PST 2015")
+
+	// For fixed-width printing of values, such as the date, that may be one or
+	// two characters (7 vs. 07), use an _ instead of a space in the layout string.
+	// Here we print just the day, which is 2 in our layout string and 7 in our
+	// value.
+	do("No pad", "<2>", "<7>")
+
+	// An underscore represents a zero pad, if required.
+	do("Spaces", "<_2>", "< 7>")
+
+	// Similarly, a 0 indicates zero padding.
+	do("Zeros", "<02>", "<07>")
+
+	// If the value is already the right width, padding is not used.
+	// For instance, the second (05 in the reference time) in our value is 39,
+	// so it doesn't need padding, but the minutes (04, 06) does.
+	do("Suppressed pad", "04:05", "06:39")
+
+	// The predefined constant Unix uses an underscore to pad the day.
+	// Compare with our simple starter example.
+	do("Unix", time.UnixDate, "Sat Mar  7 11:06:39 PST 2015")
+
+	// The hour of the reference time is 15, or 3PM. The layout can express
+	// it either way, and since our value is the morning we should see it as
+	// an AM time. We show both in one format string. Lower case too.
+	do("AM/PM", "3PM==3pm==15h", "11AM==11am==11h")
+
+	// When parsing, if the seconds value is followed by a decimal point
+	// and some digits, that is taken as a fraction of a second even if
+	// the layout string does not represent the fractional second.
+	// Here we add a fractional second to our time value used above.
+	t, err = time.Parse(time.UnixDate, "Sat Mar  7 11:06:39.1234 PST 2015")
+	if err != nil {
+		panic(err)
+	}
+	// It does not appear in the output if the layout string does not contain
+	// a representation of the fractional second.
+	do("No fraction", time.UnixDate, "Sat Mar  7 11:06:39 PST 2015")
+
+	// Fractional seconds can be printed by adding a run of 0s or 9s after
+	// a decimal point in the seconds value in the layout string.
+	// If the layout digits are 0s, the fractional second is of the specified
+	// width. Note that the output has a trailing zero.
+	do("0s for fraction", "15:04:05.00000", "11:06:39.12340")
+
+	// If the fraction in the layout is 9s, trailing zeros are dropped.
+	do("9s for fraction", "15:04:05.99999999", "11:06:39.1234")
+
 	// Output:
-	// Nov 10, 2009 at 3:00pm (PST)
-	// Nov 10, 2009 at 11:00pm (UTC)
+	// default format: 2015-03-07 11:06:39 -0800 PST
+	// Unix format: Sat Mar  7 11:06:39 PST 2015
+	// Same, in UTC: Sat Mar  7 19:06:39 UTC 2015
+	//
+	// Formats:
+	//
+	// Basic           "Mon Jan 2 15:04:05 MST 2006" gives "Sat Mar 7 11:06:39 PST 2015"
+	// No pad          "<2>" gives "<7>"
+	// Spaces          "<_2>" gives "< 7>"
+	// Zeros           "<02>" gives "<07>"
+	// Suppressed pad  "04:05" gives "06:39"
+	// Unix            "Mon Jan _2 15:04:05 MST 2006" gives "Sat Mar  7 11:06:39 PST 2015"
+	// AM/PM           "3PM==3pm==15h" gives "11AM==11am==11h"
+	// No fraction     "Mon Jan _2 15:04:05 MST 2006" gives "Sat Mar  7 11:06:39 PST 2015"
+	// 0s for fraction "15:04:05.00000" gives "11:06:39.12340"
+	// 9s for fraction "15:04:05.99999999" gives "11:06:39.1234"
+
 }
 
 func ExampleParse() {
+	// See the example for time.Format for a thorough description of how
+	// to define the layout string to parse a time.Time value; Parse and
+	// Format use the same model to describe their input and output.
+
 	// longForm shows by example how the reference time would be represented in
 	// the desired layout.
 	const longForm = "Jan 2, 2006 at 3:04pm (MST)"
diff --git a/src/time/format.go b/src/time/format.go
index 0325399..5716108 100644
--- a/src/time/format.go
+++ b/src/time/format.go
@@ -288,7 +288,7 @@
 	"December",
 }
 
-// match returns true if s1 and s2 match ignoring case.
+// match reports whether s1 and s2 match ignoring case.
 // It is assumed s1 and s2 are the same length.
 func match(s1, s2 string) bool {
 	for i := 0; i < len(s1); i++ {
@@ -620,8 +620,7 @@
 		quote(e.Value) + e.Message
 }
 
-// isDigit returns true if s[i] is a decimal digit, false if not or
-// if s[i] is out of range.
+// isDigit reports whether s[i] is in range and is a decimal digit.
 func isDigit(s string, i int) bool {
 	if len(s) <= i {
 		return false
@@ -681,10 +680,13 @@
 // would be interpreted if it were the value; it serves as an example of
 // the input format. The same interpretation will then be made to the
 // input string.
+//
 // Predefined layouts ANSIC, UnixDate, RFC3339 and others describe standard
 // and convenient representations of the reference time. For more information
 // about the formats and the definition of the reference time, see the
 // documentation for ANSIC and the other constants defined by this package.
+// Also, the executable Example for time.Format demonstrates the working
+// of the layout string in detail and is a good reference.
 //
 // Elements omitted from the value are assumed to be zero or, when
 // zero is impossible, one, so parsing "3:04pm" returns the time
diff --git a/src/time/sleep_test.go b/src/time/sleep_test.go
index c9b2956..6452a9e 100644
--- a/src/time/sleep_test.go
+++ b/src/time/sleep_test.go
@@ -383,6 +383,10 @@
 // Test that a panic while deleting a timer does not leave
 // the timers mutex held, deadlocking a ticker.Stop in a defer.
 func TestIssue5745(t *testing.T) {
+	if runtime.GOOS == "darwin" && runtime.GOARCH == "arm" {
+		t.Skipf("skipping on %s/%s, see issue 10043", runtime.GOOS, runtime.GOARCH)
+	}
+
 	ticker := NewTicker(Hour)
 	defer func() {
 		// would deadlock here before the fix due to
diff --git a/src/time/zoneinfo_ios.go b/src/time/zoneinfo_ios.go
new file mode 100644
index 0000000..f09166c
--- /dev/null
+++ b/src/time/zoneinfo_ios.go
@@ -0,0 +1,51 @@
+// Copyright 2015 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.
+
+// +build darwin
+// +build arm arm64
+
+package time
+
+import "syscall"
+
+var zoneFile string
+
+func init() {
+	wd, err := syscall.Getwd()
+	if err != nil {
+		return
+	}
+
+	// The working directory at initialization is the root of the
+	// app bundle: "/private/.../bundlename.app". That's where we
+	// keep zoneinfo.zip.
+	zoneFile = wd + "/zoneinfo.zip"
+}
+
+func forceZipFileForTesting(zipOnly bool) {
+	// On iOS we only have the zip file.
+}
+
+func initTestingZone() {
+	z, err := loadZoneFile(zoneFile, "America/Los_Angeles")
+	if err != nil {
+		panic("cannot load America/Los_Angeles for testing: " + err.Error())
+	}
+	z.name = "Local"
+	localLoc = *z
+}
+
+func initLocal() {
+	// TODO(crawshaw): [NSTimeZone localTimeZone]
+	localLoc = *UTC
+}
+
+func loadLocation(name string) (*Location, error) {
+	z, err := loadZoneFile(zoneFile, name)
+	if err != nil {
+		return nil, err
+	}
+	z.name = name
+	return z, nil
+}
diff --git a/src/time/zoneinfo_unix.go b/src/time/zoneinfo_unix.go
index 6654096..ed9502d 100644
--- a/src/time/zoneinfo_unix.go
+++ b/src/time/zoneinfo_unix.go
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris
+// +build darwin,386 darwin,amd64 dragonfly freebsd linux nacl netbsd openbsd solaris
 
 // Parse "zoneinfo" time zone file.
 // This is a fairly standard file format used on OS X, Linux, BSD, Sun, and others.
diff --git a/src/unicode/utf16/utf16.go b/src/unicode/utf16/utf16.go
index c0e47c5..b497500 100644
--- a/src/unicode/utf16/utf16.go
+++ b/src/unicode/utf16/utf16.go
@@ -25,7 +25,7 @@
 	surrSelf = 0x10000
 )
 
-// IsSurrogate returns true if the specified Unicode code point
+// IsSurrogate reports whether the specified Unicode code point
 // can appear in a surrogate pair.
 func IsSurrogate(r rune) bool {
 	return surr1 <= r && r < surr3
diff --git a/test/escape2.go b/test/escape2.go
index 3fd62d1..65dbd7a 100644
--- a/test/escape2.go
+++ b/test/escape2.go
@@ -475,12 +475,13 @@
 
 func foo67() {
 	var mv MV
-	foo63(mv)
+	foo63(mv) // ERROR "mv does not escape"
 }
 
 func foo68() {
 	var mv MV
-	foo64(mv) // escapes but it's an int so irrelevant
+	// escapes but it's an int so irrelevant
+	foo64(mv) // ERROR "mv escapes to heap"
 }
 
 func foo69(m M) { // ERROR "leaking param: m"
@@ -488,7 +489,7 @@
 }
 
 func foo70(mv1 *MV, m M) { // ERROR "leaking param: mv1" "leaking param: m"
-	m = mv1
+	m = mv1 // ERROR "mv1 escapes to heap"
 	foo64(m)
 }
 
@@ -610,65 +611,71 @@
 	}
 }
 
-func myprint(y *int, x ...interface{}) *int { // ERROR "x does not escape" "leaking param: y"
+func myprint(y *int, x ...interface{}) *int { // ERROR "x does not escape" "leaking param: y to result ~r2"
 	return y
 }
 
-func myprint1(y *int, x ...interface{}) *interface{} { // ERROR "y does not escape" "leaking param: x"
+func myprint1(y *int, x ...interface{}) *interface{} { // ERROR "y does not escape" "leaking param: x to result ~r2"
 	return &x[0] // ERROR "&x.0. escapes to heap"
 }
 
 func foo75(z *int) { // ERROR "z does not escape"
-	myprint(z, 1, 2, 3) // ERROR "[.][.][.] argument does not escape"
+	myprint(z, 1, 2, 3) // ERROR "[.][.][.] argument does not escape" "1 escapes to heap" "2 escapes to heap" "3 escapes to heap"
 }
 
 func foo75a(z *int) { // ERROR "z does not escape"
-	myprint1(z, 1, 2, 3) // ERROR "[.][.][.] argument does not escape"
+	myprint1(z, 1, 2, 3) // ERROR "[.][.][.] argument does not escape" "1 escapes to heap" "2 escapes to heap" "3 escapes to heap"
 }
 
 func foo75esc(z *int) { // ERROR "leaking param: z"
-	gxx = myprint(z, 1, 2, 3) // ERROR "[.][.][.] argument does not escape"
+	gxx = myprint(z, 1, 2, 3) // ERROR "[.][.][.] argument does not escape" "1 escapes to heap" "2 escapes to heap" "3 escapes to heap"
 }
 
 func foo75aesc(z *int) { // ERROR "z does not escape"
 	var ppi **interface{}       // assignments to pointer dereferences lose track
-	*ppi = myprint1(z, 1, 2, 3) // ERROR "[.][.][.] argument escapes to heap"
+	*ppi = myprint1(z, 1, 2, 3) // ERROR "[.][.][.] argument escapes to heap" "1 escapes to heap" "2 escapes to heap" "3 escapes to heap"
 }
 
+func foo75aesc1(z *int) { // ERROR "z does not escape"
+	sink = myprint1(z, 1, 2, 3) // ERROR "[.][.][.] argument escapes to heap" "myprint1\(z, 1, 2, 3\) escapes to heap" "1 escapes to heap" "2 escapes to heap" "3 escapes to heap"
+}
+
+// BAD: z does not escape here
 func foo76(z *int) { // ERROR "leaking param: z"
-	myprint(nil, z) // ERROR "[.][.][.] argument does not escape"
+	myprint(nil, z) // ERROR "[.][.][.] argument does not escape" "z escapes to heap"
 }
 
+// BAD: z does not escape here
 func foo76a(z *int) { // ERROR "leaking param: z"
-	myprint1(nil, z) // ERROR "[.][.][.] argument does not escape"
+	myprint1(nil, z) // ERROR "[.][.][.] argument does not escape" "z escapes to heap"
 }
 
 func foo76b() {
-	myprint(nil, 1, 2, 3) // ERROR "[.][.][.] argument does not escape"
+	myprint(nil, 1, 2, 3) // ERROR "[.][.][.] argument does not escape" "1 escapes to heap" "2 escapes to heap" "3 escapes to heap"
 }
 
 func foo76c() {
-	myprint1(nil, 1, 2, 3) // ERROR "[.][.][.] argument does not escape"
+	myprint1(nil, 1, 2, 3) // ERROR "[.][.][.] argument does not escape" "1 escapes to heap" "2 escapes to heap" "3 escapes to heap"
 }
 
 func foo76d() {
-	defer myprint(nil, 1, 2, 3) // ERROR "[.][.][.] argument does not escape"
+	defer myprint(nil, 1, 2, 3) // ERROR "[.][.][.] argument does not escape" "1 escapes to heap" "2 escapes to heap" "3 escapes to heap"
 }
 
 func foo76e() {
-	defer myprint1(nil, 1, 2, 3) // ERROR "[.][.][.] argument does not escape"
+	defer myprint1(nil, 1, 2, 3) // ERROR "[.][.][.] argument does not escape" "1 escapes to heap" "2 escapes to heap" "3 escapes to heap"
 }
 
 func foo76f() {
 	for {
 		// TODO: This one really only escapes its scope, but we don't distinguish yet.
-		defer myprint(nil, 1, 2, 3) // ERROR "[.][.][.] argument escapes to heap"
+		defer myprint(nil, 1, 2, 3) // ERROR "[.][.][.] argument escapes to heap" "1 escapes to heap" "2 escapes to heap" "3 escapes to heap"
 	}
 }
 
 func foo76g() {
 	for {
-		defer myprint1(nil, 1, 2, 3) // ERROR "[.][.][.] argument escapes to heap"
+		defer myprint1(nil, 1, 2, 3) // ERROR "[.][.][.] argument escapes to heap" "1 escapes to heap" "2 escapes to heap" "3 escapes to heap"
 	}
 }
 
@@ -685,6 +692,20 @@
 	*ppi = myprint1(nil, z...)
 }
 
+func foo77c(z []interface{}) { // ERROR "leaking param: z"
+	sink = myprint1(nil, z...) // ERROR "myprint1\(nil, z\.\.\.\) escapes to heap"
+}
+
+func dotdotdot() {
+	// BAD: i should not escape here
+	i := 0           // ERROR "moved to heap: i"
+	myprint(nil, &i) // ERROR "&i escapes to heap" "\.\.\. argument does not escape"
+
+	// BAD: j should not escape here
+	j := 0            // ERROR "moved to heap: j"
+	myprint1(nil, &j) // ERROR "&j escapes to heap" "\.\.\. argument does not escape"
+}
+
 func foo78(z int) *int { // ERROR "moved to heap: z"
 	return &z // ERROR "&z escapes to heap"
 }
@@ -1131,16 +1152,16 @@
 
 func foo121() {
 	for i := 0; i < 10; i++ {
-		defer myprint(nil, i) // ERROR "[.][.][.] argument escapes to heap"
-		go myprint(nil, i)    // ERROR "[.][.][.] argument escapes to heap"
+		defer myprint(nil, i) // ERROR "[.][.][.] argument escapes to heap" "i escapes to heap"
+		go myprint(nil, i)    // ERROR "[.][.][.] argument escapes to heap" "i escapes to heap"
 	}
 }
 
 // same as foo121 but check across import
 func foo121b() {
 	for i := 0; i < 10; i++ {
-		defer fmt.Printf("%d", i) // ERROR "[.][.][.] argument escapes to heap"
-		go fmt.Printf("%d", i)    // ERROR "[.][.][.] argument escapes to heap"
+		defer fmt.Printf("%d", i) // ERROR "[.][.][.] argument escapes to heap" "i escapes to heap"
+		go fmt.Printf("%d", i)    // ERROR "[.][.][.] argument escapes to heap" "i escapes to heap"
 	}
 }
 
@@ -1327,7 +1348,7 @@
 		T *T
 	}
 	t := &T{} // ERROR "&T literal escapes to heap"
-	return U{
+	return U{ // ERROR "U literal escapes to heap"
 		X: t.X,
 		T: t,
 	}
@@ -1562,14 +1583,14 @@
 	// Literal does not escape, but element does.
 	i := 0        // ERROR "moved to heap: i"
 	x := &Lit{&i} // ERROR "&Lit literal does not escape" "&i escapes to heap"
-	sink = *x
+	sink = *x     // ERROR "\*x escapes to heap"
 }
 
 func ptrlitEscape() {
 	// Both literal and element escape.
 	i := 0        // ERROR "moved to heap: i"
 	x := &Lit{&i} // ERROR "&Lit literal escapes to heap" "&i escapes to heap"
-	sink = x
+	sink = x      // ERROR "x escapes to heap"
 }
 
 // self-assignments
@@ -1601,7 +1622,7 @@
 func (b *Buffer) bat() { // ERROR "leaking param: b"
 	o := new(Buffer) // ERROR "new\(Buffer\) escapes to heap"
 	o.buf1 = b.buf1[1:2]
-	sink = o
+	sink = o // ERROR "o escapes to heap"
 }
 
 func quux(sp *string, bp *[]byte) { // ERROR "sp does not escape" "bp does not escape"
@@ -1619,9 +1640,9 @@
 // to just x, and thus &i looks escaping.
 func fieldFlowTracking() {
 	var x StructWithString
-	i := 0   // ERROR "moved to heap: i"
-	x.p = &i // ERROR "&i escapes to heap"
-	sink = x.s
+	i := 0     // ERROR "moved to heap: i"
+	x.p = &i   // ERROR "&i escapes to heap"
+	sink = x.s // ERROR "x.s escapes to heap"
 }
 
 // String operations.
@@ -1650,7 +1671,7 @@
 	b := make([]byte, 20) // ERROR "does not escape"
 	s := string(b)        // ERROR "string\(b\) escapes to heap"
 	s1 := s[0:1]
-	sink = s1
+	sink = s1 // ERROR "s1 escapes to heap"
 }
 
 func addstr0() {
@@ -1680,7 +1701,7 @@
 	s1 := "b"
 	s := s0 + s1 // ERROR "s0 \+ s1 escapes to heap"
 	s2 := s[0:1]
-	sink = s2
+	sink = s2 // ERROR "s2 escapes to heap"
 }
 
 func intstring0() bool {
@@ -1757,7 +1778,7 @@
 	m[0] = 0
 	m[1]++
 	delete(m, 1)
-	sink = m[0]
+	sink = m[0] // ERROR "m\[0\] escapes to heap"
 }
 
 func makemap1() map[int]int {
@@ -1766,5 +1787,13 @@
 
 func makemap2() {
 	m := make(map[int]int) // ERROR "make\(map\[int\]int\) escapes to heap"
-	sink = m
+	sink = m               // ERROR "m escapes to heap"
+}
+
+func nonescapingEface(m map[interface{}]bool) bool { // ERROR "m does not escape"
+	return m["foo"] // ERROR `"foo" does not escape`
+}
+
+func nonescapingIface(m map[M]bool) bool { // ERROR "m does not escape"
+	return m[MV(0)] // ERROR "MV\(0\) does not escape"
 }
diff --git a/test/escape2n.go b/test/escape2n.go
index e9dd7b9..59f64c0 100644
--- a/test/escape2n.go
+++ b/test/escape2n.go
@@ -475,12 +475,13 @@
 
 func foo67() {
 	var mv MV
-	foo63(mv)
+	foo63(mv) // ERROR "mv does not escape"
 }
 
 func foo68() {
 	var mv MV
-	foo64(mv) // escapes but it's an int so irrelevant
+	// escapes but it's an int so irrelevant
+	foo64(mv) // ERROR "mv escapes to heap"
 }
 
 func foo69(m M) { // ERROR "leaking param: m"
@@ -488,7 +489,7 @@
 }
 
 func foo70(mv1 *MV, m M) { // ERROR "leaking param: mv1" "leaking param: m"
-	m = mv1
+	m = mv1 // ERROR "mv1 escapes to heap"
 	foo64(m)
 }
 
@@ -610,65 +611,71 @@
 	}
 }
 
-func myprint(y *int, x ...interface{}) *int { // ERROR "x does not escape" "leaking param: y"
+func myprint(y *int, x ...interface{}) *int { // ERROR "x does not escape" "leaking param: y to result ~r2"
 	return y
 }
 
-func myprint1(y *int, x ...interface{}) *interface{} { // ERROR "y does not escape" "leaking param: x"
+func myprint1(y *int, x ...interface{}) *interface{} { // ERROR "y does not escape" "leaking param: x to result ~r2"
 	return &x[0] // ERROR "&x.0. escapes to heap"
 }
 
 func foo75(z *int) { // ERROR "z does not escape"
-	myprint(z, 1, 2, 3) // ERROR "[.][.][.] argument does not escape"
+	myprint(z, 1, 2, 3) // ERROR "[.][.][.] argument does not escape" "1 escapes to heap" "2 escapes to heap" "3 escapes to heap"
 }
 
 func foo75a(z *int) { // ERROR "z does not escape"
-	myprint1(z, 1, 2, 3) // ERROR "[.][.][.] argument does not escape"
+	myprint1(z, 1, 2, 3) // ERROR "[.][.][.] argument does not escape" "1 escapes to heap" "2 escapes to heap" "3 escapes to heap"
 }
 
 func foo75esc(z *int) { // ERROR "leaking param: z"
-	gxx = myprint(z, 1, 2, 3) // ERROR "[.][.][.] argument does not escape"
+	gxx = myprint(z, 1, 2, 3) // ERROR "[.][.][.] argument does not escape" "1 escapes to heap" "2 escapes to heap" "3 escapes to heap"
 }
 
 func foo75aesc(z *int) { // ERROR "z does not escape"
 	var ppi **interface{}       // assignments to pointer dereferences lose track
-	*ppi = myprint1(z, 1, 2, 3) // ERROR "[.][.][.] argument escapes to heap"
+	*ppi = myprint1(z, 1, 2, 3) // ERROR "[.][.][.] argument escapes to heap" "1 escapes to heap" "2 escapes to heap" "3 escapes to heap"
 }
 
+func foo75aesc1(z *int) { // ERROR "z does not escape"
+	sink = myprint1(z, 1, 2, 3) // ERROR "[.][.][.] argument escapes to heap" "myprint1\(z, 1, 2, 3\) escapes to heap" "1 escapes to heap" "2 escapes to heap" "3 escapes to heap"
+}
+
+// BAD: z does not escape here
 func foo76(z *int) { // ERROR "leaking param: z"
-	myprint(nil, z) // ERROR "[.][.][.] argument does not escape"
+	myprint(nil, z) // ERROR "[.][.][.] argument does not escape" "z escapes to heap"
 }
 
+// BAD: z does not escape here
 func foo76a(z *int) { // ERROR "leaking param: z"
-	myprint1(nil, z) // ERROR "[.][.][.] argument does not escape"
+	myprint1(nil, z) // ERROR "[.][.][.] argument does not escape" "z escapes to heap"
 }
 
 func foo76b() {
-	myprint(nil, 1, 2, 3) // ERROR "[.][.][.] argument does not escape"
+	myprint(nil, 1, 2, 3) // ERROR "[.][.][.] argument does not escape" "1 escapes to heap" "2 escapes to heap" "3 escapes to heap"
 }
 
 func foo76c() {
-	myprint1(nil, 1, 2, 3) // ERROR "[.][.][.] argument does not escape"
+	myprint1(nil, 1, 2, 3) // ERROR "[.][.][.] argument does not escape" "1 escapes to heap" "2 escapes to heap" "3 escapes to heap"
 }
 
 func foo76d() {
-	defer myprint(nil, 1, 2, 3) // ERROR "[.][.][.] argument does not escape"
+	defer myprint(nil, 1, 2, 3) // ERROR "[.][.][.] argument does not escape" "1 escapes to heap" "2 escapes to heap" "3 escapes to heap"
 }
 
 func foo76e() {
-	defer myprint1(nil, 1, 2, 3) // ERROR "[.][.][.] argument does not escape"
+	defer myprint1(nil, 1, 2, 3) // ERROR "[.][.][.] argument does not escape" "1 escapes to heap" "2 escapes to heap" "3 escapes to heap"
 }
 
 func foo76f() {
 	for {
 		// TODO: This one really only escapes its scope, but we don't distinguish yet.
-		defer myprint(nil, 1, 2, 3) // ERROR "[.][.][.] argument escapes to heap"
+		defer myprint(nil, 1, 2, 3) // ERROR "[.][.][.] argument escapes to heap" "1 escapes to heap" "2 escapes to heap" "3 escapes to heap"
 	}
 }
 
 func foo76g() {
 	for {
-		defer myprint1(nil, 1, 2, 3) // ERROR "[.][.][.] argument escapes to heap"
+		defer myprint1(nil, 1, 2, 3) // ERROR "[.][.][.] argument escapes to heap" "1 escapes to heap" "2 escapes to heap" "3 escapes to heap"
 	}
 }
 
@@ -685,6 +692,20 @@
 	*ppi = myprint1(nil, z...)
 }
 
+func foo77c(z []interface{}) { // ERROR "leaking param: z"
+	sink = myprint1(nil, z...) // ERROR "myprint1\(nil, z\.\.\.\) escapes to heap"
+}
+
+func dotdotdot() {
+	// BAD: i should not escape here
+	i := 0           // ERROR "moved to heap: i"
+	myprint(nil, &i) // ERROR "&i escapes to heap" "\.\.\. argument does not escape"
+
+	// BAD: j should not escape here
+	j := 0            // ERROR "moved to heap: j"
+	myprint1(nil, &j) // ERROR "&j escapes to heap" "\.\.\. argument does not escape"
+}
+
 func foo78(z int) *int { // ERROR "moved to heap: z"
 	return &z // ERROR "&z escapes to heap"
 }
@@ -1131,16 +1152,16 @@
 
 func foo121() {
 	for i := 0; i < 10; i++ {
-		defer myprint(nil, i) // ERROR "[.][.][.] argument escapes to heap"
-		go myprint(nil, i)    // ERROR "[.][.][.] argument escapes to heap"
+		defer myprint(nil, i) // ERROR "[.][.][.] argument escapes to heap" "i escapes to heap"
+		go myprint(nil, i)    // ERROR "[.][.][.] argument escapes to heap" "i escapes to heap"
 	}
 }
 
 // same as foo121 but check across import
 func foo121b() {
 	for i := 0; i < 10; i++ {
-		defer fmt.Printf("%d", i) // ERROR "[.][.][.] argument escapes to heap"
-		go fmt.Printf("%d", i)    // ERROR "[.][.][.] argument escapes to heap"
+		defer fmt.Printf("%d", i) // ERROR "[.][.][.] argument escapes to heap" "i escapes to heap"
+		go fmt.Printf("%d", i)    // ERROR "[.][.][.] argument escapes to heap" "i escapes to heap"
 	}
 }
 
@@ -1327,7 +1348,7 @@
 		T *T
 	}
 	t := &T{} // ERROR "&T literal escapes to heap"
-	return U{
+	return U{ // ERROR "U literal escapes to heap"
 		X: t.X,
 		T: t,
 	}
@@ -1562,14 +1583,14 @@
 	// Literal does not escape, but element does.
 	i := 0        // ERROR "moved to heap: i"
 	x := &Lit{&i} // ERROR "&Lit literal does not escape" "&i escapes to heap"
-	sink = *x
+	sink = *x     // ERROR "\*x escapes to heap"
 }
 
 func ptrlitEscape() {
 	// Both literal and element escape.
 	i := 0        // ERROR "moved to heap: i"
 	x := &Lit{&i} // ERROR "&Lit literal escapes to heap" "&i escapes to heap"
-	sink = x
+	sink = x      // ERROR "x escapes to heap"
 }
 
 // self-assignments
@@ -1601,7 +1622,7 @@
 func (b *Buffer) bat() { // ERROR "leaking param: b"
 	o := new(Buffer) // ERROR "new\(Buffer\) escapes to heap"
 	o.buf1 = b.buf1[1:2]
-	sink = o
+	sink = o // ERROR "o escapes to heap"
 }
 
 func quux(sp *string, bp *[]byte) { // ERROR "sp does not escape" "bp does not escape"
@@ -1619,9 +1640,9 @@
 // to just x, and thus &i looks escaping.
 func fieldFlowTracking() {
 	var x StructWithString
-	i := 0   // ERROR "moved to heap: i"
-	x.p = &i // ERROR "&i escapes to heap"
-	sink = x.s
+	i := 0     // ERROR "moved to heap: i"
+	x.p = &i   // ERROR "&i escapes to heap"
+	sink = x.s // ERROR "x.s escapes to heap"
 }
 
 // String operations.
@@ -1650,7 +1671,7 @@
 	b := make([]byte, 20) // ERROR "does not escape"
 	s := string(b)        // ERROR "string\(b\) escapes to heap"
 	s1 := s[0:1]
-	sink = s1
+	sink = s1 // ERROR "s1 escapes to heap"
 }
 
 func addstr0() {
@@ -1680,7 +1701,7 @@
 	s1 := "b"
 	s := s0 + s1 // ERROR "s0 \+ s1 escapes to heap"
 	s2 := s[0:1]
-	sink = s2
+	sink = s2 // ERROR "s2 escapes to heap"
 }
 
 func intstring0() bool {
@@ -1757,7 +1778,7 @@
 	m[0] = 0
 	m[1]++
 	delete(m, 1)
-	sink = m[0]
+	sink = m[0] // ERROR "m\[0\] escapes to heap"
 }
 
 func makemap1() map[int]int {
@@ -1766,5 +1787,13 @@
 
 func makemap2() {
 	m := make(map[int]int) // ERROR "make\(map\[int\]int\) escapes to heap"
-	sink = m
+	sink = m               // ERROR "m escapes to heap"
+}
+
+func nonescapingEface(m map[interface{}]bool) bool { // ERROR "m does not escape"
+	return m["foo"] // ERROR `"foo" does not escape`
+}
+
+func nonescapingIface(m map[M]bool) bool { // ERROR "m does not escape"
+	return m[MV(0)] // ERROR "MV\(0\) does not escape"
 }
diff --git a/test/escape5.go b/test/escape5.go
index a33daee..1d411b3 100644
--- a/test/escape5.go
+++ b/test/escape5.go
@@ -134,7 +134,8 @@
 		return
 	}
 
-	global = p // should make p leak always
+	// should make p leak always
+	global = p // ERROR "p escapes to heap"
 	return T2{p}
 }
 
diff --git a/test/escape_closure.go b/test/escape_closure.go
new file mode 100644
index 0000000..0a5f326
--- /dev/null
+++ b/test/escape_closure.go
@@ -0,0 +1,147 @@
+// errorcheck -0 -m -l
+
+// Copyright 2015 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.
+
+// Test escape analysis for closure arguments.
+
+package escape
+
+var sink interface{}
+
+func ClosureCallArgs0() {
+	x := 0         // ERROR "moved to heap: x"
+	func(p *int) { // ERROR "p does not escape" "func literal does not escape"
+		*p = 1
+		// BAD: x should not escape to heap here
+	}(&x) // ERROR "&x escapes to heap"
+}
+
+func ClosureCallArgs1() {
+	x := 0 // ERROR "moved to heap: x"
+	for {
+		func(p *int) { // ERROR "p does not escape" "func literal does not escape"
+			*p = 1
+			// BAD: x should not escape to heap here
+		}(&x) // ERROR "&x escapes to heap"
+	}
+}
+
+func ClosureCallArgs2() {
+	for {
+		// BAD: x should not escape here
+		x := 0         // ERROR "moved to heap: x"
+		func(p *int) { // ERROR "p does not escape" "func literal does not escape"
+			*p = 1
+		}(&x) // ERROR "&x escapes to heap"
+	}
+}
+
+func ClosureCallArgs3() {
+	x := 0         // ERROR "moved to heap: x"
+	func(p *int) { // ERROR "leaking param: p" "func literal does not escape"
+		sink = p // ERROR "p escapes to heap"
+	}(&x) // ERROR "&x escapes to heap"
+}
+
+func ClosureCallArgs4() {
+	// BAD: x should not leak here
+	x := 0                  // ERROR "moved to heap: x"
+	_ = func(p *int) *int { // ERROR "leaking param: p to result ~r1" "func literal does not escape"
+		return p
+	}(&x) // ERROR "&x escapes to heap"
+}
+
+func ClosureCallArgs5() {
+	x := 0                     // ERROR "moved to heap: x"
+	sink = func(p *int) *int { // ERROR "leaking param: p to result ~r1" "func literal does not escape"
+		return p
+	}(&x) // ERROR "&x escapes to heap" "\(func literal\)\(&x\) escapes to heap"
+}
+
+func ClosureCallArgs6() {
+	x := 0         // ERROR "moved to heap: x"
+	func(p *int) { // ERROR "moved to heap: p" "func literal does not escape"
+		sink = &p // ERROR "&p escapes to heap"
+	}(&x) // ERROR "&x escapes to heap"
+}
+
+func ClosureCallArgs7() {
+	var pp *int
+	for {
+		x := 0         // ERROR "moved to heap: x"
+		func(p *int) { // ERROR "leaking param: p" "func literal does not escape"
+			pp = p
+		}(&x) // ERROR "&x escapes to heap"
+	}
+	_ = pp
+}
+
+func ClosureCallArgs8() {
+	x := 0               // ERROR "moved to heap: x"
+	defer func(p *int) { // ERROR "p does not escape" "func literal does not escape"
+		*p = 1
+		// BAD: x should not escape to heap here
+	}(&x) // ERROR "&x escapes to heap"
+}
+
+func ClosureCallArgs9() {
+	// BAD: x should not leak
+	x := 0 // ERROR "moved to heap: x"
+	for {
+		defer func(p *int) { // ERROR "func literal escapes to heap" "p does not escape"
+			*p = 1
+		}(&x) // ERROR "&x escapes to heap"
+	}
+}
+
+func ClosureCallArgs10() {
+	for {
+		x := 0               // ERROR "moved to heap: x"
+		defer func(p *int) { // ERROR "func literal escapes to heap" "p does not escape"
+			*p = 1
+		}(&x) // ERROR "&x escapes to heap"
+	}
+}
+
+func ClosureCallArgs11() {
+	x := 0               // ERROR "moved to heap: x"
+	defer func(p *int) { // ERROR "leaking param: p" "func literal does not escape"
+		sink = p // ERROR "p escapes to heap"
+	}(&x) // ERROR "&x escapes to heap"
+}
+
+func ClosureCallArgs12() {
+	// BAD: x should not leak
+	x := 0                    // ERROR "moved to heap: x"
+	defer func(p *int) *int { // ERROR "leaking param: p to result ~r1" "func literal does not escape"
+		return p
+	}(&x) // ERROR "&x escapes to heap"
+}
+
+func ClosureCallArgs13() {
+	x := 0               // ERROR "moved to heap: x"
+	defer func(p *int) { // ERROR "moved to heap: p" "func literal does not escape"
+		sink = &p // ERROR "&p escapes to heap"
+	}(&x) // ERROR "&x escapes to heap"
+}
+
+func ClosureCallArgs14() {
+	x := 0 // ERROR "moved to heap: x"
+	// BAD: &x should not escape here
+	p := &x                  // ERROR "moved to heap: p" "&x escapes to heap"
+	_ = func(p **int) *int { // ERROR "leaking param p content to result ~r1" "func literal does not escape"
+		return *p
+		// BAD: p should not escape here
+	}(&p) // ERROR "&p escapes to heap"
+}
+
+func ClosureCallArgs15() {
+	x := 0                      // ERROR "moved to heap: x"
+	p := &x                     // ERROR "moved to heap: p" "&x escapes to heap"
+	sink = func(p **int) *int { // ERROR "leaking param p content to result ~r1" "func literal does not escape"
+		return *p
+		// BAD: p should not escape here
+	}(&p) // ERROR "&p escapes to heap" "\(func literal\)\(&p\) escapes to heap"
+}
diff --git a/test/escape_field.go b/test/escape_field.go
new file mode 100644
index 0000000..dcf8a31
--- /dev/null
+++ b/test/escape_field.go
@@ -0,0 +1,175 @@
+// errorcheck -0 -m -l
+
+// Copyright 2015 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.
+
+// Test escape analysis with respect to field assignments.
+
+package escape
+
+var sink interface{}
+
+type X struct {
+	p1 *int
+	p2 *int
+	a  [2]*int
+}
+
+type Y struct {
+	x X
+}
+
+func field0() {
+	i := 0 // ERROR "moved to heap: i$"
+	var x X
+	x.p1 = &i // ERROR "&i escapes to heap$"
+	sink = x.p1 // ERROR "x\.p1 escapes to heap"
+}
+
+func field1() {
+	i := 0 // ERROR "moved to heap: i$"
+	var x X
+	// BAD: &i should not escape
+	x.p1 = &i // ERROR "&i escapes to heap$"
+	sink = x.p2 // ERROR "x\.p2 escapes to heap"
+}
+
+func field3() {
+	i := 0 // ERROR "moved to heap: i$"
+	var x X
+	x.p1 = &i // ERROR "&i escapes to heap$"
+	sink = x // ERROR "x escapes to heap"
+}
+
+func field4() {
+	i := 0 // ERROR "moved to heap: i$"
+	var y Y
+	y.x.p1 = &i // ERROR "&i escapes to heap$"
+	x := y.x
+	sink = x // ERROR "x escapes to heap"
+}
+
+func field5() {
+	i := 0 // ERROR "moved to heap: i$"
+	var x X
+	// BAD: &i should not escape here
+	x.a[0] = &i // ERROR "&i escapes to heap$"
+	sink = x.a[1] // ERROR "x\.a\[1\] escapes to heap"
+}
+
+// BAD: we are not leaking param x, only x.p2
+func field6(x *X) { // ERROR "leaking param: x$"
+	sink = x.p2 // ERROR "x\.p2 escapes to heap"
+}
+
+func field6a() {
+	i := 0  // ERROR "moved to heap: i$"
+	var x X // ERROR "moved to heap: x$"
+	// BAD: &i should not escape
+	x.p1 = &i // ERROR "&i escapes to heap$"
+	// BAD: &x should not escape
+	field6(&x) // ERROR "&x escapes to heap$"
+}
+
+func field7() {
+	i := 0
+	var y Y
+	y.x.p1 = &i // ERROR "field7 &i does not escape$"
+	x := y.x
+	var y1 Y
+	y1.x = x
+	_ = y1.x.p1
+}
+
+func field8() {
+	i := 0 // ERROR "moved to heap: i$"
+	var y Y
+	y.x.p1 = &i // ERROR "&i escapes to heap$"
+	x := y.x
+	var y1 Y
+	y1.x = x
+	sink = y1.x.p1 // ERROR "y1\.x\.p1 escapes to heap"
+}
+
+func field9() {
+	i := 0 // ERROR "moved to heap: i$"
+	var y Y
+	y.x.p1 = &i // ERROR "&i escapes to heap$"
+	x := y.x
+	var y1 Y
+	y1.x = x
+	sink = y1.x // ERROR "y1\.x escapes to heap"
+}
+
+func field10() {
+	i := 0 // ERROR "moved to heap: i$"
+	var y Y
+	// BAD: &i should not escape
+	y.x.p1 = &i // ERROR "&i escapes to heap$"
+	x := y.x
+	var y1 Y
+	y1.x = x
+	sink = y1.x.p2 // ERROR "y1\.x\.p2 escapes to heap"
+}
+
+func field11() {
+	i := 0         // ERROR "moved to heap: i$"
+	x := X{p1: &i} // ERROR "&i escapes to heap$"
+	sink = x.p1 // ERROR "x\.p1 escapes to heap"
+}
+
+func field12() {
+	i := 0 // ERROR "moved to heap: i$"
+	// BAD: &i should not escape
+	x := X{p1: &i} // ERROR "&i escapes to heap$"
+	sink = x.p2 // ERROR "x\.p2 escapes to heap"
+}
+
+func field13() {
+	i := 0          // ERROR "moved to heap: i$"
+	x := &X{p1: &i} // ERROR "&i escapes to heap$" "field13 &X literal does not escape$"
+	sink = x.p1 // ERROR "x\.p1 escapes to heap"
+}
+
+func field14() {
+	i := 0 // ERROR "moved to heap: i$"
+	// BAD: &i should not escape
+	x := &X{p1: &i} // ERROR "&i escapes to heap$" "field14 &X literal does not escape$"
+	sink = x.p2 // ERROR "x\.p2 escapes to heap"
+}
+
+func field15() {
+	i := 0          // ERROR "moved to heap: i$"
+	x := &X{p1: &i} // ERROR "&X literal escapes to heap$" "&i escapes to heap$"
+	sink = x // ERROR "x escapes to heap"
+}
+
+func field16() {
+	i := 0 // ERROR "moved to heap: i$"
+	var x X
+	// BAD: &i should not escape
+	x.p1 = &i // ERROR "&i escapes to heap$"
+	var iface interface{} = x // ERROR "x escapes to heap"
+	x1 := iface.(X)
+	sink = x1.p2 // ERROR "x1\.p2 escapes to heap"
+}
+
+func field17() {
+	i := 0 // ERROR "moved to heap: i$"
+	var x X
+	x.p1 = &i // ERROR "&i escapes to heap$"
+	var iface interface{} = x // ERROR "x escapes to heap"
+	x1 := iface.(X)
+	sink = x1.p1 // ERROR "x1\.p1 escapes to heap"
+}
+
+func field18() {
+	i := 0 // ERROR "moved to heap: i$"
+	var x X
+	// BAD: &i should not escape
+	x.p1 = &i // ERROR "&i escapes to heap$"
+	var iface interface{} = x // ERROR "x escapes to heap"
+	y, _ := iface.(Y) // Put X, but extracted Y. The cast will fail, so y is zero initialized.
+	sink = y // ERROR "y escapes to heap"
+}
diff --git a/test/escape_iface.go b/test/escape_iface.go
new file mode 100644
index 0000000..3bc914c
--- /dev/null
+++ b/test/escape_iface.go
@@ -0,0 +1,211 @@
+// errorcheck -0 -m -l
+
+// Copyright 2015 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.
+
+// Test escape analysis for interface conversions.
+
+package escape
+
+var sink interface{}
+
+type M interface {
+	M()
+}
+
+func mescapes(m M) { // ERROR "leaking param: m"
+	sink = m // ERROR "m escapes to heap"
+}
+
+func mdoesnotescape(m M) { // ERROR "m does not escape"
+}
+
+// Tests for type stored directly in iface and with value receiver method.
+type M0 struct {
+	p *int
+}
+
+func (M0) M() {
+}
+
+func efaceEscape0() {
+	{
+		i := 0
+		v := M0{&i} // ERROR "&i does not escape"
+		var x M = v // ERROR "v does not escape"
+		_ = x
+	}
+	{
+		i := 0      // ERROR "moved to heap: i"
+		v := M0{&i} // ERROR "&i escapes to heap"
+		var x M = v // ERROR "v escapes to heap"
+		sink = x    // ERROR "x escapes to heap"
+	}
+	{
+		i := 0
+		v := M0{&i} // ERROR "&i does not escape"
+		var x M = v // ERROR "v does not escape"
+		v1 := x.(M0)
+		_ = v1
+	}
+	{
+		i := 0      // ERROR "moved to heap: i"
+		v := M0{&i} // ERROR "&i escapes to heap"
+		// BAD: v does not escape to heap here
+		var x M = v // ERROR "v escapes to heap"
+		v1 := x.(M0)
+		sink = v1 // ERROR "v1 escapes to heap"
+	}
+	{
+		i := 0      // ERROR "moved to heap: i"
+		v := M0{&i} // ERROR "&i escapes to heap"
+		// BAD: v does not escape to heap here
+		var x M = v // ERROR "v escapes to heap"
+		x.M()
+	}
+	{
+		i := 0      // ERROR "moved to heap: i"
+		v := M0{&i} // ERROR "&i escapes to heap"
+		var x M = v // ERROR "v escapes to heap"
+		mescapes(x)
+	}
+	{
+		i := 0
+		v := M0{&i} // ERROR "&i does not escape"
+		var x M = v // ERROR "v does not escape"
+		mdoesnotescape(x)
+	}
+}
+
+// Tests for type stored indirectly in iface and with value receiver method.
+type M1 struct {
+	p *int
+	x int
+}
+
+func (M1) M() {
+}
+
+func efaceEscape1() {
+	{
+		i := 0
+		v := M1{&i, 0} // ERROR "&i does not escape"
+		var x M = v    // ERROR "v does not escape"
+		_ = x
+	}
+	{
+		i := 0         // ERROR "moved to heap: i"
+		v := M1{&i, 0} // ERROR "&i escapes to heap"
+		var x M = v    // ERROR "v escapes to heap"
+		sink = x       // ERROR "x escapes to heap"
+	}
+	{
+		i := 0
+		v := M1{&i, 0} // ERROR "&i does not escape"
+		var x M = v    // ERROR "v does not escape"
+		v1 := x.(M1)
+		_ = v1
+	}
+	{
+		i := 0         // ERROR "moved to heap: i"
+		v := M1{&i, 0} // ERROR "&i escapes to heap"
+		// BAD: v does not escape to heap here
+		var x M = v // ERROR "v escapes to heap"
+		v1 := x.(M1)
+		sink = v1 // ERROR "v1 escapes to heap"
+	}
+	{
+		i := 0         // ERROR "moved to heap: i"
+		v := M1{&i, 0} // ERROR "&i escapes to heap"
+		// BAD: v does not escape to heap here
+		var x M = v // ERROR "v escapes to heap"
+		x.M()
+	}
+	{
+		i := 0         // ERROR "moved to heap: i"
+		v := M1{&i, 0} // ERROR "&i escapes to heap"
+		var x M = v    // ERROR "v escapes to heap"
+		mescapes(x)
+	}
+	{
+		i := 0
+		v := M1{&i, 0} // ERROR "&i does not escape"
+		var x M = v    // ERROR "v does not escape"
+		mdoesnotescape(x)
+	}
+}
+
+// Tests for type stored directly in iface and with pointer receiver method.
+type M2 struct {
+	p *int
+}
+
+func (*M2) M() {
+}
+
+func efaceEscape2() {
+	{
+		i := 0
+		v := &M2{&i} // ERROR "&i does not escape" "&M2 literal does not escape"
+		var x M = v  // ERROR "v does not escape"
+		_ = x
+	}
+	{
+		i := 0       // ERROR "moved to heap: i"
+		v := &M2{&i} // ERROR "&i escapes to heap" "&M2 literal escapes to heap"
+		var x M = v  // ERROR "v escapes to heap"
+		sink = x     // ERROR "x escapes to heap"
+	}
+	{
+		i := 0
+		v := &M2{&i} // ERROR "&i does not escape" "&M2 literal does not escape"
+		var x M = v  // ERROR "v does not escape"
+		v1 := x.(*M2)
+		_ = v1
+	}
+	{
+		i := 0       // ERROR "moved to heap: i"
+		v := &M2{&i} // ERROR "&i escapes to heap" "&M2 literal escapes to heap"
+		// BAD: v does not escape to heap here
+		var x M = v // ERROR "v escapes to heap"
+		v1 := x.(*M2)
+		sink = v1 // ERROR "v1 escapes to heap"
+	}
+	{
+		i := 0       // ERROR "moved to heap: i"
+		v := &M2{&i} // ERROR "&i escapes to heap" "&M2 literal does not escape"
+		// BAD: v does not escape to heap here
+		var x M = v // ERROR "v does not escape"
+		v1 := x.(*M2)
+		sink = *v1 // ERROR "v1 escapes to heap"
+	}
+	{
+		i := 0       // ERROR "moved to heap: i"
+		v := &M2{&i} // ERROR "&i escapes to heap" "&M2 literal does not escape"
+		// BAD: v does not escape to heap here
+		var x M = v // ERROR "v does not escape"
+		v1, ok := x.(*M2)
+		sink = *v1 // ERROR "v1 escapes to heap"
+		_ = ok
+	}
+	{
+		i := 0       // ERROR "moved to heap: i"
+		v := &M2{&i} // ERROR "&i escapes to heap" "&M2 literal escapes to heap"
+		// BAD: v does not escape to heap here
+		var x M = v // ERROR "v escapes to heap"
+		x.M()
+	}
+	{
+		i := 0       // ERROR "moved to heap: i"
+		v := &M2{&i} // ERROR "&i escapes to heap" "&M2 literal escapes to heap"
+		var x M = v  // ERROR "v escapes to heap"
+		mescapes(x)
+	}
+	{
+		i := 0
+		v := &M2{&i} // ERROR "&i does not escape" "&M2 literal does not escape"
+		var x M = v  // ERROR "v does not escape"
+		mdoesnotescape(x)
+	}
+}
diff --git a/test/escape_indir.go b/test/escape_indir.go
new file mode 100644
index 0000000..7c06ceb
--- /dev/null
+++ b/test/escape_indir.go
@@ -0,0 +1,153 @@
+// errorcheck -0 -m -l
+
+// Copyright 2015 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.
+
+// Test escape analysis when assigning to indirections.
+
+package escape
+
+var sink interface{}
+
+type ConstPtr struct {
+	p *int
+	c ConstPtr2
+	x **ConstPtr
+}
+
+type ConstPtr2 struct {
+	p *int
+	i int
+}
+
+func constptr0() {
+	i := 0           // ERROR "moved to heap: i"
+	x := &ConstPtr{} // ERROR "&ConstPtr literal does not escape"
+	// BAD: i should not escape here
+	x.p = &i // ERROR "&i escapes to heap"
+	_ = x
+}
+
+func constptr01() *ConstPtr {
+	i := 0           // ERROR "moved to heap: i"
+	x := &ConstPtr{} // ERROR "&ConstPtr literal escapes to heap"
+	x.p = &i         // ERROR "&i escapes to heap"
+	return x
+}
+
+func constptr02() ConstPtr {
+	i := 0           // ERROR "moved to heap: i"
+	x := &ConstPtr{} // ERROR "&ConstPtr literal does not escape"
+	x.p = &i         // ERROR "&i escapes to heap"
+	return *x
+}
+
+func constptr03() **ConstPtr {
+	i := 0           // ERROR "moved to heap: i"
+	x := &ConstPtr{} // ERROR "&ConstPtr literal escapes to heap" "moved to heap: x"
+	x.p = &i         // ERROR "&i escapes to heap"
+	return &x        // ERROR "&x escapes to heap"
+}
+
+func constptr1() {
+	i := 0           // ERROR "moved to heap: i"
+	x := &ConstPtr{} // ERROR "&ConstPtr literal escapes to heap"
+	x.p = &i         // ERROR "&i escapes to heap"
+	sink = x // ERROR "x escapes to heap"
+}
+
+func constptr2() {
+	i := 0           // ERROR "moved to heap: i"
+	x := &ConstPtr{} // ERROR "&ConstPtr literal does not escape"
+	x.p = &i         // ERROR "&i escapes to heap"
+	sink = *x// ERROR "\*x escapes to heap"
+}
+
+func constptr4() *ConstPtr {
+	p := new(ConstPtr) // ERROR "new\(ConstPtr\) escapes to heap"
+	*p = *&ConstPtr{}  // ERROR "&ConstPtr literal does not escape"
+	return p
+}
+
+func constptr5() *ConstPtr {
+	p := new(ConstPtr) // ERROR "new\(ConstPtr\) escapes to heap"
+	p1 := &ConstPtr{}  // ERROR "&ConstPtr literal does not escape"
+	*p = *p1
+	return p
+}
+
+// BAD: p should not escape here
+func constptr6(p *ConstPtr) { // ERROR "leaking param: p"
+	p1 := &ConstPtr{} // ERROR "&ConstPtr literal does not escape"
+	*p1 = *p
+	_ = p1
+}
+
+func constptr7() **ConstPtr {
+	p := new(ConstPtr) // ERROR "new\(ConstPtr\) escapes to heap" "moved to heap: p"
+	var tmp ConstPtr2
+	p1 := &tmp // ERROR "&tmp does not escape"
+	p.c = *p1
+	return &p // ERROR "&p escapes to heap"
+}
+
+func constptr8() *ConstPtr {
+	p := new(ConstPtr) // ERROR "new\(ConstPtr\) escapes to heap"
+	var tmp ConstPtr2
+	p.c = *&tmp // ERROR "&tmp does not escape"
+	return p
+}
+
+func constptr9() ConstPtr {
+	p := new(ConstPtr) // ERROR "new\(ConstPtr\) does not escape"
+	var p1 ConstPtr2
+	i := 0    // ERROR "moved to heap: i"
+	p1.p = &i // ERROR "&i escapes to heap"
+	p.c = p1
+	return *p
+}
+
+func constptr10() ConstPtr {
+	x := &ConstPtr{} // ERROR "moved to heap: x" "&ConstPtr literal escapes to heap"
+	i := 0           // ERROR "moved to heap: i"
+	var p *ConstPtr
+	p = &ConstPtr{p: &i, x: &x} // ERROR "&i escapes to heap" "&x escapes to heap" "&ConstPtr literal does not escape"
+	var pp **ConstPtr
+	pp = &p // ERROR "&p does not escape"
+	return **pp
+}
+
+func constptr11() *ConstPtr {
+	i := 0             // ERROR "moved to heap: i"
+	p := new(ConstPtr) // ERROR "new\(ConstPtr\) escapes to heap"
+	p1 := &ConstPtr{}  // ERROR "&ConstPtr literal does not escape"
+	p1.p = &i          // ERROR "&i escapes to heap"
+	*p = *p1
+	return p
+}
+
+func foo(p **int) { // ERROR "foo p does not escape"
+	i := 0 // ERROR "moved to heap: i"
+	y := p
+	*y = &i // ERROR "&i escapes to heap"
+}
+
+func foo1(p *int) { // ERROR "p does not escape"
+	i := 0  // ERROR "moved to heap: i"
+	y := &p // ERROR "&p does not escape"
+	*y = &i // ERROR "&i escapes to heap"
+}
+
+func foo2() {
+	type Z struct {
+		f **int
+	}
+	x := new(int) // ERROR "moved to heap: x" "new\(int\) escapes to heap"
+	sink = &x     // ERROR "&x escapes to heap"
+	var z Z
+	z.f = &x // ERROR "&x does not escape"
+	p := z.f
+	i := 0  // ERROR "moved to heap: i"
+	*p = &i // ERROR "&i escapes to heap"
+}
diff --git a/test/escape_level.go b/test/escape_level.go
new file mode 100644
index 0000000..581e4a9
--- /dev/null
+++ b/test/escape_level.go
@@ -0,0 +1,108 @@
+// errorcheck -0 -m -l
+
+// Copyright 2015 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.
+
+// Test indirection level computation in escape analysis.
+
+package escape
+
+var sink interface{}
+
+func level0() {
+	i := 0     // ERROR "moved to heap: i"
+	p0 := &i   // ERROR "moved to heap: p0" "&i escapes to heap"
+	p1 := &p0  // ERROR "moved to heap: p1" "&p0 escapes to heap"
+	p2 := &p1  // ERROR "moved to heap: p2" "&p1 escapes to heap"
+	sink = &p2 // ERROR "&p2 escapes to heap"
+}
+
+func level1() {
+	i := 0    // ERROR "moved to heap: i"
+	p0 := &i  // ERROR "moved to heap: p0" "&i escapes to heap"
+	p1 := &p0 // ERROR "moved to heap: p1" "&p0 escapes to heap"
+	p2 := &p1 // ERROR "&p1 escapes to heap"
+	sink = p2 // ERROR "p2 escapes to heap"
+}
+
+func level2() {
+	i := 0    // ERROR "moved to heap: i"
+	p0 := &i  // ERROR "moved to heap: p0" "&i escapes to heap"
+	p1 := &p0 // ERROR "&p0 escapes to heap"
+	p2 := &p1 // ERROR "&p1 does not escape"
+	sink = *p2 // ERROR "\*p2 escapes to heap"
+}
+
+func level3() {
+	i := 0    // ERROR "moved to heap: i"
+	p0 := &i  // ERROR "&i escapes to heap"
+	p1 := &p0 // ERROR "&p0 does not escape"
+	p2 := &p1 // ERROR "&p1 does not escape"
+	sink = **p2 // ERROR "\* \(\*p2\) escapes to heap"
+}
+
+func level4() {
+	i := 0     // ERROR "moved to heap: i"
+	p0 := &i   // ERROR "moved to heap: p0" "&i escapes to heap"
+	p1 := &p0  // ERROR "&p0 escapes to heap"
+	p2 := p1   // ERROR "moved to heap: p2"
+	sink = &p2 // ERROR "&p2 escapes to heap"
+}
+
+func level5() {
+	i := 0    // ERROR "moved to heap: i"
+	p0 := &i  // ERROR "moved to heap: p0" "&i escapes to heap"
+	p1 := &p0 // ERROR "&p0 escapes to heap"
+	p2 := p1
+	sink = p2 // ERROR "p2 escapes to heap"
+}
+
+func level6() {
+	i := 0    // ERROR "moved to heap: i"
+	p0 := &i  // ERROR "&i escapes to heap"
+	p1 := &p0 // ERROR "&p0 does not escape"
+	p2 := p1
+	sink = *p2 // ERROR "\*p2 escapes to heap"
+}
+
+func level7() {
+	i := 0     // ERROR "moved to heap: i"
+	p0 := &i   // ERROR "moved to heap: p0" "&i escapes to heap"
+	// BAD: p0 should not escape here
+	p1 := &p0  // ERROR "&p0 escapes to heap"
+	p2 := *p1  // ERROR "moved to heap: p2"
+	sink = &p2 // ERROR "&p2 escapes to heap"
+}
+
+func level8() {
+	i := 0    // ERROR "moved to heap: i"
+	p0 := &i  // ERROR "&i escapes to heap"
+	p1 := &p0 // ERROR "&p0 does not escape"
+	p2 := *p1
+	sink = p2 // ERROR "p2 escapes to heap"
+}
+
+func level9() {
+	i := 0
+	p0 := &i  // ERROR "&i does not escape"
+	p1 := &p0 // ERROR "&p0 does not escape"
+	p2 := *p1
+	sink = *p2 // ERROR "\*p2 escapes to heap"
+}
+
+func level10() {
+	i := 0
+	p0 := &i // ERROR "&i does not escape"
+	p1 := *p0
+	p2 := &p1 // ERROR "&p1 does not escape"
+	sink = *p2 // ERROR "\*p2 escapes to heap"
+}
+
+func level11() {
+	i := 0
+	p0 := &i   // ERROR "&i does not escape"
+	p1 := &p0  // ERROR "&p0 does not escape"
+	p2 := **p1 // ERROR "moved to heap: p2"
+	sink = &p2 // ERROR "&p2 escapes to heap"
+}
diff --git a/test/escape_map.go b/test/escape_map.go
new file mode 100644
index 0000000..868c456
--- /dev/null
+++ b/test/escape_map.go
@@ -0,0 +1,107 @@
+// errorcheck -0 -m -l
+
+// Copyright 2015 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.
+
+// Test escape analysis for maps.
+
+package escape
+
+var sink interface{}
+
+func map0() {
+	m := make(map[*int]*int) // ERROR "make\(map\[\*int\]\*int\) does not escape"
+	// BAD: i should not escape
+	i := 0 // ERROR "moved to heap: i"
+	// BAD: j should not escape
+	j := 0     // ERROR "moved to heap: j"
+	m[&i] = &j // ERROR "&i escapes to heap" "&j escapes to heap"
+	_ = m
+}
+
+func map1() *int {
+	m := make(map[*int]*int) // ERROR "make\(map\[\*int\]\*int\) does not escape"
+	// BAD: i should not escape
+	i := 0       // ERROR "moved to heap: i"
+	j := 0       // ERROR "moved to heap: j"
+	m[&i] = &j   // ERROR "&i escapes to heap" "&j escapes to heap"
+	return m[&i] // ERROR "&i does not escape"
+}
+
+func map2() map[*int]*int {
+	m := make(map[*int]*int) // ERROR "make\(map\[\*int\]\*int\) escapes to heap"
+	i := 0                   // ERROR "moved to heap: i"
+	j := 0                   // ERROR "moved to heap: j"
+	m[&i] = &j               // ERROR "&i escapes to heap" "&j escapes to heap"
+	return m
+}
+
+func map3() []*int {
+	m := make(map[*int]*int) // ERROR "make\(map\[\*int\]\*int\) does not escape"
+	i := 0                   // ERROR "moved to heap: i"
+	// BAD: j should not escape
+	j := 0     // ERROR "moved to heap: j"
+	m[&i] = &j // ERROR "&i escapes to heap" "&j escapes to heap"
+	var r []*int
+	for k := range m {
+		r = append(r, k)
+	}
+	return r
+}
+
+func map4() []*int {
+	m := make(map[*int]*int) // ERROR "make\(map\[\*int\]\*int\) does not escape"
+	// BAD: i should not escape
+	i := 0     // ERROR "moved to heap: i"
+	j := 0     // ERROR "moved to heap: j"
+	m[&i] = &j // ERROR "&i escapes to heap" "&j escapes to heap"
+	var r []*int
+	for k, v := range m {
+		// We want to test exactly "for k, v := range m" rather than "for _, v := range m".
+		// The following if is merely to use (but not leak) k.
+		if k != nil {
+			r = append(r, v)
+		}
+	}
+	return r
+}
+
+func map5(m map[*int]*int) { // ERROR "m does not escape"
+	i := 0     // ERROR "moved to heap: i"
+	j := 0     // ERROR "moved to heap: j"
+	m[&i] = &j // ERROR "&i escapes to heap" "&j escapes to heap"
+}
+
+func map6(m map[*int]*int) { // ERROR "m does not escape"
+	if m != nil {
+		m = make(map[*int]*int) // ERROR "make\(map\[\*int\]\*int\) does not escape"
+	}
+	i := 0     // ERROR "moved to heap: i"
+	j := 0     // ERROR "moved to heap: j"
+	m[&i] = &j // ERROR "&i escapes to heap" "&j escapes to heap"
+}
+
+func map7() {
+	// BAD: i should not escape
+	i := 0 // ERROR "moved to heap: i"
+	// BAD: j should not escape
+	j := 0                     // ERROR "moved to heap: j"
+	m := map[*int]*int{&i: &j} // ERROR "&i escapes to heap" "&j escapes to heap" "literal does not escape"
+	_ = m
+}
+
+func map8() {
+	i := 0                     // ERROR "moved to heap: i"
+	j := 0                     // ERROR "moved to heap: j"
+	m := map[*int]*int{&i: &j} // ERROR "&i escapes to heap" "&j escapes to heap" "literal escapes to heap"
+	sink = m // ERROR "m escapes to heap"
+}
+
+func map9() *int {
+	// BAD: i should not escape
+	i := 0                     // ERROR "moved to heap: i"
+	j := 0                     // ERROR "moved to heap: j"
+	m := map[*int]*int{&i: &j} // ERROR "&i escapes to heap" "&j escapes to heap" "literal does not escape"
+	return m[nil]
+}
diff --git a/test/escape_param.go b/test/escape_param.go
new file mode 100644
index 0000000..91ad437
--- /dev/null
+++ b/test/escape_param.go
@@ -0,0 +1,326 @@
+// errorcheck -0 -m -l
+
+// Copyright 2015 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.
+
+// Test escape analysis for function parameters.
+
+// In this test almost everything is BAD except the simplest cases
+// where input directly flows to output.
+
+package escape
+
+var sink interface{}
+
+// in -> out
+func param0(p *int) *int { // ERROR "leaking param: p to result ~r1$"
+	return p
+}
+
+func caller0a() {
+	i := 0
+	_ = param0(&i) // ERROR "caller0a &i does not escape$"
+}
+
+func caller0b() {
+	i := 0            // ERROR "moved to heap: i$"
+	sink = param0(&i) // ERROR "&i escapes to heap$" "param0\(&i\) escapes to heap"
+}
+
+// in, in -> out, out
+func param1(p1, p2 *int) (*int, *int) { // ERROR "leaking param: p1 to result ~r2$" "leaking param: p2 to result ~r3$"
+	return p1, p2
+}
+
+func caller1() {
+	i := 0 // ERROR "moved to heap: i$"
+	j := 0
+	sink, _ = param1(&i, &j) // ERROR "&i escapes to heap$" "caller1 &j does not escape$"
+}
+
+// in -> other in
+func param2(p1 *int, p2 **int) { // ERROR "leaking param: p1$" "param2 p2 does not escape$"
+	*p2 = p1
+}
+
+func caller2a() {
+	i := 0 // ERROR "moved to heap: i$"
+	var p *int
+	param2(&i, &p) // ERROR "&i escapes to heap$" "caller2a &p does not escape$"
+	_ = p
+}
+
+func caller2b() {
+	i := 0 // ERROR "moved to heap: i$"
+	var p *int
+	param2(&i, &p) // ERROR "&i escapes to heap$" "caller2b &p does not escape$"
+	sink = p       // ERROR "p escapes to heap$"
+}
+
+// in -> in
+type Pair struct {
+	p1 *int
+	p2 *int
+}
+
+func param3(p *Pair) { // ERROR "leaking param: p$"
+	p.p1 = p.p2
+}
+
+func caller3a() {
+	i := 0            // ERROR "moved to heap: i$"
+	j := 0            // ERROR "moved to heap: j$"
+	p := Pair{&i, &j} // ERROR "&i escapes to heap$" "&j escapes to heap$" "moved to heap: p$"
+	param3(&p)        // ERROR "&p escapes to heap$"
+	_ = p
+}
+
+func caller3b() {
+	i := 0            // ERROR "moved to heap: i$"
+	j := 0            // ERROR "moved to heap: j$"
+	p := Pair{&i, &j} // ERROR "&i escapes to heap$" "&j escapes to heap$" "moved to heap: p$"
+	param3(&p)        // ERROR "&p escapes to heap$"
+	sink = p          // ERROR "p escapes to heap$"
+}
+
+// in -> rcvr
+func (p *Pair) param4(i *int) { // ERROR "\(\*Pair\).param4 p does not escape$" "leaking param: i$"
+	p.p1 = i
+}
+
+func caller4a() {
+	i := 0 // ERROR "moved to heap: i$"
+	p := Pair{}
+	p.param4(&i) // ERROR "&i escapes to heap$" "caller4a p does not escape$"
+	_ = p
+}
+
+func caller4b() {
+	i := 0 // ERROR "moved to heap: i$"
+	p := Pair{}
+	p.param4(&i) // ERROR "&i escapes to heap$" "caller4b p does not escape$"
+	sink = p     // ERROR "p escapes to heap$"
+}
+
+// in -> heap
+func param5(i *int) { // ERROR "leaking param: i$"
+	sink = i // ERROR "i escapes to heap$"
+}
+
+func caller5() {
+	i := 0     // ERROR "moved to heap: i$"
+	param5(&i) // ERROR "&i escapes to heap$"
+}
+
+// *in -> heap
+func param6(i ***int) { // ERROR "leaking param: i$"
+	sink = *i // ERROR "\*i escapes to heap$"
+}
+
+func caller6a() {
+	i := 0      // ERROR "moved to heap: i$"
+	p := &i     // ERROR "&i escapes to heap$" "moved to heap: p$"
+	p2 := &p    // ERROR "&p escapes to heap$" "moved to heap: p2$"
+	param6(&p2) // ERROR "&p2 escapes to heap$"
+}
+
+// **in -> heap
+func param7(i ***int) { // ERROR "leaking param: i$"
+	sink = **i // ERROR "\* \(\*i\) escapes to heap"
+}
+
+func caller7() {
+	i := 0      // ERROR "moved to heap: i$"
+	p := &i     // ERROR "&i escapes to heap$" "moved to heap: p$"
+	p2 := &p    // ERROR "&p escapes to heap$" "moved to heap: p2$"
+	param7(&p2) // ERROR "&p2 escapes to heap$"
+}
+
+// **in -> heap
+func param8(i **int) { // ERROR "param8 i does not escape$"
+	sink = **i // ERROR "\* \(\*i\) escapes to heap"
+}
+
+func caller8() {
+	i := 0
+	p := &i    // ERROR "caller8 &i does not escape$"
+	param8(&p) // ERROR "caller8 &p does not escape$"
+}
+
+// *in -> out
+func param9(p ***int) **int { // ERROR "param9 leaking param p content to result ~r1$"
+	return *p
+}
+
+func caller9a() {
+	i := 0          // ERROR "moved to heap: i$"
+	p := &i         // ERROR "&i escapes to heap$" "moved to heap: p$"
+	p2 := &p        // ERROR "&p escapes to heap$"
+	_ = param9(&p2) // ERROR "caller9a &p2 does not escape$"
+}
+
+func caller9b() {
+	i := 0             // ERROR "moved to heap: i$"
+	p := &i            // ERROR "&i escapes to heap$" "moved to heap: p$"
+	p2 := &p           // ERROR "&p escapes to heap$"
+	sink = param9(&p2) // ERROR "caller9b &p2 does not escape$"  "param9\(&p2\) escapes to heap"
+}
+
+// **in -> out
+func param10(p ***int) *int { // ERROR "param10 leaking param p content to result ~r1$"
+	return **p
+}
+
+func caller10a() {
+	i := 0           // ERROR "moved to heap: i$"
+	p := &i          // ERROR "&i escapes to heap$" "moved to heap: p$"
+	p2 := &p         // ERROR "&p escapes to heap$"
+	_ = param10(&p2) // ERROR "caller10a &p2 does not escape$"
+}
+
+func caller10b() {
+	i := 0              // ERROR "moved to heap: i$"
+	p := &i             // ERROR "&i escapes to heap$" "moved to heap: p$"
+	p2 := &p            // ERROR "&p escapes to heap$"
+	sink = param10(&p2) // ERROR "caller10b &p2 does not escape$" "param10\(&p2\) escapes to heap"
+}
+
+// &in -> out
+func param11(i **int) ***int { // ERROR "moved to heap: i$"
+	return &i // ERROR "&i escapes to heap$"
+}
+
+func caller11a() {
+	i := 0          // ERROR "moved to heap: i$"
+	p := &i         // ERROR "&i escapes to heap$" "moved to heap: p$"
+	_ = param11(&p) // ERROR "&p escapes to heap$"
+}
+
+func caller11b() {
+	i := 0             // ERROR "moved to heap: i$"
+	p := &i            // ERROR "&i escapes to heap$" "moved to heap: p$"
+	sink = param11(&p) // ERROR "&p escapes to heap$" "param11\(&p\) escapes to heap"
+}
+
+func caller11c() {
+	i := 0              // ERROR "moved to heap: i$"
+	p := &i             // ERROR "&i escapes to heap$" "moved to heap: p$"
+	sink = *param11(&p) // ERROR "&p escapes to heap$" "\*param11\(&p\) escapes to heap"
+}
+
+// &in -> rcvr
+type Indir struct {
+	p ***int
+}
+
+func (r *Indir) param12(i **int) { // ERROR "\(\*Indir\).param12 r does not escape$" "moved to heap: i$"
+	r.p = &i // ERROR "&i escapes to heap$"
+}
+
+func caller12a() {
+	i := 0  // ERROR "moved to heap: i$"
+	p := &i // ERROR "&i escapes to heap$" "moved to heap: p$"
+	var r Indir
+	r.param12(&p) // ERROR "&p escapes to heap$" "caller12a r does not escape$"
+	_ = r
+}
+
+func caller12b() {
+	i := 0        // ERROR "moved to heap: i$"
+	p := &i       // ERROR "&i escapes to heap$" "moved to heap: p$"
+	r := &Indir{} // ERROR "caller12b &Indir literal does not escape$"
+	r.param12(&p) // ERROR "&p escapes to heap$"
+	_ = r
+}
+
+func caller12c() {
+	i := 0  // ERROR "moved to heap: i$"
+	p := &i // ERROR "&i escapes to heap$" "moved to heap: p$"
+	r := Indir{}
+	r.param12(&p) // ERROR "&p escapes to heap$" "caller12c r does not escape$"
+	sink = r      // ERROR "r escapes to heap$"
+}
+
+func caller12d() {
+	i := 0  // ERROR "moved to heap: i$"
+	p := &i // ERROR "&i escapes to heap$" "moved to heap: p$"
+	r := Indir{}
+	r.param12(&p) // ERROR "&p escapes to heap$" "caller12d r does not escape$"
+	sink = **r.p  // ERROR "\* \(\*r\.p\) escapes to heap"
+}
+
+// in -> value rcvr
+type Val struct {
+	p **int
+}
+
+func (v Val) param13(i *int) { // ERROR "Val.param13 v does not escape$" "leaking param: i$"
+	*v.p = i
+}
+
+func caller13a() {
+	i := 0 // ERROR "moved to heap: i$"
+	var p *int
+	var v Val
+	v.p = &p      // ERROR "caller13a &p does not escape$"
+	v.param13(&i) // ERROR "&i escapes to heap$"
+	_ = v
+}
+
+func caller13b() {
+	i := 0 // ERROR "moved to heap: i$"
+	var p *int
+	v := Val{&p}  // ERROR "caller13b &p does not escape$"
+	v.param13(&i) // ERROR "&i escapes to heap$"
+	_ = v
+}
+
+func caller13c() {
+	i := 0 // ERROR "moved to heap: i$"
+	var p *int
+	v := &Val{&p} // ERROR "caller13c &Val literal does not escape$" "caller13c &p does not escape$"
+	v.param13(&i) // ERROR "&i escapes to heap$"
+	_ = v
+}
+
+func caller13d() {
+	i := 0     // ERROR "moved to heap: i$"
+	var p *int // ERROR "moved to heap: p$"
+	var v Val
+	v.p = &p      // ERROR "&p escapes to heap$"
+	v.param13(&i) // ERROR "&i escapes to heap$"
+	sink = v      // ERROR "v escapes to heap$"
+}
+
+func caller13e() {
+	i := 0        // ERROR "moved to heap: i$"
+	var p *int    // ERROR "moved to heap: p$"
+	v := Val{&p}  // ERROR "&p escapes to heap$"
+	v.param13(&i) // ERROR "&i escapes to heap$"
+	sink = v      // ERROR "v escapes to heap$"
+}
+
+func caller13f() {
+	i := 0        // ERROR "moved to heap: i$"
+	var p *int    // ERROR "moved to heap: p$"
+	v := &Val{&p} // ERROR "&Val literal escapes to heap$" "&p escapes to heap$"
+	v.param13(&i) // ERROR "&i escapes to heap$"
+	sink = v      // ERROR "v escapes to heap$"
+}
+
+func caller13g() {
+	i := 0 // ERROR "moved to heap: i$"
+	var p *int
+	v := Val{&p}  // ERROR "caller13g &p does not escape$"
+	v.param13(&i) // ERROR "&i escapes to heap$"
+	sink = *v.p   // ERROR "\*v\.p escapes to heap"
+}
+
+func caller13h() {
+	i := 0 // ERROR "moved to heap: i$"
+	var p *int
+	v := &Val{&p} // ERROR "caller13h &Val literal does not escape$" "caller13h &p does not escape$"
+	v.param13(&i) // ERROR "&i escapes to heap$"
+	sink = **v.p  // ERROR "\* \(\*v\.p\) escapes to heap"
+}
diff --git a/test/escape_slice.go b/test/escape_slice.go
new file mode 100644
index 0000000..9315e27
--- /dev/null
+++ b/test/escape_slice.go
@@ -0,0 +1,90 @@
+// errorcheck -0 -m -l
+
+// Copyright 2015 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.
+
+// Test escape analysis for slices.
+
+package escape
+
+var sink interface{}
+
+func slice0() {
+	var s []*int
+	// BAD: i should not escape
+	i := 0            // ERROR "moved to heap: i"
+	s = append(s, &i) // ERROR "&i escapes to heap"
+	_ = s
+}
+
+func slice1() *int {
+	var s []*int
+	i := 0            // ERROR "moved to heap: i"
+	s = append(s, &i) // ERROR "&i escapes to heap"
+	return s[0]
+}
+
+func slice2() []*int {
+	var s []*int
+	i := 0            // ERROR "moved to heap: i"
+	s = append(s, &i) // ERROR "&i escapes to heap"
+	return s
+}
+
+func slice3() *int {
+	var s []*int
+	i := 0            // ERROR "moved to heap: i"
+	s = append(s, &i) // ERROR "&i escapes to heap"
+	for _, p := range s {
+		return p
+	}
+	return nil
+}
+
+func slice4(s []*int) { // ERROR "s does not escape"
+	i := 0    // ERROR "moved to heap: i"
+	s[0] = &i // ERROR "&i escapes to heap"
+}
+
+func slice5(s []*int) { // ERROR "s does not escape"
+	if s != nil {
+		s = make([]*int, 10) // ERROR "make\(\[\]\*int, 10\) does not escape"
+	}
+	i := 0    // ERROR "moved to heap: i"
+	s[0] = &i // ERROR "&i escapes to heap"
+}
+
+func slice6() {
+	s := make([]*int, 10) // ERROR "make\(\[\]\*int, 10\) does not escape"
+	// BAD: i should not escape
+	i := 0    // ERROR "moved to heap: i"
+	s[0] = &i // ERROR "&i escapes to heap"
+	_ = s
+}
+
+func slice7() *int {
+	s := make([]*int, 10) // ERROR "make\(\[\]\*int, 10\) does not escape"
+	i := 0                // ERROR "moved to heap: i"
+	s[0] = &i             // ERROR "&i escapes to heap"
+	return s[0]
+}
+
+func slice8() {
+	// BAD: i should not escape here
+	i := 0          // ERROR "moved to heap: i"
+	s := []*int{&i} // ERROR "&i escapes to heap" "literal does not escape"
+	_ = s
+}
+
+func slice9() *int {
+	i := 0          // ERROR "moved to heap: i"
+	s := []*int{&i} // ERROR "&i escapes to heap" "literal does not escape"
+	return s[0]
+}
+
+func slice10() []*int {
+	i := 0          // ERROR "moved to heap: i"
+	s := []*int{&i} // ERROR "&i escapes to heap" "literal escapes to heap"
+	return s
+}
diff --git a/test/fixedbugs/bug495.go b/test/fixedbugs/bug495.go
new file mode 100644
index 0000000..dfc0c9f
--- /dev/null
+++ b/test/fixedbugs/bug495.go
@@ -0,0 +1,20 @@
+// compile
+
+// Copyright 2015 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.
+
+// Gccgo used to give an incorrect error
+// bug495.go:16:2: error: missing statement after label
+
+package p
+
+func F(i int) {
+	switch i {
+	case 0:
+		goto lab
+	lab:
+		fallthrough
+	case 1:
+	}
+}
diff --git a/test/fixedbugs/issue10047.go b/test/fixedbugs/issue10047.go
new file mode 100644
index 0000000..1cb9c24
--- /dev/null
+++ b/test/fixedbugs/issue10047.go
@@ -0,0 +1,19 @@
+// compile
+
+// Copyright 2015 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.
+
+// Issue 10047: gccgo failed to compile a type switch where the switch variable
+// and the base type of a case share the same identifier.
+
+package main
+
+func main() {
+	type t int
+	var p interface{}
+	switch t := p.(type) {
+	case t:
+		_ = t
+	}
+}
diff --git a/test/fixedbugs/issue10066.dir/a.go b/test/fixedbugs/issue10066.dir/a.go
new file mode 100644
index 0000000..8bb3b30
--- /dev/null
+++ b/test/fixedbugs/issue10066.dir/a.go
@@ -0,0 +1,11 @@
+package a
+
+import "log"
+
+func Do() {
+	Do2()
+}
+
+func Do2() {
+	println(log.Ldate | log.Ltime | log.Lshortfile)
+}
diff --git a/test/fixedbugs/issue10066.dir/b.go b/test/fixedbugs/issue10066.dir/b.go
new file mode 100644
index 0000000..46d2f55
--- /dev/null
+++ b/test/fixedbugs/issue10066.dir/b.go
@@ -0,0 +1,7 @@
+package b
+
+import "./a"
+
+func test() {
+	a.Do()
+}
diff --git a/test/fixedbugs/issue10066.go b/test/fixedbugs/issue10066.go
new file mode 100644
index 0000000..3ea552f
--- /dev/null
+++ b/test/fixedbugs/issue10066.go
@@ -0,0 +1,10 @@
+// compiledir
+
+// Copyright 2015 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.
+
+// Issue 10066: constants are printed in the original form
+// in export data. This is the opposite of issue 9076.
+
+package ignored
diff --git a/test/fixedbugs/issue10135.go b/test/fixedbugs/issue10135.go
new file mode 100644
index 0000000..9985e5a
--- /dev/null
+++ b/test/fixedbugs/issue10135.go
@@ -0,0 +1,25 @@
+// run
+
+// Copyright 2015 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.
+
+// Issue 10135: append a slice with zero-sized element used
+// to always return a slice with the same data pointer as the
+// old slice, even if it's nil, so this program used to panic
+// with nil pointer dereference because after append, s is a
+// slice with nil data pointer but non-zero len and cap.
+
+package main
+
+type empty struct{}
+
+func main() {
+	var s []empty
+
+	s = append(s, empty{})
+
+	for _, v := range s {
+		_ = v
+	}
+}
diff --git a/test/fixedbugs/issue10284.go b/test/fixedbugs/issue10284.go
new file mode 100644
index 0000000..e89d6f4
--- /dev/null
+++ b/test/fixedbugs/issue10284.go
@@ -0,0 +1,16 @@
+// compile
+
+// Copyright 2015 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.
+
+// Issue 10284: gccgo failed to allow converting a user-defined
+// type whose underlying type is uintptr to unsafe.Pointer.
+
+package p
+
+import "unsafe"
+
+type T uintptr
+
+var _ unsafe.Pointer = unsafe.Pointer(T(0))
diff --git a/test/interface/assertinline.go b/test/interface/assertinline.go
new file mode 100644
index 0000000..faa848a
--- /dev/null
+++ b/test/interface/assertinline.go
@@ -0,0 +1,53 @@
+// errorcheck -0 -d=typeassert
+
+// Copyright 2015 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 p
+
+func assertptr(x interface{}) *int {
+	return x.(*int) // ERROR "type assertion inlined"
+}
+
+func assertptr2(x interface{}) (*int, bool) {
+	z, ok := x.(*int) // ERROR "type assertion inlined"
+	return z, ok
+}
+
+func assertfunc(x interface{}) func() {
+	return x.(func()) // ERROR "type assertion inlined"
+}
+
+func assertfunc2(x interface{}) (func(), bool) {
+	z, ok := x.(func()) // ERROR "type assertion inlined"
+	return z, ok
+}
+
+// TODO(rsc): struct{*int} is stored directly in the interface
+// and should be possible to fetch back out of the interface,
+// but more of the general data movement code needs to
+// realize that before we can inline the assertion.
+
+func assertstruct(x interface{}) struct{ *int } {
+	return x.(struct{ *int }) // ERROR "type assertion not inlined"
+}
+
+func assertstruct2(x interface{}) (struct{ *int }, bool) {
+	z, ok := x.(struct{ *int }) // ERROR "type assertion not inlined"
+	return z, ok
+}
+
+func assertbig(x interface{}) complex128 {
+	return x.(complex128) // ERROR "type assertion not inlined"
+}
+
+func assertbig2(x interface{}) (complex128, bool) {
+	z, ok := x.(complex128) // ERROR "type assertion not inlined"
+	return z, ok
+}
+
+func assertbig2ok(x interface{}) (complex128, bool) {
+	_, ok := x.(complex128) // ERROR "type assertion [(]ok only[)] inlined"
+	return 0, ok
+}
diff --git a/test/nilptr3.go b/test/nilptr3.go
index cf26993..a62b262 100644
--- a/test/nilptr3.go
+++ b/test/nilptr3.go
@@ -1,6 +1,7 @@
 // errorcheck -0 -d=nil
-// Fails on ppc64x because of incomplete optimization.  See issue 9058.
-// +build !ppc64,!ppc64le
+// Fails on ppc64x and arm64 because of incomplete optimization.
+// See issues 9058 and 10105.
+// +build !ppc64,!ppc64le,!arm64
 
 // Copyright 2013 The Go Authors.  All rights reserved.
 // Use of this source code is governed by a BSD-style
diff --git a/test/nosplit.go b/test/nosplit.go
index 0bd13c1..bd4e60b 100644
--- a/test/nosplit.go
+++ b/test/nosplit.go
@@ -261,6 +261,9 @@
 			fmt.Fprintf(&buf, "#define CALL BL\n#define REGISTER (CTR)\n#define RET RETURN\n")
 		case "arm":
 			fmt.Fprintf(&buf, "#define CALL BL\n#define REGISTER (R0)\n")
+		case "arm64":
+			ptrSize = 8
+			fmt.Fprintf(&buf, "#define CALL BL\n#define REGISTER (R0)\n")
 		case "amd64":
 			ptrSize = 8
 			fmt.Fprintf(&buf, "#define REGISTER AX\n")
diff --git a/test/recover4.go b/test/recover4.go
new file mode 100644
index 0000000..cda0813
--- /dev/null
+++ b/test/recover4.go
@@ -0,0 +1,73 @@
+// +build linux darwin
+// run
+
+// Copyright 2015 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.
+
+// Test that if a slice access causes a fault, a deferred func
+// sees the most recent value of the variables it accesses.
+// This is true today; the role of the test is to ensure it stays true.
+//
+// In the test, memcopy is the function that will fault, during dst[i] = src[i].
+// The deferred func recovers from the error and returns, making memcopy
+// return the current value of n. If n is not being flushed to memory
+// after each modification, the result will be a stale value of n.
+//
+// The test is set up by mmapping a 64 kB block of memory and then
+// unmapping a 16 kB hole in the middle of it. Running memcopy
+// on the resulting slice will fault when it reaches the hole.
+
+package main
+
+import (
+	"log"
+	"runtime/debug"
+	"syscall"
+	"unsafe"
+)
+
+func memcopy(dst, src []byte) (n int, err error) {
+	defer func() {
+		err = recover().(error)
+	}()
+
+	for i := 0; i < len(dst) && i < len(src); i++ {
+		dst[i] = src[i]
+		n++
+	}
+	return
+}
+
+func main() {
+	// Turn the eventual fault into a panic, not a program crash,
+	// so that memcopy can recover.
+	debug.SetPanicOnFault(true)
+
+	size := syscall.Getpagesize()
+
+	// Map 16 pages of data with a 4-page hole in the middle.
+	data, err := syscall.Mmap(-1, 0, 16*size, syscall.PROT_READ|syscall.PROT_WRITE, syscall.MAP_ANON|syscall.MAP_PRIVATE)
+	if err != nil {
+		log.Fatalf("mmap: %v", err)
+	}
+
+	// Note: Cannot call syscall.Munmap, because Munmap checks
+	// that you are unmapping a whole region returned by Mmap.
+	// We are trying to unmap just a hole in the middle.
+	if _, _, err := syscall.Syscall(syscall.SYS_MUNMAP, uintptr(unsafe.Pointer(&data[8*size])), uintptr(4*size), 0); err != 0 {
+		log.Fatalf("munmap: %v", err)
+	}
+
+	other := make([]byte, 16*size)
+
+	// Check that memcopy returns the actual amount copied
+	// before the fault (8*size - 5, the offset we skip in the argument).
+	n, err := memcopy(data[5:], other)
+	if err == nil {
+		log.Fatal("no error from memcopy across memory hole")
+	}
+	if n != 8*size-5 {
+		log.Fatal("memcopy returned %d, want %d", n, 8*size-5)
+	}
+}